Source code for tradeexecutor.ethereum.routing_data

"""Default routing models for Uniswap v2 like exchange.

Describe which smart contract addresses are used to make a trade.
Map factory addresses, router addresses and quote token addresses.

- This takes one of the default routing options and gives the routing model for it

- The routing model consists of smart contract addresses needed to trade

- Parameters needed for basic routing for an Uniswap v2 compatible exchange:

    - Factory smart contract address

    - Router smart contract address

    - Pair contract "init code hash"

    - Wrapped token address

    - Stablecoin addresses

    - Wrapped token/stablecoin pool address

See also :py:class:`tradeexecutor.strategy.default_routing_options.TradeRouting`
that gives the users the choices for the trade routing options in their strategy module.

"""
from typing import TypedDict, List

from tradingstrategy.chain import ChainId

from tradeexecutor.backtest.backtest_generic_router import EthereumBacktestPairConfigurator
from tradeexecutor.backtest.backtest_routing import BacktestRoutingModel, BacktestRoutingIgnoredModel
from tradeexecutor.ethereum.uniswap_v2.uniswap_v2_routing import UniswapV2Routing
from tradeexecutor.ethereum.uniswap_v3.uniswap_v3_routing import UniswapV3Routing
from tradeexecutor.strategy.execution_context import ExecutionContext, ExecutionMode
from tradeexecutor.strategy.reserve_currency import ReserveCurrency
from tradeexecutor.strategy.default_routing_options import TradeRouting
from tradeexecutor.strategy.routing import RoutingModel


QUICKSWAP_FEE = 0.0030
TRADER_JOE_FEE = 0.0030
PANCAKE_FEE = 0.0025
UNISWAP_V2_FEE = 0.0030

# Allowed exchanges as factory -> router pairs,
# by their smart contract addresses
# init_code_hash not applicable to v3 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
# not really a map, change name? 
# V2 contracts (for router and quoter), not supported yet
# Same address_map for ethereum, polygon and arbitrum
# TODO create address_map class
uniswap_v3_address_map = {
    "factory": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
    "router": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
    "position_manager": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
    "quoter": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6"
    # "router02":"0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
    # "quoterV2":"0x61fFE014bA17989E743c5F6cB21bF9697530B21e"
} 


