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 definition

  • Persisting, 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 class

  • See 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.