Internal development process#
Preface#
In this chapter, we will discuss how to developer trading-strategy and trade-executor Python packages.
Installation for local development#
See respective READMEs in Github repositories.
Run tests#
trading-strategy package#
To run tests you need to have a Trading Strategy API key. Tests use the production server.
poetry shell
export TRADING_STRATEGY_API_KEY="secret-token:tradingstrategy-xxx"
pytest
Tests are very slow.
By default, the test run will cache any downloaded blobs. You can force the redownload with:
CLEAR_CACHES=true pytest --log-cli-level=debug -k test_grouped_liquidity
Or manually:
rm -rf /tmp/trading-strategy-tests
trade-executor package#
To run the full test suite, multiple blockchain node connections are needed.
You will also need to have installed
Anvil
Ganache
You also need [Trading Strategy API key](https://tradingstrategy.ai/trading-view/backtesting).
To set environment:
# Free and somewhat robust Polygon endpoint
export JSON_RPC_POLYGON="https://polygon-rpc.com"
export TRADING_STRATEGY_API_KEY=...
export BNB_CHAIN_JSON_RPC=...
Then run:
pytest
Some tests take a long time, because they are checking different real-time timings. You can skip the slow tests with
export SKIP_SLOW_TESTS=true
For more information see Github CI pipeline.
Updating documentation notebooks#
The example notebooks must be run using jupyter notebook server before committing to the documentation, as otherwise Plotly figures won’t display.
Visual Studio Code notebook output gives you Data type cannot be displayed: application/vnd.plotly.v1+json error if added via nbsphinx
PyCharm has internal bugs and fails to finish running notebooks
First set up the development environment:
git clone [email protected]:tradingstrategy-ai/docs.git
co docs
make \
update-git-submodules \
poetry-install \
pip-force-install-deps \
install-furo \
rebuild-furo \
clean-autosummary \
clean \
html
This will create build/html/index.html which you can open in your web browser
open build/html/index.html
And now you can browse the documentation locally using file:// protcol.
Then to rerun and rerender a Jupyter notebook locally.
First start the notebook browser locally in Poetry environment:
jupyter notebook
This will spawn a Jupyter server and open a Jupyter notebook user interface in your web browser. You can later close this with CTRL + C.
Find a notebook that you want to rerender.
Choose clear output. Run it.
Manually inspect that the notebook complete and there are no errors
All figures are rendered
The last cell with print(“Ok”)
= There are no excessive warnings (some warnings are ok)
Then commit new notebook
Create a branch
Push in refreshed ipynb file
Open a PR
Note
Because how Sphinx automsummary works, it may update files under source tree, so be careful when doing a full regeneration of documentation.
Terminal IPython and debugging with ipdb#
You might want to run notebooks in a terminal using ipython
command e.g. for better debugging facilities.
You can run example notebooks in a terminal after git checkout and poetry install:
ipython --TerminalIPythonApp.file_to_run=source/programming/strategy-examples/pancakeswap-ema.ipynb
This is especially useful if you want to debug library code with ipdb.
Dataset cache#
The default cache location for the downloaded datasets is ~/.cache/tradingstrategy.
ls -lha ~/.cache/tradingstrategy
total 56M
drwxr-xr-x 5 moo staff 160 Jul 19 23:14 ./
drwx------ 14 moo staff 448 Jul 18 15:49 ../
-rw-r--r-- 1 moo staff 49M Jul 19 23:14 candles-24h.feather
-rw-r--r-- 1 moo staff 95K Jul 18 15:49 exchange-universe.json
-rw-r--r-- 1 moo staff 6.3M Jul 19 21:57 pair-universe.json.zstd
You can clear this out manually from the UNIX shell
rm -rf ~/.cache/tradingstrategy
Making a release#
poetry build
poetry publish
Memory profiling#
Use pytest-monitor for profiling memory usage. We need to ensure large datasets do not cause issues on low-memory environments like WebAsssembly in web browsers.
pytest-monitor is installed as a dev dependency.
Example:
pytest --db ./monitor.db
sqlite3 ./monitor.db
Then
select ITEM, MEM_USAGE from TEST_METRICS;
Leak detection#
For memory leaks see pytest-leaks.
Warning
pytest-leaks crashes with pyarrow package
Note
Python debug build needed. Here are instructions how to install one. Also, this means you need to create another Poetry environment for leak testing.
First create install a Python debug build with pyenv.
Pick a Python version you want to have a debug build. This cannot be the same as your current Python version, as pyenv will overwrite it. The easiest way is to pick a different patch version of your current interpreter.
pyenv install --list
# We have 3.10.13 as main
pyenv install --debug 3.10.12
Then create a new Poetry environment with debug Python:
git clone --recursive [email protected]:tradingstrategy-ai/trade-executor.git executor-debug
cd executor-debug
pyenv local 3.10.12
# Should be 3.10.12
poetry install --all-extras
pip install pytest-leaks
And run a single test to figure out where the leaks are:
poetry shell
#
pytest --leaks : -k test_load_trading_and_lending_data_historical_certain_assets_only
Profiling Python notebooks for code speed bottlenecks#
You can profile a backtesting notebook with Python’s built-in profiler cProf.
In a notebook extract backtest run function to its own cell and add %%prun meta command:
%%prun -s cumulative
state, _, debug_dump = run_backtest_inline(
name="SLS",
start_at=start_at,
end_at=end_at,
client=client,
cycle_duration=cycle_duration,
decide_trades=decide_trades,
universe=universe,
initial_deposit=initial_deposit,
reserve_currency=reserve_currency,
trade_routing=trade_routing,
log_level=logging.WARNING,
)
Then run the notebook
ipython notebooks/arbitrum-btc-usd-sls-binance-data-1h.ipynb
The output will be in less paged format in your terminal
15192529 function calls (14695168 primitive calls) in 4.701 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
2/1 0.000 0.000 4.706 4.706 {built-in method builtins.exec}
1 0.000 0.000 4.706 4.706 <string>:1(<module>)
1 0.000 0.000 4.706 4.706 backtest_runner.py:405(run_backtest_inline)
1 0.000 0.000 4.706 4.706 backtest_runner.py:297(run_backtest)
1 0.000 0.000 4.706 4.706 loop.py:1209(run_and_setup_backtest)
1 0.010 0.010 4.706 4.706 loop.py:669(run_backtest)
1416 0.007 0.000 4.162 0.003 loop.py:328(tick)
1416 0.013 0.000 4.138 0.003 runner.py:329(tick)
For more information
Building Docker image locally#
For testing trade-executor command or for writing documentation with an unreleased version.
docker build -t ghcr.io/tradingstrategy-ai/trade-executo/trade-executor:latest .
Then copy-paste the image hash from docker build output and run:
docker run -it cf308d43ad577c5194dd8669316a6a80ba6adc901f461ddf287f14915f206082 --help
Converting backtest notebooks to PDF#
You might want to convert backtest results Jupyter Notebooks for PDF format to share them.
Make sure you initialise notebook charting in static (offline) mode:
from tradeexecutor.backtest.notebook import setup_charting_and_output, OutputMode
# Set Jupyter Notebook output mode parameters
setup_charting_and_output(OutputMode.static)
Run the notebook e.g. using Visual Studio Code.
Then you can use nbconvert to generate a PDF out of the notebook:
# Mactex takes long to install
brew install --cask mactex
eval "$(/usr/libexec/path_helper)"
jupyter nbconvert --to pdf uniswap_v3_1h_arbitrum.ipynb
This will generate PDF file from the notebook.