Architecture overview#
Here is an overview of core concepts and architecture of trading strategy execution, by walking through modules and terms used. Some concepts are common for trading, like positions, but some are specifically created for this project and decentralised markets.
Trade executor#
The trade executor refers to the process that is running live trading or backtesting strategy. There is 1:1 mapping between strategies and OS processes.
Trade executor is set up by a launcing Command line application application or invoking backtesting directly from Jupyter notebook or Python code
Trade executor life cycle depends on if we are doing backtesting or live trading
Trade executor can support different Strategy types
Live trading life cycle#
Live trading main loop life cycle is
Download new trading universe
Decide trades
Revalue positions
Sleep until next cycle
Backtesting life cycle#
Backtesting main loop life cycle is
~ Download trading universe (only once)
And then:
Decide trades
Cycle to the next historical timestamp
Trading universe#
A trading universe defines what trading pairs a strategy can trade.
A classical strategy trades only a single pair like BTC-USD. These strategies have a single pair trading universe.
Trading universe can be fixed or dynamic.
A fixed trading universe might contain 10 top pairs, locked at the start of the strategy.
A dynamic trading universe might contain all trading pairs on PancakeSwap. New pairs are introduced every day.
See
tradeeexecutor.strategy.universe_model
See
tradeeexecutor.strategy.trading_strategy_universe
See
tradingstrategy.universe
Strategy cycle#
Each strategy operates in fixed time intervals called cycles.
A typical cycle is 4h or 24h.
Stop loss and other trigger conditions might happen independently from cycles.
The cycle duration might be different from the used candle duration. E.g. a cycle fo 16 hours can operate on 4 x 4h candles.
See
tradingstrategy.strategy.cycle
State#
The state defines the internal trade executor state.
The state is JSON serialisable
The trade executor uses a single flat file JSON for its state persistency
The state contains open positions, past trades, strategy visualisation data points and such
Both live trading and backtesting produce the same state files
See
tradeeexecutor.state.state
for the core state definitionPersisting, storing and loading the state, is done by
tradeeexecutor.state.store
Portfolio#
Portfolio defines open and closed positions
Portfolio has a reserve currency
All deposits and withdrawals must be in reserve currency
See
tradeeexecutor.state.portfolio
Reserve currency#
Each portfolio must have its own reserve currency.
The standard rese`rve currency is USDC token
All positions and trades are valued in a reserve currency
Currently only one reserve currency per portfolio is supported
Position#
A position is open or closed trading position.
Position is opened with its first trade
Position is closed when there is no more tokens left to sell, or its value goes to zero
Position is always against a trading pair
Position can contain multiple buy and sell trades, it can increase and decrease over time
Frozen positions are specially positions with failed trades and might need manual intervention to be resolved
When position is open, the underlying token is held in a wallet - unlike on centralised exchanges, this same position could be closed by selling the token on another market, but despite this each position tracks a trading pair even though its physically presented by holding a token in a wallet
A strategy manages its positions using
tradeeexecutor.strategy.pandas_trader.position_manager.PositionManager
classSee
tradeeexecutor.state.position
Trade#
Trade is one buy or sell for a position.
Trades are created by position manager
Trade can be buy or sell, short or long
Trade is always against a certain exchange, trading pair and blockchain
The strategy decide_trades function returns a list of new trades to perform on each Strategy cycle
Trades generated by a strategy are abstract, they are mapped to real blockchain transactions by an execution model
See
tradeeexecutor.state.trade
Execution model#
An Execution model converts abstract trades to real blockchain transactions using a hot wallet private key and communicating with a blockchain node.
Execution model communicates with a blockchain node using JSON-RPC
When backtesting, no real transactions are performed
Each trade is mapped to multiple blockchain transactions, depending on what a routing model tells to the execution model
Execution model ensures all blockchain transactions are signed, broadcasted and confirmed in the blockchain network
Execution model marks trades either succeeded or failed
See
tradeeexecutor.strategy.execution_model
See
tradeeexecutor.ethereum.uniswap_v2_exeuction
See
tradeeexecutor.backtest.backtest_execution
Routing model#
Routing model defines how traded are routed between different exchanges and pairs - you can have two-leg (WETH-USDC) or three-leg (AAVE-WETH-USDC) trades.
The simple routing model just routes the the trades directly to one pair contrac
…or indirectly by trading the reserve currency, like USDC, first to WETH, to buy ETH quoted pairs like AAVE-ETH.
Approval model#
Algorithmic trades are usually automatically executed. They might be subject to manual approval for slow moving strategies like daily or weekly.
See
tradeeexecutor.strategy.approval
See
tradeeexecutor.cli.approval
for manual Command line application based approval model
Blockchain transaction#
A blockchain transaction presents a physical transaction with a transaction hash.
One trade can be one or more transactions e.g. approve() and swap() in the case of Uniswap v2 like exchange
Blockchain transactions contain the tracking information of the transaction status: when it was broadcasted, how much gas was used, did the transaction succeed
In the future, more advanced execution models can perform a single trade over a block trading, OTC pools, or splitting one strategy trade to smaller physical trades to get better price execution
See
tradeeexecutor.state.blockchain_transaction
Pricing model#
Pricing model defines the (estimated) asset price for each trade decisions.
In the simplest form, pricing model reads the latest price from Uniswap
Backtesting uses historical pricing model, based on historical backtest datasets
Pricing model consides price impact of a trade
Valuation model#
Valuation model defines the value of open positions.
The position value is usually its sell price on open market
Valuation of open positions is done regularly, e.g. for every hour. This process is called revaluation.
If the position value falls too much a stop loss might be triggered
See
tradeeexecutor.strategy.valuation
Trading pair identifier#
Trading pair identifier uniquely identifies one trading pair
Trading pair is (blockchain, exchange, pair id) tuple
Trading pairs have well-defined base and quota tokens
Trading pair identifier also contains human readable data, like token symbols and decimals needed for some USD conversion math
Trading pair identifies are immutable
Trading pair identifies are passed by copy
See
tradeeexecutor.state.identifier
Token identifier#
Token identifier defines one token in a trading pair.
Token idenfitier contains data like address, name, symbol, decimal
See
tradeeexecutor.state.identifier
Statistics#
Trade executor keeps statistics over a strategy performance
Statistics data does not affect trade decisions
Some statistics are calculated only when a trade is executed
Some statistics are calculated constantly, like position valuations, in a cron job like manner
See
tradeeexecutor.state.statistics
Visualisation#
Like statistics, trade executor tracks visualisation data for a state.
Visualisation data is similar for statistics, but it has some parameters like name and color set by the strategy developer to make it more human readable
Visualisation is especially useful in backtesting to give a human readable diagnostics information on a strategy performance
Visualisation data does not affect trade decisions
Visualisation data is only meant for plotting nice graphs
Some statistics are calculated constantly, like position valuations, in a cron job like manner
See
tradeeexecutor.state.visualisation
Webhook#
Webhook provides HTTP interface for a trade executor, so that web frontend and others can access the strategy state.
See Webhook server