Trading pairs

Trading pair information and pair datasets.

The core classes to understand the data are

To download the pairs dataset see

exception tradingstrategy.pair.NoPairFound

No trading pair found matching the given criteria.

exception tradingstrategy.pair.DuplicatePair

Found multiple trading pairs for the same naive lookup.

class tradingstrategy.pair.PairType

What kind of an decentralised exchange, AMM or other the pair is trading on.

Note that each type can have multiple implementations. For example QuickSwap, Sushi and Pancake are all Uniswap v2 types.

uniswap_v2 = 'uni_v2'

Uniswap v2 style exchange

uniswap_v3 = 'uni_v3'

Uniswap v3 style exchange

class tradingstrategy.pair.DEXPair

Trading pair information for a single pair.

Presents a single trading pair on decentralised exchanges.

DEX trading pairs can be uniquely identified by

  • Internal id.

  • (Chain id, address) tuple - the same address can exist on multiple chains.

  • (Chain slug, exchange slug, pair slug) tuple.

  • Token names and symbols are not unique - anyone can create any number of trading pair tickers and token symbols. Do not rely on token symbols for anything.

About data:

  • There is a different between token0 and token1 and base_token and quote_token conventions - the former are raw DEX (Uniswap) data while the latter are preprocessed by the server to make the data more understandable. Base token is the token you are trading and the quote token is the token you consider “money” for the trading. E.g. in WETH-USDC, USDC is the quote token. In SUSHI-WETH, WETH is the quote token.

  • Optional fields may be available if the candle server 1) detected the pair popular enough 2) managed to fetch the third party service information related to the token

When you download a trading pair dataset from the server, not all trading pairs are available. For more information about trading pair availability see trading pair tracking.

The class provides some JSON helpers to make it more usable with JSON based APIs.

This data class is serializable via dataclasses-json methods. Example:

info_as_string = pair.to_json()

You can also do __json__() convention data export:

info_as_dict = pair.__json__()

Note

Currently all flags are disabled and will be removed in the future. The historical dataset does not contain any filtering flags, because the data has to be filtered prior to download, to keep the download dump in a reasonasble size. The current data set of 800k trading pairs produce 100 MB dataset of which most of the pairs are useless. The server prefilters trading pairs and thus you cannot access historical data of pairs that have been prefiltered.

pair_id: tradingstrategy.types.PrimaryKey

Internal primary key for any trading pair

chain_id: tradingstrategy.chain.ChainId

The chain id on which chain this pair is trading. 1 for Ethereum.

exchange_id: tradingstrategy.types.PrimaryKey

The exchange where this token trades

address: tradingstrategy.types.NonChecksummedAddress

Smart contract address for the pair. In the case of Uniswap this is the pair (pool) address.

dex_type: tradingstrategy.pair.PairType

What kind of exchange this pair is on

token0_address: str

Token pair contract address on-chain. Lowercase, non-checksummed.

token1_address: str

Token pair contract address on-chain Lowercase, non-checksummed.

token0_symbol: Optional[str]

Token0 as in raw Uniswap data. ERC-20 contracst are not guaranteed to have this data.

token1_symbol: Optional[str]

Token1 as in raw Uniswap data ERC-20 contracst are not guaranteed to have this data.

base_token_symbol: Optional[str] = None

Naturalised base and quote token. Uniswap may present the pair in USDC-WETH or WETH-USDC order based on the token address order. However we humans always want the quote token to be USD, or ETH or BTC. For the reverse token orders, the candle serve swaps the token order so that the quote token is the more natural token of the pair (in the above case USD)

quote_token_symbol: Optional[str] = None

Naturalised base and quote token. Uniswap may present the pair in USDC-WETH or WETH-USDC order based on the token address order. However we humans always want the quote token to be USD, or ETH or BTC. For the reverse token orders, the candle serve swaps the token order so that the quote token is the more natural token of the pair (in the above case USD)

token0_decimals: Optional[int] = None

Number of decimals to convert between human amount and Ethereum fixed int raw amount. Note - this information might be missing from ERC-20 smart contracts. If the information is missing the token is not tradeable in practice.

token1_decimals: Optional[int] = None

Number of decimals to convert between human amount and Ethereum fixed int raw amount Note - this information might be missing from ERC-20 smart contracts. If the information is missing the token is not tradeable in practice.

exchange_slug: Optional[str] = None

Denormalised web page and API look up information

exchange_address: Optional[str] = None

Exchange factory address. Denormalised here, so we do not need an additional lookup.

pair_slug: Optional[str] = None

Denormalised web page and API look up information

first_swap_at_block_number: Optional[tradingstrategy.types.BlockNumber] = None

Block number of the first Uniswap Swap event

last_swap_at_block_number: Optional[tradingstrategy.types.BlockNumber] = None

Block number of the last Uniswap Swap event

first_swap_at: Optional[tradingstrategy.types.UNIXTimestamp] = None

Timestamp of the first Uniswap Swap event

last_swap_at: Optional[tradingstrategy.types.UNIXTimestamp] = None

Timestamp of the first Uniswap Swap event

flag_inactive: Optional[bool] = None

Pair has been flagged inactive, because it has not traded at least once during the last 30 days. TODO - inactive, remove.

flag_blacklisted_manually: Optional[bool] = None

Pair is blacklisted by operators. Current there is no blacklist process so this is always false. TODO - inactive, remove.

flag_unsupported_quote_token: Optional[bool] = None

Quote token is one of USD, ETH, BTC, MATIC or similar popular token variants. Because all candle data is outputted in the USD, if we have a quote token for which we do not have an USD conversation rate reference price source, we cannot create candles for the pair. TODO - inactive, remove.

flag_unknown_exchange: Optional[bool] = None

Pair is listed on an exchange we do not if it is good or not TODO - inactive, remove.

fee: Optional[tradingstrategy.types.BasisPoint] = None

Swap fee in basis points if known

buy_count_all_time: Optional[int] = None

Risk assessment summary data

sell_count_all_time: Optional[int] = None

Risk assessment summary data

buy_volume_all_time: Optional[float] = None

Risk assessment summary data

sell_volume_all_time: Optional[float] = None

Risk assessment summary data

buy_count_30d: Optional[int] = None

Risk assessment summary data

sell_count_30d: Optional[int] = None

Risk assessment summary data

buy_volume_30d: Optional[float] = None

Risk assessment summary data

sell_volume_30d: Optional[float] = None

Risk assessment summary data

buy_tax: Optional[float] = None

Buy token tax for this trading pair. See Token tax and deflationary tokens for details.

transfer_tax: Optional[float] = None

Transfer token tax for this trading pair. See Token tax and deflationary tokens for details.

sell_tax: Optional[float] = None

Sell tax for this trading pair. See Token tax and deflationary tokens for details.

property base_token_address: str

Get smart contract address for the base token.

Returns

Lowercase, non-checksummed.

property quote_token_address: str

Get smart contract address for the quote token

Returns

Token address in checksummed case

property base_token_decimals: Optional[int]

Get token decimal count for the base token.

property quote_token_decimals: Optional[int]

Get token decimal count for the quote token

get_ticker() str

Return trading ‘ticker’

get_friendly_name(exchange_universe: tradingstrategy.exchange.ExchangeUniverse) str

Get a very human readable name for this trading pair.

We need to translate the exchange id to someething human readable, and for this we need to have the access to the exchange universe.

get_trading_pair_page_url() Optional[str]

Get information page for this trading pair.

Returns

URL of the trading pair page or None if page/data not available.

classmethod to_pyarrow_schema() pyarrow.lib.Schema

Construct schema for reading writing Parquet filss for pair information.

classmethod convert_to_pyarrow_table(pairs: List[tradingstrategy.pair.DEXPair], check_schema=False) pyarrow.lib.Table

Convert a list of DEXPair instances to a Pyarrow table.

Used to prepare a data export on a server.

Parameters
  • pairs – The list wil be consumed in the process

  • check_schema – Run additional checks on the data. Slow. Use only in tests. May be give happier error messages instead of “OverflowError” what pyarrow spits out.

classmethod convert_to_dataframe(pairs: List[tradingstrategy.pair.DEXPair]) pandas.core.frame.DataFrame

Convert Python DEXPair objects back to the Pandas dataframe presentation.

As this is super-inefficient, do not use for large amount of data.

__init__(pair_id: tradingstrategy.types.PrimaryKey, chain_id: tradingstrategy.chain.ChainId, exchange_id: tradingstrategy.types.PrimaryKey, address: tradingstrategy.types.NonChecksummedAddress, dex_type: tradingstrategy.pair.PairType, token0_address: str, token1_address: str, token0_symbol: Optional[str], token1_symbol: Optional[str], base_token_symbol: Optional[str] = None, quote_token_symbol: Optional[str] = None, token0_decimals: Optional[int] = None, token1_decimals: Optional[int] = None, exchange_slug: Optional[str] = None, exchange_address: Optional[str] = None, pair_slug: Optional[str] = None, first_swap_at_block_number: Optional[tradingstrategy.types.BlockNumber] = None, last_swap_at_block_number: Optional[tradingstrategy.types.BlockNumber] = None, first_swap_at: Optional[tradingstrategy.types.UNIXTimestamp] = None, last_swap_at: Optional[tradingstrategy.types.UNIXTimestamp] = None, flag_inactive: Optional[bool] = None, flag_blacklisted_manually: Optional[bool] = None, flag_unsupported_quote_token: Optional[bool] = None, flag_unknown_exchange: Optional[bool] = None, fee: Optional[tradingstrategy.types.BasisPoint] = None, buy_count_all_time: Optional[int] = None, sell_count_all_time: Optional[int] = None, buy_volume_all_time: Optional[float] = None, sell_volume_all_time: Optional[float] = None, buy_count_30d: Optional[int] = None, sell_count_30d: Optional[int] = None, buy_volume_30d: Optional[float] = None, sell_volume_30d: Optional[float] = None, buy_tax: Optional[float] = None, transfer_tax: Optional[float] = None, sell_tax: Optional[float] = None) None
class tradingstrategy.pair.PandasPairUniverse

A pair universe implementation that is created from Pandas dataset.

This is a helper class, as pandas.DataFrame is somewhat more difficult to interact with. This class will read the raw data frame and convert it to DEXPair objects with a lookup index. Because the DEXPair conversion is expensive for 10,000s of Python objects, it is recommended that you filter the raw pandas.DataFrame by using filtering functions in tradingstrategy.pair first, before initializing PandasPairUniverse.

About the usage:

Example how to use:

# Get dataset from the server as Apache Pyarrow table
columnar_pair_table = client.fetch_pair_universe()

# Convert Pyarrow -> Pandas -> in-memory DEXPair index
pair_universe = PandasPairUniverse(columnar_pair_table.to_pandas())

# Lookup SUSHI-WETH trading pair from DEXPair index
# https://tradingstrategy.ai/trading-view/ethereum/sushi/sushi-eth
pair: DEXPair = pair_universe.get_pair_by_smart_contract("0x795065dcc9f64b5614c407a6efdc400da6221fb0")

If the pair index is too slow to build, or you want to keep it lean, you can disable the indexing with build_index. In this case, some of the methods won’t work:

# Get dataset from the server as Apache Pyarrow table
columnar_pair_table = client.fetch_pair_universe()

# Convert Pyarrow -> Pandas -> in-memory DEXPair index
pair_universe = PandasPairUniverse(columnar_pair_table.to_pandas(), build_index=False)
__init__(df: pandas.core.frame.DataFrame, build_index=True)
Parameters
  • df – The source DataFrame that contains all DEXPair entries

  • build_index – Build quick lookup index for pairs

build_index()

Create pair_id -> data mapping.

Allows fast lookup of individual pairs.

get_count() int

How many trading pairs there are.

get_pair_by_id(pair_id: tradingstrategy.types.PrimaryKey) Optional[tradingstrategy.pair.DEXPair]

Look up pair information and return its data.

Returns

Nicely presented DEXPair.

get_pair_by_smart_contract(address: str) Optional[tradingstrategy.pair.DEXPair]

Resolve a trading pair by its pool smart contract address.

Parameters

address – Ethereum smart contract address of the Uniswap pair contract

get_token(address: str) Optional[tradingstrategy.token.Token]

Get a token that is part of any trade pair.

Get a token details for a token that is base or quotetoken of any trading pair.

..note

TODO: Not a final implementation subject to chage.
Returns

Tuple (name, symbol, address, decimals) or None if not found.

get_all_tokens() Set[tradingstrategy.token.Token]

Get all base and quote tokens in trading pairs.

Warning

This method is useful for only test/limited pair count universes. It is very slow and mainly purported for debugging and diagnostics.

get_single() tradingstrategy.pair.DEXPair

For strategies that trade only a single trading pair, get the only pair in the universe.

Raises

AssertionError – If our pair universe does not have an exact single pair

get_by_symbols(base_token_symbol: str, quote_token_symbol: str) Optional[tradingstrategy.pair.DEXPair]

For strategies that trade only a few trading pairs, get the only pair in the universe.

Warning

Currently, this method is only safe for prefiltered universe. There are no safety checks if the returned trading pair is legit. In the case of multiple matching pairs, a random pair is returned.g

get_one_pair_from_pandas_universe(exchange_id: tradingstrategy.types.PrimaryKey, base_token: str, quote_token: str, pick_by_highest_vol=False) Optional[tradingstrategy.pair.DEXPair]

Get a trading pair by its ticker symbols.

Note that this method works only very simple universes, as any given pair is poised to have multiple tokens and multiple trading pairs on different exchanges.

Example:

# 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(
    pancake.exchange_id,
    "WBNB",
    "BUSD",
    pick_by_highest_vol=True,
    )

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

pick_by_highest_vol – If multiple trading pairs with the same symbols are found, pick one with the highest volume. This is because often malicious trading pairs are create to attract novice users.

Raises

DuplicatePair – If the universe contains more than single entry for the pair.

Returns

None if there is no match

static create_single_pair_universe(df: pandas.core.frame.DataFrame, exchange: tradingstrategy.exchange.Exchange, base_token_symbol: str, quote_token_symbol: str, pick_by_highest_vol=True) tradingstrategy.pair.PandasPairUniverse

Create a trading pair universe that contains only a single trading pair.

This is useful for trading strategies that to technical analysis trading on a single trading pair like BTC-USD.

Parameters
  • df – Unfiltered DataFrame for all pairs

  • exchange – Exchange instance on the pair is trading

  • base_token_symbol – Base token symbol of the trading pair

  • quote_token_symbol – Base token symbol of the trading pair

  • pick_by_highest_vol – In the case of multiple match per token symbol, or scam tokens, pick one with the highest trade volume

Raises
static create_limited_pair_universe(df: pandas.core.frame.DataFrame, exchange: tradingstrategy.exchange.Exchange, pairs: List[Tuple[str, str]], pick_by_highest_vol=True) tradingstrategy.pair.PandasPairUniverse

Create a trading pair universe that contains only few trading pairs.

This is useful for trading strategies that to technical analysis trading on a few trading pairs, or single pair three-way trades like Cake-WBNB-BUSD.

Parameters
  • df – Unfiltered DataFrame for all pairs

  • exchange – Exchange instance on the pair is trading

  • pairs – List of trading pairs as ticket tuples. E.g. [ (“WBNB, “BUSD”), (“Cake”, “WBNB”) ]

  • pick_by_highest_vol – In the case of multiple match per token symbol, or scam tokens, pick one with the highest trade volume

Raises
class tradingstrategy.pair.LegacyPairUniverse

The queries universe, as returned by the server.

Note

TODO: Legacy prototype implementation and will be deprecated.

Converts raw pair dataset to easier to use DEXPair in-memory index.

You likely want to use PandasPairUniverse, as its offers much more functionality than this implemetation.

__init__(pairs: Dict[int, tradingstrategy.pair.DEXPair])
pairs: Dict[int, tradingstrategy.pair.DEXPair]

Internal id -> DEXPair mapping

classmethod create_from_pyarrow_table(table: pyarrow.lib.Table) tradingstrategy.pair.LegacyPairUniverse

Convert columnar presentation to a Python in-memory objects.

Some data manipulation is easier with objects instead of columns.

Note

This seems to quite slow operation. It is recommend you avoid this if you do not need row-like data.

classmethod create_from_pyarrow_table_with_filters(table: pyarrow.lib.Table, chain_id_filter: Optional[tradingstrategy.chain.ChainId] = None) tradingstrategy.pair.LegacyPairUniverse

Convert columnar presentation to a Python in-memory objects.

Filter the pairs based on given filter arguments.

get_pair_by_id(pair_id: int) Optional[tradingstrategy.pair.DEXPair]

Resolve pair by its id.

Only useful for debugging. Does a slow look

get_pair_by_ticker(base_token, quote_token) Optional[tradingstrategy.pair.DEXPair]

Get a trading pair by its ticker symbols.

Note that this method works only very simple universes, as any given pair is poised to have multiple tokens and multiple trading pairs on different exchanges.

Raises

DuplicatePair – If the universe contains more than single entry for the pair.

Returns

None if there is no match

get_pair_by_ticker_by_exchange(exchange_id: int, base_token: str, quote_token: str) Optional[tradingstrategy.pair.DEXPair]

Get a trading pair by its ticker symbols.

Note that this method works only very simple universes, as any given pair is poised to have multiple tokens and multiple trading pairs on different exchanges.

Parameters

exchange_id – E.g. 1 for uniswap_v2

Raises

DuplicatePair – If the universe contains more than single entry for the pair. Because we are looking by a token symbol there might be fake tokens with the same symbol.

Returns

None if there is no match

get_all_pairs_on_exchange(exchange_id: int) Iterable[tradingstrategy.pair.DEXPair]

Get all trading pair on a decentralsied exchange.

Use ExchangeUniverse.get_by_chain_and_slug to resolve the exchange_id first. :param chain_id: E.g. ChainId.ethereum

Parameters

exchange_id – E.g. 1 for uniswap_v2

Raises

DuplicatePair – If the universe contains more than single entry for the pair. Because we are looking by a token symbol there might be fake tokens with the same symbol.

Returns

None if there is no match

get_active_pairs() Iterable[tradingstrategy.pair.DEXPair]

Filter for pairs that have see a trade for the last 30 days

get_inactive_pairs() Iterable[tradingstrategy.pair.DEXPair]

Filter for pairs that have not see a trade for the last 30 days

tradingstrategy.pair.filter_for_exchanges(pairs: pandas.core.frame.DataFrame, exchanges: List[tradingstrategy.exchange.Exchange]) pandas.core.frame.DataFrame

Filter dataset so that it only contains data for the trading pairs from a certain exchange.

Useful as a preprocess step for creating tradingstrategy.candle.GroupedCandleUniverse or tradingstrategy.liquidity.GroupedLiquidityUniverse.

tradingstrategy.pair.filter_for_quote_tokens(pairs: pandas.core.frame.DataFrame, quote_token_addresses: Union[List[str], Set[str]]) pandas.core.frame.DataFrame

Filter dataset so that it only contains data for the trading pairs that have a certain quote tokens.

Useful as a preprocess step for creating tradingstrategy.candle.GroupedCandleUniverse or tradingstrategy.liquidity.GroupedLiquidityUniverse.

You might, for example, want to construct a trading universe where you have only BUSD pairs.

Parameters

quote_token_addresses – List of Ethereum addresses of the tokens - most be lowercased, as Ethereum addresses in our raw data are.

class tradingstrategy.pair.StablecoinFilteringMode

How to filter pairs in stablecoin filtering.

tradingstrategy.pair.filter_for_stablecoins(pairs: pandas.core.frame.DataFrame, mode: tradingstrategy.pair.StablecoinFilteringMode) pandas.core.frame.DataFrame

Filter dataset so that it only contains data for the trading pairs that are either stablecoin pairs or not.

Trading logic might not be able to deal with or does not want to deal with stable -> stable pairs. Trading stablecoin to another does not make sense, unless you are doing high volume arbitration strategies.

Uses internal stablecoin list from tradingstrategy.stablecoin.