[docs]class RoutingData(TypedDict): """Describe raw smart contract order routing data.""" chain_id: ChainId #: Factory contract address -> Tuple (default router address, init code hash) factory_router_map: tuple #: Token address -> pair address allowed_intermediary_pairs: dict #: Token address for the reserve currency #: #: E.g. BUSD, USDC address. #: Is given as :py:class:`tradeexecutor.strategy.reserve_currency.ReserveCurrency` #: and mapped to an address. #: reserve_token_address: str #: Supported quote token addresses #: #: Besides reserve currency, we can route three leg trades #: through high liquidity pools. #: E.g. if we buy XXX/BNB pair we route it through BNB/BUSD #: and WBNB would appear here as a supported quote token. #: #: E.g. (WBNB, BUSD), (WBNB, USDC) quote_token_addresses: List[str]
class MismatchReserveCurrency(Exception): """Routing table did not except this asset as a reserve currency and cannot route."""
[docs]def get_pancake_default_routing_parameters( reserve_currency: ReserveCurrency, ) -> RoutingData: """Generate routing using PancakeSwap v2 router. For the Binance Smart Chain. TODO: Polish the interface of this function when we have more strategies """ if reserve_currency == ReserveCurrency.busd: # https://tradingstrategy.ai/trading-view/binance/tokens/0xe9e7cea3dedca5984780bafc599bd69add087d56 reserve_token_address = "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WBNB through BUSD:WBNB pool, # https://tradingstrategy.ai/trading-view/binance/pancakeswap-v2/bnb-busd "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c": "0x58f876857a02d6762e0101bb5c46a8c1ed44dc16", } elif reserve_currency == ReserveCurrency.usdc: # https://tradingstrategy.ai/trading-view/binance/tokens/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d reserve_token_address = "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WBNB through USDC:WBNB pool, # https://tradingstrategy.ai/trading-view/binance/pancakeswap-v2/bnb-usdc "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c": "0xd99c7f6c65857ac913a8f880a4cb84032ab2fc5b", } elif reserve_currency == ReserveCurrency.usdt: # https://tradingstrategy.ai/trading-view/binance/tokens/0x55d398326f99059ff775485246999027b3197955 reserve_token_address = "0x55d398326f99059ff775485246999027b3197955".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WBNB through USDT:WBNB pool, # https://tradingstrategy.ai/trading-view/binance/pancakeswap-v2/bnb-usdt "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c": "0x16b9a82891338f9ba80e2d6970fdda79d1eb0dae", } else: raise NotImplementedError() # Allowed exchanges as factory -> router pairs, # by their smart contract addresses # init_code_hash: https://bscscan.com/address/0x10ED43C718714eb63d5aA57B78B54704E256024E#code#L298 factory_router_map = { "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73": ( "0x10ED43C718714eb63d5aA57B78B54704E256024E", "0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5", ) } return { "chain_id": ChainId.bsc, "factory_router_map": factory_router_map, "allowed_intermediary_pairs": allowed_intermediary_pairs, "reserve_token_address": reserve_token_address, "quote_token_addresses": { "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56", "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", "0x55d398326f99059ff775485246999027b3197955", }, "trading_fee": PANCAKE_FEE, }
[docs]def get_quickswap_default_routing_parameters( reserve_currency: ReserveCurrency, ) -> RoutingData: """Generate routing using Trader Joe router. For Polygon chain. TODO: Polish the interface of this function when we have more strategies """ if reserve_currency == ReserveCurrency.usdc: # https://tradingstrategy.ai/trading-view/polygon/tokens/0x2791bca1f2de4661ed88a30c99a7a9449aa84174 reserve_token_address = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WMATIC through USDC:WMATIC pool, # https://tradingstrategy.ai/trading-view/polygon/quickswap/matic-usdc "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270": "0x6e7a5fafcec6bb1e78bae2a1f0b612012bf14827", # Route WETH through WETH/USDC pool, # https://tradingstrategy.ai/trading-view/polygon/quickswap/eth-usdc "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619": "0x853ee4b2a13f8a742d64c8f088be7ba2131f670d", } elif reserve_currency == ReserveCurrency.usdt: # https://tradingstrategy.ai/trading-view/polygon/tokens/0xc2132d05d31c914a87c6611c10748aeb04b58e8f reserve_token_address = "0xc2132d05d31c914a87c6611c10748aeb04b58e8f".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WMATIC through USDT:WMATIC pool, # https://tradingstrategy.ai/trading-view/polygon/quickswap/matic-usdt "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270": "0x604229c960e5cacf2aaeac8be68ac07ba9df81c3", } elif reserve_currency == ReserveCurrency.dai: # https://tradingstrategy.ai/trading-view/polygon/tokens/0x8f3cf7ad23cd3cadbd9735aff958023239c6a063 reserve_token_address = "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route USDC through DAI:UDSC pool, # https://tradingstrategy.ai/trading-view/polygon/quickswap/dai-usdc "0x2791bca1f2de4661ed88a30c99a7a9449aa84174": "0xf04adbf75cdfc5ed26eea4bbbb991db002036bdd" } else: raise NotImplementedError() # Allowed exchanges as factory -> router pairs, # by their smart contract addresses # init_code_hash: https://polygonscan.com/address/0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff#code#L297 factory_router_map = { "0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32": ( "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff", "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", ) } return { "chain_id": ChainId.polygon, "factory_router_map": factory_router_map, "allowed_intermediary_pairs": allowed_intermediary_pairs, "reserve_token_address": reserve_token_address, "quote_token_addresses": { "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", }, "trading_fee": QUICKSWAP_FEE, }
[docs]def get_sushi_default_routing_parameters( reserve_currency: ReserveCurrency, ) -> RoutingData: """Generate routing using Sushi router. For Polygon chain. TODO: Polish the interface of this function when we have more strategies """ if reserve_currency == ReserveCurrency.usdc: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 reserve_token_address = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WETH through WETH/USDC pool, # https://tradingstrategy.ai/trading-view/ethereum/sushi/eth-usdc "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "0x397ff1542f962076d0bfe58ea045ffa2d347aca0", } elif reserve_currency == ReserveCurrency.usdt: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0xdac17f958d2ee523a2206206994597c13d831ec7 reserve_token_address = "0xdac17f958d2ee523a2206206994597c13d831ec7".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WETH through WETH/USDT pool, # https://tradingstrategy.ai/trading-view/ethereum/sushi/eth-usdt "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "0x06da0fd433c1a5d7a4faa01111c044910a184553", } else: raise NotImplementedError() # Allowed exchanges as factory -> router pairs, # by their smart contract addresses # init_code_hash: https://etherscan.io/address/0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F#code#L103 factory_router_map = { "0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac": ( "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F", "e18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303", ) } return { "chain_id": ChainId.ethereum, "factory_router_map": factory_router_map, "allowed_intermediary_pairs": allowed_intermediary_pairs, "reserve_token_address": reserve_token_address, "quote_token_addresses": { "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", # USDC "0xdac17f958d2ee523a2206206994597c13d831ec7", # USDT "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", # WETH }, "trading_fee": UNISWAP_V2_FEE, }
[docs]def get_trader_joe_default_routing_parameters( reserve_currency: ReserveCurrency, ) -> RoutingData: """Generate routing using Trader Joe router. For the Avalanche C-chain. TODO: Polish the interface of this function when we have more strategies """ if reserve_currency == ReserveCurrency.usdc: # https://tradingstrategy.ai/trading-view/avalanche/tokens/0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e reserve_token_address = "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WAVAX through USDC:WAVAX pool, # https://tradingstrategy.ai/trading-view/avalanche/trader-joe/wavax-usdc "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7": "0xf4003f4efbe8691b60249e6afbd307abe7758adb", } elif reserve_currency == ReserveCurrency.usdt: # https://tradingstrategy.ai/trading-view/avalanche/tokens/0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7 reserve_token_address = "0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WAVAX through USDT:WAVAX pool, # https://tradingstrategy.ai/trading-view/avalanche/trader-joe/usdt-wavax "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7": "0xbb4646a764358ee93c2a9c4a147d5aded527ab73", } else: raise NotImplementedError() # Allowed exchanges as factory -> router pairs, # by their smart contract addresses # init_code_hash: https://snowtrace.io/address/0x60aE616a2155Ee3d9A68541Ba4544862310933d4#code#L174 factory_router_map = { "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10": ( "0x60aE616a2155Ee3d9A68541Ba4544862310933d4", "0x0bbca9af0511ad1a1da383135cf3a8d2ac620e549ef9f6ae3a4c33c2fed0af91", ) } return { "chain_id": ChainId.avalanche, "factory_router_map": factory_router_map, "allowed_intermediary_pairs": allowed_intermediary_pairs, "reserve_token_address": reserve_token_address, "quote_token_addresses": { "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", "0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7" "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7", }, "trading_fee": TRADER_JOE_FEE, }
[docs]def get_uniswap_v2_default_routing_parameters( reserve_currency: ReserveCurrency, ) -> RoutingData: """Generate routing using Uniswap v2 router. TODO: Polish the interface of this function when we have more strategies """ if reserve_currency == ReserveCurrency.usdc: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 reserve_token_address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WETH through USDC:WETH pool, # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v2/eth-usdc "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": "0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc", } elif reserve_currency == ReserveCurrency.usdt: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0xdac17f958d2ee523a2206206994597c13d831ec7 reserve_token_address = "0xdac17f958d2ee523a2206206994597c13d831ec7".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WETH through USDT:WETH pool, # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v2/eth-usdt "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": "0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852", } elif reserve_currency == ReserveCurrency.dai: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0x6b175474e89094c44da98b954eedeac495271d0f reserve_token_address = "0x6b175474e89094c44da98b954eedeac495271d0f".lower() # For three way trades, which pools we can use allowed_intermediary_pairs = { # Route WETH through DAI:WETH pool, # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v2/eth-dai "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11" } else: raise NotImplementedError() # Allowed exchanges as factory -> router pairs, # by their smart contract addresses # https://docs.uniswap.org/protocol/V2/reference/smart-contracts/factory # https://github.com/Uniswap/v2-core/issues/102 # init_code_hash: https://etherscan.io/address/0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D#code#L700 factory_router_map = { "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f": ( "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", "96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", ) } return { "chain_id": ChainId.ethereum, "factory_router_map": factory_router_map, "allowed_intermediary_pairs": allowed_intermediary_pairs, "reserve_token_address": reserve_token_address, # USDC, WETH, USDT "quote_token_addresses": { "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "0xdac17f958d2ee523a2206206994597c13d831ec7", }, "trading_fee": UNISWAP_V2_FEE, }
[docs]def get_uniswap_v3_ethereum_default_routing_parameters( reserve_currency: ReserveCurrency, ) -> RoutingData: """Generate routing using Uniswap V3 router for Ethereum""" if reserve_currency == ReserveCurrency.usdc: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0xdac17f958d2ee523a2206206994597c13d831ec7 reserve_token_address = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48".lower() allowed_intermediary_pairs = { # Route WETH through USDC:WETH fee 0.05% pool, # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/eth-usdc-fee-5 "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", # Route USDT through USDC:USDT fee 0.01% pool, # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/usdt-usdc-fee-1 "0xdac17f958d2ee523a2206206994597c13d831ec7": "0x3416cf6c708da44db2624d63ea0aaef7113527c6", } elif reserve_currency == ReserveCurrency.usdt: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0xdac17f958d2ee523a2206206994597c13d831ec7 reserve_token_address = "0xdac17f958d2ee523a2206206994597c13d831ec7" allowed_intermediary_pairs = { # Route WETH through USDT:ETH fee 0.05% pool # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/eth-usdt-fee-5 "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "0x11b815efb8f581194ae79006d24e0d814b7697f6", # Route USDC through USDT:USDC fee 0.01% pool # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/usdt-usdc-fee-1 "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "0x3416cf6c708da44db2624d63ea0aaef7113527c6", } elif reserve_currency == ReserveCurrency.dai: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0x6b175474e89094c44da98b954eedeac495271d0f reserve_token_address = "0x6b175474e89094c44da98b954eedeac495271d0f" allowed_intermediary_pairs = { # Route WETH through DAI:ETH fee 0.05% pool # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/eth-dai-fee-5 "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", # Route USDC through DAI:USDC 0.01% pool # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/dai-usdc-fee-1 "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "0x5777d92f208679db4b9778590fa3cab3ac9e2168", } elif reserve_currency == ReserveCurrency.busd: # https://tradingstrategy.ai/trading-view/ethereum/tokens/0x4fabb145d64652a948d72533023f6e7a623c7c53 reserve_token_address = "0x4fabb145d64652a948d72533023f6e7a623c7c53" allowed_intermediary_pairs = { # Route USDC through BUSD:USDC fee 0.01% pool # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/busd-usdc-fee-1 "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "0x5e35c4eba72470ee1177dcb14dddf4d9e6d915f4", # Route USDT through BUSD:USDT fee 0.05% pool # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/busd-usdt-fee-5 "0xdac17f958d2ee523a2206206994597c13d831ec7": "0xd5ad5ec825cac700d7deafe3102dc2b6da6d195d", # Route DAI through BUSD:DAI fee 0.01% pool # https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/busd-dai-fee-1 "0x6b175474e89094c44da98b954eedeac495271d0f": "0xd1000344c3a00846462b4624bb452621cf2ce001", } else: raise NotImplementedError() return { "chain_id": ChainId.ethereum, "address_map": uniswap_v3_address_map, "allowed_intermediary_pairs": allowed_intermediary_pairs, "reserve_token_address": reserve_token_address, # USDC, WETH, USDT "quote_token_addresses": { "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "0xdac17f958d2ee523a2206206994597c13d831ec7", }, }
[docs]def get_uniswap_v3_polygon_default_routing_parameters( reserve_currency: ReserveCurrency, ) -> RoutingData: """Generate routing using Uniswap V3 router for Polygon""" if reserve_currency == ReserveCurrency.usdc: # https://tradingstrategy.ai/trading-view/polygon/tokens/0x2791bca1f2de4661ed88a30c99a7a9449aa84174 reserve_token_address = "0x2791bca1f2de4661ed88a30c99a7a9449aa84174".lower() allowed_intermediary_pairs = { # Route WMATIC through USDC:WMATIC fee 0.05% pool, # https://tradingstrategy.ai/trading-view/polygon/uniswap-v3/matic-usdc-fee-5 "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270": "0xa374094527e1673a86de625aa59517c5de346d32", # Route WETH through USDC:WETH fee 0.05% pool, # https://tradingstrategy.ai/trading-view/polygon/uniswap-v3/eth-usdc-fee-5 "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619": "0x45dda9cb7c25131df268515131f647d726f50608", } elif reserve_currency == ReserveCurrency.usdt: # https://tradingstrategy.ai/trading-view/polygon/tokens/0xc2132d05d31c914a87c6611c10748aeb04b58e8f reserve_token_address = "0xc2132d05d31c914a87c6611c10748aeb04b58e8f" allowed_intermediary_pairs = { # Route WMATIC through USDT:ETH fee 0.05% pool # https://tradingstrategy.ai/trading-view/polygon/uniswap-v3/matic-usdt-fee-5 "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270": "0x9b08288c3be4f62bbf8d1c20ac9c5e6f9467d8b7", } return { "chain_id": ChainId.polygon, "address_map": uniswap_v3_address_map, "allowed_intermediary_pairs": allowed_intermediary_pairs, "reserve_token_address": reserve_token_address, # USDC, WMATIC, USDT "quote_token_addresses": { "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", }, }
[docs]def get_uniswap_v3_arbitrum_default_routing_parameters( reserve_currency: ReserveCurrency, ) -> RoutingData: """Generate routing using Uniswap V3 router for Arbitrum""" if reserve_currency == ReserveCurrency.usdc: reserve_token_address = "0xaf88d065e77c8cc2239327c5edb3a432268e5831".lower() allowed_intermediary_pairs = {} elif reserve_currency == ReserveCurrency.usdc_e: reserve_token_address = "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8".lower() allowed_intermediary_pairs = {} elif reserve_currency == ReserveCurrency.usdt: # https://tradingstrategy.ai/trading-view/arbitrum/tokens/0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9 reserve_token_address = "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9" allowed_intermediary_pairs = { # Route WETH through USDT:ETH fee 0.05% pool # https://tradingstrategy.ai/trading-view/arbitrum/uniswap-v3/eth-usdt-fee-5 "0x82af49447d8a07e3bd95bd0d56f35241523fbab1": "0x641c00a822e8b671738d32a431a4fb6074e5c79d", } return { "chain_id": ChainId.arbitrum, "address_map": uniswap_v3_address_map, "allowed_intermediary_pairs": allowed_intermediary_pairs, "reserve_token_address": reserve_token_address, # USDC, WETH, USDT "quote_token_addresses": { "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8", "0xaf88d065e77c8cc2239327c5edb3a432268e5831", "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", }, }
[docs]def get_uniswap_v3_compatible_routing_types_eth(): # TODO find a way to get without hardcoding return { TradeRouting.uniswap_v3_usdc, TradeRouting.uniswap_v3_busd, TradeRouting.uniswap_v3_dai, TradeRouting.uniswap_v3_usdt, }
[docs]def get_uniswap_v3_compatible_routing_types_poly(): # TODO find a way to get without hardcoding return { TradeRouting.uniswap_v3_usdc_poly, TradeRouting.uniswap_v3_usdt_poly, }
[docs]def get_uniswap_v3_compatible_routing_types_arbitrum(): # TODO find a way to get without hardcoding return { TradeRouting.uniswap_v3_usdc_arbitrum_bridged, TradeRouting.uniswap_v3_usdc_arbitrum_native, TradeRouting.uniswap_v3_usdt_arbitrum, }
[docs]def get_all_uniswap_v3_compatible_routing_types(): return get_uniswap_v3_compatible_routing_types_arbitrum() | get_uniswap_v3_compatible_routing_types_eth() | get_uniswap_v3_compatible_routing_types_poly()
[docs]def get_uniswap_v2_compatible_routing_types(): return { TradeRouting.pancakeswap_busd, TradeRouting.pancakeswap_usdc, TradeRouting.pancakeswap_usdt, TradeRouting.uniswap_v2_usdc, TradeRouting.uniswap_v2_usdt, TradeRouting.uniswap_v2_dai, TradeRouting.quickswap_usdc, TradeRouting.quickswap_usdt, TradeRouting.quickswap_dai, TradeRouting.trader_joe_usdt, TradeRouting.trader_joe_usdc, TradeRouting.sushi_usdc, TradeRouting.sushi_usdt, }
[docs]def validate_reserve_currency( routing_type: TradeRouting, reserve_currency: ReserveCurrency ): """Assert that reserve currency matches routing type""" if routing_type == TradeRouting.ignore: # Backtesting that does not use routing return # busd if routing_type in {TradeRouting.pancakeswap_busd, TradeRouting.uniswap_v3_busd}: if reserve_currency != ReserveCurrency.busd: raise MismatchReserveCurrency(f"Got {routing_type} with {reserve_currency}") # usdc elif routing_type in { TradeRouting.pancakeswap_usdc, TradeRouting.quickswap_usdc, TradeRouting.trader_joe_usdc, TradeRouting.sushi_usdc, TradeRouting.uniswap_v2_usdc, TradeRouting.uniswap_v3_usdc, TradeRouting.uniswap_v3_usdc_poly, TradeRouting.uniswap_v3_usdc_arbitrum_native, }: if reserve_currency != ReserveCurrency.usdc: raise MismatchReserveCurrency(f"Got {routing_type} with {reserve_currency}") elif routing_type in { TradeRouting.uniswap_v3_usdc_arbitrum_bridged, }: if reserve_currency != ReserveCurrency.usdc_e: raise MismatchReserveCurrency(f"Got {routing_type} with {reserve_currency}") # usdt elif routing_type in { TradeRouting.pancakeswap_usdt, TradeRouting.quickswap_usdt, TradeRouting.trader_joe_usdt, TradeRouting.sushi_usdt, TradeRouting.uniswap_v2_usdt, TradeRouting.uniswap_v3_usdt, TradeRouting.uniswap_v3_usdt_poly, TradeRouting.uniswap_v3_usdt_arbitrum, }: if reserve_currency != ReserveCurrency.usdt: raise MismatchReserveCurrency(f"Got {routing_type} with {reserve_currency}") # dai elif routing_type in { TradeRouting.quickswap_dai, TradeRouting.uniswap_v2_dai, TradeRouting.uniswap_v3_dai, }: if reserve_currency != ReserveCurrency.dai: raise MismatchReserveCurrency(f"Got {routing_type} with {reserve_currency}") elif routing_type == TradeRouting.user_supplied_routing_model: # Unit tests. # Do nothing pass elif routing_type == TradeRouting.default: # Reserve currency set in create_trading_strategy() pass # else else: raise NotImplementedError(f"Unknown routing type: {routing_type}")
[docs]def get_backtest_routing_model( routing_type: TradeRouting, reserve_currency: ReserveCurrency ) -> BacktestRoutingModel | BacktestRoutingIgnoredModel: """Get routing options for backtests. At the moment, just create a real router and copy parameters from there. """ if routing_type == TradeRouting.ignore: params = get_uniswap_v2_default_routing_parameters(reserve_currency) return BacktestRoutingIgnoredModel(params["reserve_token_address"]) elif routing_type == TradeRouting.default: raise AssertionError(f"Shoudl not be reached. If you use routing_type == TradeRouting.default GenericRouting should have been configured earlier in the stack.") real_routing_model = create_compatible_routing(routing_type, reserve_currency) if isinstance(real_routing_model, UniswapV2Routing): return BacktestRoutingModel( real_routing_model.factory_router_map, real_routing_model.allowed_intermediary_pairs, real_routing_model.reserve_token_address, ) elif isinstance(real_routing_model, UniswapV3Routing): return BacktestRoutingModel( real_routing_model.address_map, real_routing_model.allowed_intermediary_pairs, real_routing_model.reserve_token_address ) else: raise TypeError(f"Routing model must either be of type UniswapV2SimpleRoutingModel, \ or of type UniswapV3SimpleRolutingModel. Received {type(real_routing_model)}")
[docs]def create_uniswap_v2_compatible_routing( routing_type: TradeRouting, reserve_currency: ReserveCurrency ) -> UniswapV2Routing: """Set up Uniswap v2 compatible routing. Not recommended to use by itself, because it doesn't validate reserve currency. Rather use create_compatible_routing :param routing_type: TradeRouting type :param reserve_currency: Reservecurrency type :returns: UniswapV2SimpleRoutingModel""" if routing_type in { TradeRouting.pancakeswap_busd, TradeRouting.pancakeswap_usdc, TradeRouting.pancakeswap_usdt, }: # pancake on bsc params = get_pancake_default_routing_parameters(reserve_currency) elif routing_type in { TradeRouting.quickswap_usdc, TradeRouting.quickswap_usdt, TradeRouting.quickswap_dai, }: # quickswap on polygon params = get_quickswap_default_routing_parameters(reserve_currency) elif routing_type in { TradeRouting.sushi_usdc, TradeRouting.sushi_usdt, }: # sushi on ethereum mainnet params = get_sushi_default_routing_parameters(reserve_currency) elif routing_type in {TradeRouting.trader_joe_usdc, TradeRouting.trader_joe_usdt}: # trader joe on avalanche params = get_trader_joe_default_routing_parameters(reserve_currency) elif routing_type in { TradeRouting.uniswap_v2_usdc, TradeRouting.uniswap_v2_usdt, TradeRouting.uniswap_v2_dai, }: # uniswap v2 on eth params = get_uniswap_v2_default_routing_parameters(reserve_currency) else: raise NotImplementedError() routing_model = UniswapV2Routing( params["factory_router_map"], params["allowed_intermediary_pairs"], params["reserve_token_address"], params["chain_id"], params["trading_fee"], ) return routing_model
[docs]def create_uniswap_v3_compatible_routing( routing_type: TradeRouting, reserve_currency: ReserveCurrency ) -> UniswapV3Routing: """Set up Uniswap v3 compatible routing. Not recommended to use by itself, because it doesn't validate reserve currency. Rather use create_compatible_routing :param routing_type: TradeRouting type :param reserve_currency: Reservecurrency type :returns: UniswapV3SimpleRoutingModel""" if routing_type in get_uniswap_v3_compatible_routing_types_eth(): params = get_uniswap_v3_ethereum_default_routing_parameters(reserve_currency) elif routing_type in get_uniswap_v3_compatible_routing_types_poly(): params = get_uniswap_v3_polygon_default_routing_parameters(reserve_currency) elif routing_type in get_uniswap_v3_compatible_routing_types_arbitrum(): params = get_uniswap_v3_arbitrum_default_routing_parameters(reserve_currency) else: raise NotImplementedError() # Trading fee is derived dynamically for each trading pair routing_model = UniswapV3Routing( params["address_map"], params["allowed_intermediary_pairs"], params["reserve_token_address"], params["chain_id"], ) return routing_model
[docs]def create_compatible_routing( routing_type: TradeRouting, reserve_currency: ReserveCurrency ): """Create compatible routing. At the moment, can either be uniswap-v2 compatible or uniswap-v3 compatible. - This takes one of the default routing options and gives the routing model for it - The routing model consists of smart contract addresses needed to trade, the chainid, and trading fee """ # assert reserve currency matches routing_type validate_reserve_currency(routing_type, reserve_currency) if routing_type in get_uniswap_v2_compatible_routing_types(): return create_uniswap_v2_compatible_routing(routing_type, reserve_currency) elif routing_type in get_all_uniswap_v3_compatible_routing_types(): return create_uniswap_v3_compatible_routing(routing_type, reserve_currency)
[docs]def get_routing_model( execution_context: ExecutionContext, routing_type: TradeRouting, reserve_currency: ReserveCurrency, ) -> RoutingModel: """Create trade routing model for the strategy. :param execution_model: Either backtest or live :param routing_type: One of the default routing options, as definedin backtest notebook or strategy module :param reserve_currency: One of the default reserve currency options, as definedin backtest notebook or strategy module """ if execution_context.mode == ExecutionMode.backtesting: return get_backtest_routing_model(routing_type, reserve_currency) else: return create_compatible_routing(routing_type, reserve_currency)