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

Getting started#

First, let’s create Trading Strategy dataset client.

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

from tradingstrategy.exchange import ExchangeUniverse
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
columnar_pair_table: Table = client.fetch_pair_universe()

print(f"Total pairs {len(columnar_pair_table)}, total exchanges {len(exchange_universe.exchanges)}")
Total pairs 105657, total exchanges 2977

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…

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 744 pairs

Calculating combined buy and sell volume#

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

# 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.

# 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()

  '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)

  'Volume 30d USD': lambda val: f'${val:,.2f}',
/var/folders/tx/50wn88yd40v2_6_7fvfr98z00000gn/T/ipykernel_43436/729194997.py:17: FutureWarning: this method is deprecated in favour of `Styler.hide(axis='index')`
Base token Quote token Volume 30d USD
WETH USDC $611,525,376.00
LUNA WETH $514,604,416.00
UST WETH $330,820,640.00
WETH USDT $212,708,032.00
SYN WETH $156,471,424.00
WETH UST $148,764,160.00
WETH DAI $138,515,360.00
SUSHI WETH $103,439,400.00
LDO WETH $91,034,992.00
WETH WBTC $52,359,200.00

Resolving Uniswap/PancakeSwap trading pairs by their ticker name#

If you want to resolve a trading pair based on its human readable ticker to token and pair contract addresses you can do it as below.

from tradingstrategy.pair import PandasPairUniverse

# Download symbolic exchange and pair data needed for the resolution
exchange_universe = client.fetch_exchange_universe()
pair_data = client.fetch_pair_universe().to_pandas()
pair_universe = PandasPairUniverse(pair_data)

# Get PancakeSwap exchange,
# for the full exchange list see https://tradingstrategy.ai/trading-view/exchanges
pancake = exchange_universe.get_by_chain_and_slug(ChainId.bsc, "pancakeswap-v2")

# Because there can be multiple trading pairs with same tickers,
# we pick the genuine among the scams based on its trading volume
wbnb_busd_pair = pair_universe.get_one_pair_from_pandas_universe(

print("WBNB address is", wbnb_busd_pair.base_token_address)
print("BUSD address is", wbnb_busd_pair.quote_token_address)
print("WBNB-BUSD pair contract address is", wbnb_busd_pair.address)
WBNB address is 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c
BUSD address is 0xe9e7cea3dedca5984780bafc599bd69add087d56
WBNB-BUSD pair contract address is 0x58f876857a02d6762e0101bb5c46a8c1ed44dc16
[ ]: