Exploring trading pairs#

An example how to filter and plot candles for pair data

We will

  • Look up trading pairs by their ticker name and token symbols

  • Download pair and exchange map (“the trading universe”)

  • Filter out SushiSwap pairs

  • Download 4 hour candle data for all pairs

  • Display top 10 pairs by their 30d volume, nominated in the USD

For exploring the trading pairs through web you can use

After you have found your pair in the web interface, you can look it up in the code as described below.

Getting started#

First, let’s create Trading Strategy dataset client.

[8]:
from tradingstrategy.client import Client

client = Client.create_jupyter_client()
Started Trading Strategy in Jupyter notebook environment, configuration is stored in /Users/moo/.tradingstrategy

Get the map of exchanges and pairs we are working on

[9]:
from tradingstrategy.exchange import ExchangeUniverse
from tradingstrategy.pair import PandasPairUniverse
from pyarrow import Table

# Exchange map data is so small it does not need any decompression
exchange_universe: ExchangeUniverse = client.fetch_exchange_universe()

# Decompress the pair dataset to Python map
# This is raw PyArrow data
columnar_pair_table: Table = client.fetch_pair_universe()
print(f"Total pairs {len(columnar_pair_table)}, total exchanges {len(exchange_universe.exchanges)}")

# Wrap the data in a helper class with indexes for easier access
pair_universe = PandasPairUniverse(columnar_pair_table.to_pandas(), exchange_universe=exchange_universe)

Total pairs 191072, total exchanges 4759

Looking up a trading pair with a human description#

We have a helper class PandasPairUniverse that takes a raw pair data as an input and creates look-up indexes for it.

With this class, you can look up trading pairs by using HumanReadableTradingPairDescription.

Here is a an example for PancakeSwap on BNB Smart Chain which has only a single fee tier.

About scam pairs#

For any popular token, there will be multiple scam tokens with the same token symbol. In the case of the multiple matches for the same token symbol, by default the look up will pick the trading pair with most monthly trading volume. Usually this is the “real” trading pair, but always be careful. For extra confidence you can look up trading pairs by smart contract addresses that are immutable and unique.

[10]:
from tradingstrategy.chain import ChainId
from tradingstrategy.pair import HumanReadableTradingPairDescription

# Get BNB-BUSD pair on PancakeSwap v2
#
# There are no fee tiers, so we
#
desc: HumanReadableTradingPairDescription = (ChainId.bsc, "pancakeswap-v2", "WBNB", "BUSD")
bnb_busd = pair_universe.get_pair_by_human_description(desc)
print(f"We have pair {bnb_busd} with 30d volume of USD {bnb_busd.volume_30d:,}")
We have pair <Pair #1364760 WBNB - BUSD (0x58f876857a02d6762e0101bb5c46a8c1ed44dc16) at exchange #1187 on binance> with 30d volume of USD 45,035,140.0

Looking up a trading pair with a human description and a fee tie#

Here is another example for Uniswap v3 on Arbitrum. On Uniswap v3, we need to differetiate between different fee tiers of the pairs. We use 5 BPS (0.05%) fee tier.

You can use e.g. Trading Strategy trading pair search to find out about available fee tiers.

[11]:
desc: HumanReadableTradingPairDescription = (ChainId.arbitrum, "uniswap-v3", "WETH", "USDC", 0.0005)
eth_usdc = pair_universe.get_pair_by_human_description(desc)
print(f"We have pair {eth_usdc} with 30d volume of USD {eth_usdc.volume_30d:,}")
We have pair <Pair #2991521 WETH - USDC (0xc31e54c7a869b9fcbecc14363cf510d1c41fa443) at exchange #4338 on arbitrum> with 30d volume of USD 1,057,692,608.0

Filtering pairs trading on Sushiswap#

We are only interested in SushiSwap, the mosh pit of a degens, so filter pairs that are on this exchange only. We specifically pick Sushiswap on Ethereum mainnet, as it is the oldest and most active for all Sushiswap instances across EVM blockchains like Polygon, BSC, Fantom, etc.

Also we do not yet have multichain data on the dataset server, when I am writing this tutorial so…

[12]:
import pandas as pd
from tradingstrategy.chain import ChainId

# Convert PyArrow table to Pandas format to continue working on it
all_pairs_dataframe = columnar_pair_table.to_pandas()

# Filter down to pairs that only trade on Sushiswap
sushi_swap = exchange_universe.get_by_chain_and_slug(ChainId.ethereum, "sushi")
sushi_pairs: pd.DataFrame = all_pairs_dataframe.loc[all_pairs_dataframe['exchange_id'] == sushi_swap.exchange_id]

print(f"Sushiswap on Ethereum has {len(sushi_pairs)} pairs")
Sushiswap on Ethereum has 895 pairs

Calculating combined buy and sell volume#

Now let’s get pairs sorted out by 30d buy and sell volume

[13]:
# Avoid doing set operations on a Pandas read-only view
# https://stackoverflow.com/questions/20625582/how-to-deal-with-settingwithcopywarning-in-pandas
sushi_pairs = sushi_pairs.copy()
total_volume_30d = sushi_pairs["buy_volume_30d"] + sushi_pairs["sell_volume_30d"]
sushi_pairs["total_30d_volume"] = total_volume_30d
# Sort by highest volume firs   t
sushi_pairs = sushi_pairs.sort_values("total_30d_volume", ascending=False)

print("total_30d_volume column sum added")
total_30d_volume column sum added

Output table for top-10 pairs#

Then let’s see the top 10 pairs we got and choose colums to display.

[14]:
# See Pandas official documentation for table visualisation
# https://pandas.pydata.org/pandas-docs/stable/user_guide/style.html

output = sushi_pairs[["base_token_symbol", "quote_token_symbol", "total_30d_volume"]].copy()

output.style.format({
  'total_30d_volume': lambda val: f'${val:,.2f}',
})

output = output.rename(columns={
    'base_token_symbol': 'Base token',
    'quote_token_symbol': 'Quote token',
    'total_30d_volume': 'Volume 30d USD'})

top_10 = output.head(10)

top_10.style.format({
  'Volume 30d USD': lambda val: f'${val:,.2f}',
}).hide_index()
/var/folders/12/pbc59svn70q_9dfz1kjl3zww0000gn/T/ipykernel_52060/729194997.py:19: FutureWarning: this method is deprecated in favour of `Styler.hide(axis="index")`
  }).hide_index()
[14]:
Base token Quote token Volume 30d USD
SDT WETH $37,052,792.00
WETH USDT $26,307,796.00
SYN WETH $24,369,570.00
ILV WETH $19,799,964.00
PNDC WETH $13,236,364.00
THOR WETH $13,077,034.00
WETH USDC $11,519,882.00
COMP WETH $9,277,188.00
WETH UST $7,120,714.50
SUSHI WETH $5,229,757.00
[14]: