PandasPairUniverse#
API documentation for tradingstrategy.pair.PandasPairUniverse Python class in Trading Strategy framework.
- class PandasPairUniverse[source]#
Bases:
object
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 rawpandas.DataFrame
by using filtering functions intradingstrategy.pair
first, before initializingPandasPairUniverse
.About the usage:
Single trading pairs can be looked up using
PandasPairUniverse.get_pair_by_smart_contract()
andPandasPairUniverse.get_pair_by_id()
Multiple pairs can be looked up by directly reading PandasPairUniverse.df Pandas dataframe
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, build_index=True, exchange_universe=None)[source]#
- Parameters:
df (DataFrame) – The source DataFrame that contains all DEXPair entries
build_index – Build quick lookup index for pairs
exchange_universe (Optional[ExchangeUniverse]) –
Optional exchange universe needed for human-readable pair lookup.
We cannot properly resolve pairs unless we can map exchange names to their ids. Currently optional, only needed by get_pair().
Methods
__init__
(df[, build_index, exchange_universe])- param df:
Create pair_id -> data mapping.
create_limited_pair_universe
(df, exchange, pairs)Create a trading pair universe that contains only few trading pairs.
create_pair_universe
(df, pairs)Create a PandasPairUniverse instance based on loaded raw pairs data.
create_parquet_load_filter
([count_limit])Returns a Parquet loading filter that contains pairs in this universe.
create_single_pair_universe
(df, exchange, ...)Create a trading pair universe that contains only a single trading pair.
Get all pair ids in the data frame.
Get all base and quote tokens in trading pairs.
get_by_symbols
(base_token_symbol, ...)For strategies that trade only a few trading pairs, get the only pair in the universe.
get_by_symbols_safe
(base_token_symbol, ...)Get a trading pair by its ticker symbols.
How many trading pairs there are.
get_exchange_for_pair
(pair)Get the exchange data on which a pair is trading.
get_one_pair_from_pandas_universe
(...[, ...])Get a trading pair by its ticker symbols.
get_pair
(chain_id, exchange_slug, ...[, ...])Get a pair by its description.
get_pair_by_human_description
(desc[, ...])Get pair by its human readable description.
get_pair_by_id
(pair_id)Look up pair information and return its data.
get_pair_by_smart_contract
(address)Resolve a trading pair by its pool smart contract address.
get_pair_ids_by_exchange
(exchange_id)Get all pair ids on a specific exchange.
For strategies that trade only a single trading pair, get the only pair in the universe.
Gets the only trading pair quote token for this trading universe.
get_token
(address[, chain_id])Get a token that is part of any trade pair.
get_token_by_symbol
(symbol[, chain_id, ...])Get one and only one token from the trading universe by its symbol.
Iterate over all pairs in this universe.
Iterate over all tokens in this universe.
limit_to_pairs
(pair_ids)Create a reduced pair universe with
Attributes
pair_id -> raw dict data mappings
pair_id -> constructed DEXPair cache
A hack used in a single trading pair univerwse
- __init__(df, build_index=True, exchange_universe=None)[source]#
- Parameters:
df (DataFrame) – The source DataFrame that contains all DEXPair entries
build_index – Build quick lookup index for pairs
exchange_universe (Optional[ExchangeUniverse]) –
Optional exchange universe needed for human-readable pair lookup.
We cannot properly resolve pairs unless we can map exchange names to their ids. Currently optional, only needed by get_pair().
- pair_map: Dict[int, dict]#
pair_id -> raw dict data mappings
Constructed in one pass from Pandas DataFrame.
Don’t access directly, use
iterate_pairs()
.
- dex_pair_obj_cache: Dict[int, DEXPair]#
pair_id -> constructed DEXPair cache
Don’t access directly, use
iterate_pairs()
.
- limit_to_pairs(pair_ids)[source]#
Create a reduced pair universe with
- Parameters:
pair_ids (Collection[int]) – Only leave these pairs.
- Returns:
New pair universe only with selected pairs
- Return type:
- build_index()[source]#
Create pair_id -> data mapping.
Allows fast lookup of individual pairs.
Warning
This function assumes the universe contains data for only one blockchain. The same address can exist across multiple EVM chains. The created smart contract address index does not index chain id and thus is invalid.
- get_pair_ids_by_exchange(exchange_id)[source]#
Get all pair ids on a specific exchange.
- Returns:
Raw slide of DataFrame
- Parameters:
exchange_id (int) –
- Return type:
DataFrame
- get_pair_by_id(pair_id)[source]#
Look up pair information and return its data.
Uses a cached path. Constructing
DEXPair
objects is a bit slow, so this is a preferred method if you need to access multiple pairs in a hot loop.
- get_pair_by_smart_contract(address)[source]#
Resolve a trading pair by its pool smart contract address.
Warning
This function assumes the universe contains data for only one blockchain. The same address can exist across multiple EVM chains.
- get_token(address, chain_id=None)[source]#
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.
- get_token_by_symbol(symbol, chain_id=None, pick_by_highest_volume=True)[source]#
Get one and only one token from the trading universe by its symbol.
There might be multiple scam tokens for any legit token symbol. By default we use
pick_by_highest_volume
to choose one. If this method does not use, useget_token()
with address lookup instead.This method is not designed for heavy access, as it is using uncached data. Use sparsingly.
- Parameters:
symbol (str) – E.g.
USDC
.chain_id – Match token on a specific chain only.
pick_by_highest_volume –
If multiple mactches are found, pick one witht the highest 30d vol.
Volume is 30d total across all loaded pairs.
- Returns:
Tuple (name, symbol, address, decimals) or None if not found.
- Raises:
MultipleTokensWithSymbol – In the case we get multiple matches.
TokenNotFound – If none of the loaded trading pairs contains a matching token with a symbol.
- Return type:
- get_all_tokens()[source]#
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()[source]#
For strategies that trade only a single trading pair, get the only pair in the universe.
- Raises:
If our pair universe does not have an exact single pair.
If the target pair could not be decoded.
- Return type:
- get_single_quote_token()[source]#
Gets the only trading pair quote token for this trading universe.
- Returns:
Quote token for all trading pairs.
- Raises:
If we have trading pairs with different quotes.
E.g. both
-ETH
and-USDC
pairs.- Return type:
- get_by_symbols(base_token_symbol, quote_token_symbol)[source]#
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_by_symbols_safe(base_token_symbol, quote_token_symbol)[source]#
Get a trading pair by its ticker symbols. In the case of multiple matching pairs, an exception is raised.
- get_one_pair_from_pandas_universe(exchange_id, base_token, quote_token, fee_tier=None, pick_by_highest_vol=False)[source]#
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:
exchange_id (int | None) –
The exchange internal id which we are looking up.
Set
None
to look all exchanges.Uniswap v3 and likes provide the same ticker in multiple fee tiers.
You need to use fee_tier parameter to separate the Uniswap pools. Fee tier is not needed for Uniswap v2 like exchanges as all of their trading pairs have the same fee structure.
The fee tier is 0…1 e.g. 0.0030 for 3 BPS or 0.3% fee tier.
If fee tier is not provided, then the lowest fee tier pair is returned. However the lowest fee tier might not have the best liquidity or volume.
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.
base_token (str) –
quote_token (str) –
- Raises:
DuplicatePair – If the universe contains more than single entry for the pair.
PairNotFoundError – If the pair is not found in the universe.
- Returns:
DEXPairs with the given symbols
- Return type:
- get_pair(chain_id, exchange_slug, base_token, quote_token, fee_tier=None, exchange_universe=None)[source]#
Get a pair by its description.
The simplest way to access pairs in the pair universe.
To use this method, we must include exchange_universe in the
__init__()
as otherwise we do not have required look up tables.- Returns:
The trading pair on the exchange.
Highest volume trading pair if multiple matches.
- Raises:
PairNotFoundError – In the case input data cannot be resolved.
- Parameters:
- Return type:
- get_pair_by_human_description(desc, exchange_universe=None)[source]#
Get pair by its human readable description.
Look up a trading pair by chain, exchange, base, quote token tuple.
See
HumanReadableTradingPairDescription
for more information.Note
API signature change and the order of parameters reversed in TS version 0.19
Example:
# Get BNB-BUSD pair on PancakeSwap v2 desc = (ChainId.bsc, "pancakeswap-v2", "WBNB", "BUSD") bnb_busd = pair_universe.get_pair_by_human_description(desc) assert bnb_busd.base_token_symbol == "WBNB" assert bnb_busd.quote_token_symbol == "BUSD" assert bnb_busd.buy_volume_30d > 1_000_000
Another example:
pair_human_descriptions = ( (ChainId.ethereum, "uniswap-v2", "WETH", "USDC"), # ETH (ChainId.ethereum, "uniswap-v2", "EUL", "WETH", 0.0030), # Euler 30 bps fee (ChainId.ethereum, "uniswap-v3", "EUL", "WETH", 0.0100), # Euler 100 bps fee (ChainId.ethereum, "uniswap-v2", "MKR", "WETH"), # MakerDAO (ChainId.ethereum, "uniswap-v2", "HEX", "WETH"), # MakerDAO (ChainId.ethereum, "uniswap-v2", "FNK", "USDT"), # Finiko (ChainId.ethereum, "sushi", "AAVE", "WETH"), # AAVE (ChainId.ethereum, "sushi", "COMP", "WETH"), # Compound (ChainId.ethereum, "sushi", "WETH", "WBTC"), # BTC (ChainId.ethereum, "sushi", "ILV", "WETH"), # Illivium (ChainId.ethereum, "sushi", "DELTA", "WETH"), # Delta (ChainId.ethereum, "sushi", "UWU", "WETH"), # UwU lend (ChainId.ethereum, "uniswap-v2", "UNI", "WETH"), # UNI (ChainId.ethereum, "uniswap-v2", "CRV", "WETH"), # Curve (ChainId.ethereum, "sushi", "SUSHI", "WETH"), # Sushi (ChainId.bsc, "pancakeswap-v2", "WBNB", "BUSD"), # BNB (ChainId.bsc, "pancakeswap-v2", "Cake", "BUSD"), # Cake (ChainId.bsc, "pancakeswap-v2", "MBOX", "BUSD"), # Mobox (ChainId.bsc, "pancakeswap-v2", "RDNT", "WBNB"), # Radiant (ChainId.polygon, "quickswap", "WMATIC", "USDC"), # Matic (ChainId.polygon, "quickswap", "QI", "WMATIC"), # QiDao (ChainId.polygon, "sushi", "STG", "USDC"), # Stargate (ChainId.avalanche, "trader-joe", "WAVAX", "USDC"), # Avax (ChainId.avalanche, "trader-joe", "JOE", "WAVAX"), # TraderJoe (ChainId.avalanche, "trader-joe", "GMX", "WAVAX"), # GMX (ChainId.arbitrum, "camelot", "ARB", "WETH"), # ARB # (ChainId.arbitrum, "sushi", "MAGIC", "WETH"), # Magic ) client = persistent_test_client exchange_universe = client.fetch_exchange_universe() pairs_df = client.fetch_pair_universe().to_pandas() pair_universe = PandasPairUniverse(pairs_df, exchange_universe=exchange_universe) pairs: List[DEXPair] pairs = [pair_universe.get_pair_by_human_description(exchange_universe, d) for d in pair_human_descriptions] assert len(pairs) == 26 assert pairs[0].exchange_slug == "uniswap-v2" assert pairs[0].get_ticker() == "WETH-USDC" assert pairs[1].exchange_slug == "uniswap-v2" assert pairs[1].get_ticker() == "EUL-WETH"
- Parameters:
desc (Union[Tuple[ChainId, str | None, str, str, float], Tuple[ChainId, str | None, str, str], ExchangeUniverse]) – Trading pair description as tuple (blockchain, dex, base, quote fee)
exchange_universe (Union[ExchangeUniverse, Tuple[ChainId, str | None, str, str, float], Tuple[ChainId, str | None, str, str]]) –
The current database used to decode exchanges.
If not given use the exchange_universe given in the constructor. Either argument here or argument in the constructor must be given.
- Returns:
The trading pair on the exchange.
Highest volume trading pair if multiple matches.
- Raises:
PairNotFoundError – In the case input data cannot be resolved.
- Return type:
- create_parquet_load_filter(count_limit=10000)[source]#
Returns a Parquet loading filter that contains pairs in this universe.
When candle or liquidity file is read to the memory, only read pairs that are within this pair universe. This severely reduces the memory usage and speed ups loading.
- static create_single_pair_universe(df, exchange, base_token_symbol, quote_token_symbol, pick_by_highest_vol=True, fee_tier=None)[source]#
Create a trading pair universe that contains only a single trading pair.
Warning
Deprecated
This is useful for trading strategies that to technical analysis trading on a single trading pair like BTC-USD.
- Parameters:
df (DataFrame) – Unfiltered DataFrame for all pairs
exchange (Exchange) – Exchange instance on the pair is trading
base_token_symbol (str) – Base token symbol of the trading pair
quote_token_symbol (str) – Quote 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
Pick a pair for a specific fee tier.
Uniswap v3 has
- Raises:
DuplicatePair – Multiple pairs matching the criteria
PairNotFoundError – No pairs matching the criteria
- Return type:
- static create_limited_pair_universe(df, exchange, pairs, pick_by_highest_vol=True)[source]#
Create a trading pair universe that contains only few trading pairs.
Warning
Deprecated
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 (DataFrame) – Unfiltered DataFrame for all pairs
exchange (Exchange) – Exchange instance on the pair is trading
pairs (List[Tuple[str, str]]) – 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:
DuplicatePair – Multiple pairs matching the criteria
PairNotFoundError – No pairs matching the criteria
- Return type:
- static create_pair_universe(df, pairs)[source]#
Create a PandasPairUniverse instance based on loaded raw pairs data.
A shortcut method to create a pair universe for a single or few trading pairs, from DataFrame of all possible trading pairs.
Example for a single pair:
pairs_df = client.fetch_pair_universe().to_pandas() pair_universe = PandasPairUniverse.create_pair_universe( pairs_df, [(ChainId.polygon, "uniswap-v3", "WMATIC", "USDC", 0.0005)], ) assert pair_universe.get_count() == 1 pair = pair_universe.get_single() assert pair.base_token_symbol == "WMATIC" assert pair.quote_token_symbol == "USDC" assert pair.fee_tier == 0.0005 # BPS
Example for multiple trading pairs.:
pairs_df = client.fetch_pair_universe().to_pandas() # Create a trading pair universe for a single trading pair # # WMATIC-USD on Uniswap v3 on Polygon, 5 BPS fee tier and 30 BPS fee tier # pair_universe = PandasPairUniverse.create_pair_universe( pairs_df, [ (ChainId.polygon, "uniswap-v3", "WMATIC", "USDC", 0.0005), (ChainId.polygon, "uniswap-v3", "WMATIC", "USDC", 0.0030) ], ) assert pair_universe.get_count() == 2
- Parameters:
df (DataFrame) –
Pandas DataFrame of all pair data.
See
tradingstrategy.client.Client.fetch_pair_universe()
for more information.pairs (Collection[Union[Tuple[ChainId, str | None, str, str, float], Tuple[ChainId, str | None, str, str]]]) –
List of pair human descriptions.
Warning: If any of descriptions have fee set, all must have fee set, or there might be resolution issues.
- Returns:
A trading pair universe that contains only the listed trading pairs.
- Return type: