├── .github
├── ISSUE_TEMPLATE.md
└── workflows
│ ├── main.yml
│ └── publish.yml
├── .gitignore
├── .travis.yml
├── .vscode
├── launch.json
└── settings.json
├── LICENSE
├── MANIFEST.in
├── README.md
├── changelog.md
├── docs
├── .buildinfo
├── .nojekyll
├── _sources
│ ├── backtest.md.txt
│ ├── brokerage.rst.txt
│ ├── data.rst.txt
│ ├── event.rst.txt
│ ├── gui.rst.txt
│ ├── index.rst.txt
│ ├── installation.md.txt
│ ├── instrument.md.txt
│ ├── intro.md.txt
│ ├── introduction.md.txt
│ ├── livetrading.md.txt
│ ├── order.rst.txt
│ ├── ordertype.md.txt
│ ├── performance.rst.txt
│ ├── position.rst.txt
│ ├── risk.rst.txt
│ ├── strategy.rst.txt
│ ├── trading_engine.rst.txt
│ └── tradingengine.rst.txt
├── _static
│ ├── alabaster.css
│ ├── basic.css
│ ├── css
│ │ ├── badge_only.css
│ │ ├── fonts
│ │ │ ├── Roboto-Slab-Bold.woff
│ │ │ ├── Roboto-Slab-Bold.woff2
│ │ │ ├── Roboto-Slab-Regular.woff
│ │ │ ├── Roboto-Slab-Regular.woff2
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.svg
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ ├── fontawesome-webfont.woff
│ │ │ ├── fontawesome-webfont.woff2
│ │ │ ├── lato-bold-italic.woff
│ │ │ ├── lato-bold-italic.woff2
│ │ │ ├── lato-bold.woff
│ │ │ ├── lato-bold.woff2
│ │ │ ├── lato-normal-italic.woff
│ │ │ ├── lato-normal-italic.woff2
│ │ │ ├── lato-normal.woff
│ │ │ └── lato-normal.woff2
│ │ └── theme.css
│ ├── custom.css
│ ├── doctools.js
│ ├── documentation_options.js
│ ├── file.png
│ ├── fonts
│ │ ├── FontAwesome.otf
│ │ ├── Lato
│ │ │ ├── lato-bold.eot
│ │ │ ├── lato-bold.ttf
│ │ │ ├── lato-bold.woff
│ │ │ ├── lato-bold.woff2
│ │ │ ├── lato-bolditalic.eot
│ │ │ ├── lato-bolditalic.ttf
│ │ │ ├── lato-bolditalic.woff
│ │ │ ├── lato-bolditalic.woff2
│ │ │ ├── lato-italic.eot
│ │ │ ├── lato-italic.ttf
│ │ │ ├── lato-italic.woff
│ │ │ ├── lato-italic.woff2
│ │ │ ├── lato-regular.eot
│ │ │ ├── lato-regular.ttf
│ │ │ ├── lato-regular.woff
│ │ │ └── lato-regular.woff2
│ │ ├── Roboto-Slab-Bold.woff
│ │ ├── Roboto-Slab-Bold.woff2
│ │ ├── Roboto-Slab-Light.woff
│ │ ├── Roboto-Slab-Light.woff2
│ │ ├── Roboto-Slab-Regular.woff
│ │ ├── Roboto-Slab-Regular.woff2
│ │ ├── Roboto-Slab-Thin.woff
│ │ ├── Roboto-Slab-Thin.woff2
│ │ ├── RobotoSlab
│ │ │ ├── roboto-slab-v7-bold.eot
│ │ │ ├── roboto-slab-v7-bold.ttf
│ │ │ ├── roboto-slab-v7-bold.woff
│ │ │ ├── roboto-slab-v7-bold.woff2
│ │ │ ├── roboto-slab-v7-regular.eot
│ │ │ ├── roboto-slab-v7-regular.ttf
│ │ │ ├── roboto-slab-v7-regular.woff
│ │ │ └── roboto-slab-v7-regular.woff2
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.svg
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ ├── fontawesome-webfont.woff2
│ │ ├── lato-bold-italic.woff
│ │ ├── lato-bold-italic.woff2
│ │ ├── lato-bold.woff
│ │ ├── lato-bold.woff2
│ │ ├── lato-normal-italic.woff
│ │ ├── lato-normal-italic.woff2
│ │ ├── lato-normal.woff
│ │ └── lato-normal.woff2
│ ├── jquery-3.5.1.js
│ ├── jquery.js
│ ├── js
│ │ ├── badge_only.js
│ │ ├── html5shiv-printshiv.min.js
│ │ ├── html5shiv.min.js
│ │ ├── modernizr.min.js
│ │ └── theme.js
│ ├── language_data.js
│ ├── minus.png
│ ├── plus.png
│ ├── pygments.css
│ ├── searchtools.js
│ ├── underscore-1.3.1.js
│ └── underscore.js
├── backtest.html
├── brokerage.html
├── data.html
├── event.html
├── genindex.html
├── gui.html
├── index.html
├── installation.html
├── instrument.html
├── intro.html
├── introduction.html
├── livetrading.html
├── objects.inv
├── order.html
├── ordertype.html
├── performance.html
├── position.html
├── py-modindex.html
├── risk.html
├── search.html
├── searchindex.js
├── strategy.html
├── trading_engine.html
└── tradingengine.html
├── examples
├── BENCH.csv
├── TEST.csv
├── __init__.py
├── buy_and_hold_strategy.py
├── config_live.yaml
├── download_historical_data_from_ib.py
├── download_ib_contract_info.py
├── gui.png
├── gui
│ └── image
│ │ └── logo.ico
├── instrument_meta.yaml
├── live_engine.py
├── prepare_trading_session.py
└── strategy
│ ├── __init__.py
│ ├── active_buy_sell_strength_strategy.py
│ ├── double_moving_average_cross_strategy.py
│ ├── dual_thrust.csv
│ ├── dual_thrust_strategy.py
│ ├── dual_time_frame_strategy.py
│ ├── moving_average_cross_strategy.py
│ └── order_per_interval_strategy.py
├── mypy.ini
├── poetry.lock
├── pyproject.toml
├── quanttrader
├── __init__.py
├── account
│ ├── __init__.py
│ ├── account_event.py
│ └── account_manager.py
├── backtest_engine.py
├── brokerage
│ ├── __init__.py
│ ├── backtest_brokerage.py
│ ├── brokerage_base.py
│ └── ib_brokerage.py
├── data
│ ├── __init__.py
│ ├── backtest_data_feed.py
│ ├── bar_event.py
│ ├── data_board.py
│ ├── data_feed_base.py
│ ├── live_data_feed.py
│ └── tick_event.py
├── event
│ ├── __init__.py
│ ├── backtest_event_engine.py
│ ├── event.py
│ └── live_event_engine.py
├── gui
│ ├── __init__.py
│ ├── image
│ │ └── logo.ico
│ ├── ui_account_window.py
│ ├── ui_fill_window.py
│ ├── ui_log_window.py
│ ├── ui_main_window.py
│ ├── ui_order_window.py
│ ├── ui_position_menu.py
│ ├── ui_position_window.py
│ ├── ui_risk_menu.py
│ ├── ui_strategy_window.py
│ └── ui_trade_menu.py
├── log
│ ├── __init__.py
│ ├── tick_recorder.py
│ ├── trade_recorder.py
│ └── trade_recorder_base.py
├── order
│ ├── __init__.py
│ ├── fill_event.py
│ ├── order_event.py
│ ├── order_flag.py
│ ├── order_manager.py
│ ├── order_status.py
│ └── order_type.py
├── performance
│ ├── __init__.py
│ ├── performance_manager.py
│ └── report_manager.py
├── portfolio_env.py
├── position
│ ├── __init__.py
│ ├── contract_event.py
│ ├── position.py
│ ├── position_event.py
│ └── position_manager.py
├── risk
│ ├── __init__.py
│ ├── margin_manager.py
│ ├── risk_manager.py
│ └── risk_manager_base.py
├── strategy
│ ├── __init__.py
│ ├── strategy_base.py
│ └── strategy_manager.py
├── trading_env.py
├── util
│ ├── __init__.py
│ └── util_func.py
└── version.py
├── sphinx
├── Makefile
├── _build
│ ├── doctrees
│ │ ├── backtest.doctree
│ │ ├── brokerage.doctree
│ │ ├── data.doctree
│ │ ├── environment.pickle
│ │ ├── event.doctree
│ │ ├── gui.doctree
│ │ ├── index.doctree
│ │ ├── installation.doctree
│ │ ├── instrument.doctree
│ │ ├── intro.doctree
│ │ ├── introduction.doctree
│ │ ├── livetrading.doctree
│ │ ├── order.doctree
│ │ ├── ordertype.doctree
│ │ ├── performance.doctree
│ │ ├── position.doctree
│ │ ├── risk.doctree
│ │ ├── strategy.doctree
│ │ ├── trading_engine.doctree
│ │ └── tradingengine.doctree
│ └── html
│ │ ├── .buildinfo
│ │ ├── _sources
│ │ ├── backtest.md.txt
│ │ ├── brokerage.rst.txt
│ │ ├── data.rst.txt
│ │ ├── event.rst.txt
│ │ ├── gui.rst.txt
│ │ ├── index.rst.txt
│ │ ├── installation.md.txt
│ │ ├── instrument.md.txt
│ │ ├── intro.md.txt
│ │ ├── introduction.md.txt
│ │ ├── livetrading.md.txt
│ │ ├── order.rst.txt
│ │ ├── ordertype.md.txt
│ │ ├── performance.rst.txt
│ │ ├── position.rst.txt
│ │ ├── risk.rst.txt
│ │ ├── strategy.rst.txt
│ │ ├── trading_engine.rst.txt
│ │ └── tradingengine.rst.txt
│ │ ├── _static
│ │ ├── alabaster.css
│ │ ├── basic.css
│ │ ├── css
│ │ │ ├── badge_only.css
│ │ │ ├── fonts
│ │ │ │ ├── Roboto-Slab-Bold.woff
│ │ │ │ ├── Roboto-Slab-Bold.woff2
│ │ │ │ ├── Roboto-Slab-Regular.woff
│ │ │ │ ├── Roboto-Slab-Regular.woff2
│ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ ├── fontawesome-webfont.svg
│ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ ├── fontawesome-webfont.woff2
│ │ │ │ ├── lato-bold-italic.woff
│ │ │ │ ├── lato-bold-italic.woff2
│ │ │ │ ├── lato-bold.woff
│ │ │ │ ├── lato-bold.woff2
│ │ │ │ ├── lato-normal-italic.woff
│ │ │ │ ├── lato-normal-italic.woff2
│ │ │ │ ├── lato-normal.woff
│ │ │ │ └── lato-normal.woff2
│ │ │ └── theme.css
│ │ ├── custom.css
│ │ ├── doctools.js
│ │ ├── documentation_options.js
│ │ ├── file.png
│ │ ├── fonts
│ │ │ ├── FontAwesome.otf
│ │ │ ├── Lato
│ │ │ │ ├── lato-bold.eot
│ │ │ │ ├── lato-bold.ttf
│ │ │ │ ├── lato-bold.woff
│ │ │ │ ├── lato-bold.woff2
│ │ │ │ ├── lato-bolditalic.eot
│ │ │ │ ├── lato-bolditalic.ttf
│ │ │ │ ├── lato-bolditalic.woff
│ │ │ │ ├── lato-bolditalic.woff2
│ │ │ │ ├── lato-italic.eot
│ │ │ │ ├── lato-italic.ttf
│ │ │ │ ├── lato-italic.woff
│ │ │ │ ├── lato-italic.woff2
│ │ │ │ ├── lato-regular.eot
│ │ │ │ ├── lato-regular.ttf
│ │ │ │ ├── lato-regular.woff
│ │ │ │ └── lato-regular.woff2
│ │ │ ├── Roboto-Slab-Bold.woff
│ │ │ ├── Roboto-Slab-Bold.woff2
│ │ │ ├── Roboto-Slab-Light.woff
│ │ │ ├── Roboto-Slab-Light.woff2
│ │ │ ├── Roboto-Slab-Regular.woff
│ │ │ ├── Roboto-Slab-Regular.woff2
│ │ │ ├── Roboto-Slab-Thin.woff
│ │ │ ├── Roboto-Slab-Thin.woff2
│ │ │ ├── RobotoSlab
│ │ │ │ ├── roboto-slab-v7-bold.eot
│ │ │ │ ├── roboto-slab-v7-bold.ttf
│ │ │ │ ├── roboto-slab-v7-bold.woff
│ │ │ │ ├── roboto-slab-v7-bold.woff2
│ │ │ │ ├── roboto-slab-v7-regular.eot
│ │ │ │ ├── roboto-slab-v7-regular.ttf
│ │ │ │ ├── roboto-slab-v7-regular.woff
│ │ │ │ └── roboto-slab-v7-regular.woff2
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.svg
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ ├── fontawesome-webfont.woff
│ │ │ ├── fontawesome-webfont.woff2
│ │ │ ├── lato-bold-italic.woff
│ │ │ ├── lato-bold-italic.woff2
│ │ │ ├── lato-bold.woff
│ │ │ ├── lato-bold.woff2
│ │ │ ├── lato-normal-italic.woff
│ │ │ ├── lato-normal-italic.woff2
│ │ │ ├── lato-normal.woff
│ │ │ └── lato-normal.woff2
│ │ ├── jquery-3.5.1.js
│ │ ├── jquery.js
│ │ ├── js
│ │ │ ├── badge_only.js
│ │ │ ├── html5shiv-printshiv.min.js
│ │ │ ├── html5shiv.min.js
│ │ │ ├── modernizr.min.js
│ │ │ └── theme.js
│ │ ├── language_data.js
│ │ ├── minus.png
│ │ ├── plus.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── underscore-1.3.1.js
│ │ └── underscore.js
│ │ ├── backtest.html
│ │ ├── brokerage.html
│ │ ├── data.html
│ │ ├── event.html
│ │ ├── genindex.html
│ │ ├── gui.html
│ │ ├── index.html
│ │ ├── installation.html
│ │ ├── instrument.html
│ │ ├── intro.html
│ │ ├── introduction.html
│ │ ├── livetrading.html
│ │ ├── objects.inv
│ │ ├── order.html
│ │ ├── ordertype.html
│ │ ├── performance.html
│ │ ├── position.html
│ │ ├── py-modindex.html
│ │ ├── risk.html
│ │ ├── search.html
│ │ ├── searchindex.js
│ │ ├── strategy.html
│ │ ├── trading_engine.html
│ │ └── tradingengine.html
├── backtest.md
├── brokerage.rst
├── conf.py
├── data.rst
├── event.rst
├── googleaa7b60d3069d75c3.html
├── gui.rst
├── index.rst
├── installation.md
├── instrument.md
├── introduction.md
├── livetrading.md
├── make.bat
├── order.rst
├── ordertype.md
├── performance.rst
├── position.rst
├── risk.rst
├── strategy.rst
└── tradingengine.rst
├── tests
├── __init__.py
├── test_data
│ ├── BENCH.csv
│ └── TEST.csv
└── test_strats.py
└── tick
└── 20240618.txt
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | * quanttrader version:
2 | * Python version:
3 | * Operating System:
4 |
5 | ### Description
6 |
7 | Describe what you were trying to get done.
8 | Tell us what happened, what went wrong, and what you expected to happen.
9 |
10 | ### What I Did
11 |
12 | ```
13 | Paste the command(s) you ran and the output.
14 | If there was a crash, please include the traceback here.
15 | ```
16 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: main
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | python-version: ["3.12"]
11 | steps:
12 | - uses: actions/checkout@v4
13 |
14 | - name: Set up Python ${{ matrix.python-version }}
15 | uses: actions/setup-python@v3
16 | with:
17 | python-version: ${{ matrix.python-version }}
18 |
19 | - name: Cache dependencies
20 | uses: actions/cache@v2
21 | with:
22 | path: ~/.cache/pypoetry
23 | key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
24 | restore-keys: |
25 | ${{ runner.os }}-poetry-
26 |
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | python -m pip install poetry
31 | poetry install
32 |
33 | - name: Check code formatting with black
34 | run: |
35 | poetry run isort --check .
36 | poetry run black --check .
37 |
38 | - name: Analysing the code with pylint
39 | run: |
40 | poetry run pylint $(git ls-files '*.py')
41 |
42 | - name: Run tests
43 | run: poetry run pytest
44 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to PyPI
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*' # This triggers the workflow on new tags starting with "v"
7 |
8 | jobs:
9 | publish:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Checkout code
14 | uses: actions/checkout@v3
15 |
16 | - name: Set up Python
17 | uses: actions/setup-python@v4
18 | with:
19 | python-version: '3.12' # Specify your Python version
20 |
21 | - name: Install dependencies
22 | run: |
23 | python -m pip install --upgrade pip
24 | python -m pip install poetry
25 | poetry install
26 | pip install build twine
27 |
28 | - name: Build package
29 | run: python -m build
30 |
31 | - name: Publish to PyPI
32 | env:
33 | TWINE_USERNAME: __token__
34 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
35 | run: python -m twine upload dist/*
36 |
37 | - name: Clean up
38 | run: rm -rf dist build *.egg-info
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 | *.xml
6 | *.iml
7 | examples/log/
8 | examples/tick/
9 |
10 | # C extensions
11 | *.so
12 |
13 | # Distribution / packaging
14 | .Python
15 | build/
16 | develop-eggs/
17 | dist/
18 | downloads/
19 | eggs/
20 | .eggs/
21 | lib/
22 | lib64/
23 | parts/
24 | sdist/
25 | var/
26 | wheels/
27 | pip-wheel-metadata/
28 | share/python-wheels/
29 | *.egg-info/
30 | .installed.cfg
31 | *.egg
32 | MANIFEST
33 |
34 | # PyInstaller
35 | # Usually these files are written by a python script from a template
36 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
37 | *.manifest
38 | *.spec
39 |
40 | # Installer logs
41 | pip-log.txt
42 | pip-delete-this-directory.txt
43 |
44 | # Unit test / coverage reports
45 | htmlcov/
46 | .tox/
47 | .nox/
48 | .coverage
49 | .coverage.*
50 | .cache
51 | nosetests.xml
52 | coverage.xml
53 | *.cover
54 | *.py,cover
55 | .hypothesis/
56 | .pytest_cache/
57 |
58 | # Translations
59 | *.mo
60 | *.pot
61 |
62 | # Django stuff:
63 | *.log
64 | local_settings.py
65 | db.sqlite3
66 | db.sqlite3-journal
67 |
68 | # Flask stuff:
69 | instance/
70 | .webassets-cache
71 |
72 | # Scrapy stuff:
73 | .scrapy
74 |
75 | # Sphinx documentation
76 | docs/_build/
77 |
78 | # PyBuilder
79 | target/
80 |
81 | # Jupyter Notebook
82 | .ipynb_checkpoints
83 |
84 | # IPython
85 | profile_default/
86 | ipython_config.py
87 |
88 | # pyenv
89 | .python-version
90 |
91 | # pipenv
92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
95 | # install all needed dependencies.
96 | #Pipfile.lock
97 |
98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
99 | __pypackages__/
100 |
101 | # Celery stuff
102 | celerybeat-schedule
103 | celerybeat.pid
104 |
105 | # SageMath parsed files
106 | *.sage.py
107 |
108 | # Environments
109 | .env
110 | .venv
111 | env/
112 | venv/
113 | ENV/
114 | env.bak/
115 | venv.bak/
116 |
117 | # Spyder project settings
118 | .spyderproject
119 | .spyproject
120 |
121 | # Rope project settings
122 | .ropeproject
123 |
124 | # mkdocs documentation
125 | /site
126 |
127 | # mypy
128 | .mypy_cache/
129 | .dmypy.json
130 | dmypy.json
131 |
132 | # Pyre type checker
133 | .pyre/
134 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | ncsudo: required
2 |
3 | language: python
4 |
5 | python:
6 | - 3.6
7 | - 3.7
8 | - 3.8
9 |
10 | install:
11 | - pip install -r requirements.txt
12 |
13 | script:
14 | - pytest
15 |
16 | deploy:
17 | provider: pypi
18 | user: letianzj
19 | password:
20 | secure: I/YdGexN0bIPIltYZOkMGr9Kpaby3XOfrAac0WvUhYPpNmaNyAmlCB/eUzq5r4n6chsmiWBcOj2k1ePsrtweqra0aSgAYLGv7jN8xtSMWk1rkdzB4zbMVjyvyrIyNYCtf+dmhkWGLN685WmrrTujGuGTE9IpmCqz8sBWbiLToyodAc1NK6xTF+z1NqdKwufLXKoj4dzHSmt6WHyuxGS0f0UbW8znBL6DwHUY2UFFBCZUQUZkNFS+K1Hf+LXeNU2AwDMcTf9V6daUmTU0lWdYlrzCHdbL0kMazFVGnXF3NOSoV3F4+CnH/r5ryNA4dDtkrnyYUhL3o3aDABrlW6dhzJ0mM2v+RhzPm+n2Q0AD0R/gzv64DthNKZxeJI2RQ91T/z/tOgqJi6p8FH7AbpYIJl1ztO4TCYzyTKh9FqBImPQo+esXxF968qPy5ROmCNl5SbAKsy48m9NpsH1w+mluYUsq+fOyqctZuNa1aZxRmw9vXTY606+Fx3LE9oj4RnDNA4GxD+O7M1SA2+6uDJ+8rL87RAeOD0ZPwUyPSsMlM5DpU2NLMc+ZSxuIVEjo0E0+PP7eawYtUN+stb62Xo/VL2/qpuAWqaqu6SQCtVUTyCLnzDhJCWGd24o4ssILsTr2gG1A769YaJkc/dIYwz79HVzMtXPUiMu63Ji9TB1mt4k=
21 | on:
22 | tags: true
23 | distributions: bdist_wheel
24 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Python Debugger: Current File",
9 | "type": "debugpy",
10 | "request": "launch",
11 | "program": "${file}",
12 | "env": {
13 | "PYTHONPATH": "${workspaceFolder};${workspaceFolder}/src" // ; on windows
14 | },
15 | "console": "integratedTerminal",
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true,
3 | "editor.defaultFormatter": "ms-python.black-formatter",
4 | "black-formatter.args": ["--line-length", "100"],
5 | "python.testing.pytestArgs": [
6 | "tests"
7 | ],
8 | "python.testing.unittestEnabled": false,
9 | "python.testing.pytestEnabled": true,
10 | }
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # quanttrader
2 | [](https://pypi.python.org/pypi/quanttrader)
3 | [](https://pypi.python.org/pypi/quanttrader)
4 | [](https://opensource.org/licenses/MIT)
5 |
6 | Welcome to quanttrader, a pure python-based event-driven backtest and live trading package for quant traders.
7 |
8 | The source code is completely open-sourced [here on GitHub](https://github.com/letianzj/quanttrader). The package is published [here on pypi](https://pypi.org/project/quanttrader/) and is ready to be pip installed. The document is hosted [here on readthedocs](https://quanttrader.readthedocs.io/).
9 |
10 | In most cases, a backtest strategy can be directly used for live trade by simply switching to live brokerage. A control window is provided to monitor live trading sessions for each strategy separately and the portfolio as a whole.
11 |
12 | ### Backtest
13 |
14 | [Backtest code structure](https://letianzj.github.io/quanttrading-backtest.html)
15 |
16 | [Backtests examples](https://github.com/letianzj/QuantResearch/tree/master/backtest)
17 |
18 | [Reinforcement trader](https://github.com/letianzj/QuantResearch/blob/master/ml/reinforcement_trader.ipynb)
19 |
20 | ### Live trading
21 |
22 | [Live Trading demo video](https://youtu.be/CrsrTxqiXNY)
23 |
24 | [Live Trading code structure](https://letianzj.github.io/live-trading-ib-native-python.html)
25 |
26 | __Prerequisite__: download and install IB TWS or IB Gateway; enable API connection as described [here](https://interactivebrokers.github.io/tws-api/initial_setup.html).
27 |
28 | __Installation__
29 |
30 | Step 1
31 |
32 | ```shell
33 | pip install quanttrader
34 | ```
35 |
36 | Alternatively, download or git the source code and include unzipped path in PYTHONPATH environment variable.
37 |
38 | step 2
39 |
40 | Download [live_engine.py](https://github.com/letianzj/quanttrader/blob/master/examples/live_engine.py), [config_live.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/config_live.yaml), [order_per_interval_strategy.py](order_per_interval_strategy.py) by clicking Raw button, right clicking save as, and then change the file extension to .py or .yaml.
41 |
42 | step 3
43 | ```shell
44 | cd where_the_files_are_saved
45 | python live_engine.py
46 | ```
47 |
48 | __Instruments Supported and Example__
49 |
50 | * __Stock__: AMZN STK SMART
51 | * __Foreign Exchange__: EURGBP CASH IDEALPRO
52 | * __Futures__: ESM9 FUT GLOBEX
53 | * __Options on Stock__: AAPL OPT 20201016 128.75 C SMART
54 | * __Options on Futures__: ES FOP 20200911 3450 C 50 GLOBEX
55 | * __Comdty__: XAUUSD CMDTY SMART
56 |
57 | __Order Type Supported__
58 |
59 | Basic order types. See [IB Doc](http://interactivebrokers.github.io/tws-api/basic_orders.html) for details.
60 | * Auction
61 | * Auction Limit
62 | * Market
63 | * Market If Touched
64 | * Market On Close
65 | * Market On Open
66 | * Market to Limit
67 | * Limit Order
68 | * Limit if Touched
69 | * Limit on Close
70 | * Limit on Open
71 | * Stop
72 | * Stop Limit
73 | * Trailing Stop
74 | * Trailing Stop Limit
75 |
76 |
77 | 
78 |
79 |
80 | **DISCLAIMER**
81 | Open source, free to use, free to contribute, use at own risk. No promise of future profits nor responsibility of future loses.
82 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/changelog.md
--------------------------------------------------------------------------------
/docs/.buildinfo:
--------------------------------------------------------------------------------
1 | # Sphinx build info version 1
2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3 | config: a7f9dea1d954c700f5fc66492ec65237
4 | tags: 645f666f9bcd5a90fca523b33c5a78b7
5 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/_sources/backtest.md.txt:
--------------------------------------------------------------------------------
1 | ## Backtest
2 |
3 | [This document](https://letianzj.github.io/quanttrading-backtest.html) explains quanttrader backtest framework and code structure.
4 |
5 | [This repository](https://github.com/letianzj/QuantResearch/tree/master/backtest) contains examples of some classical strategies and their Sharpe ratios, as well as grid-search based parameter optimization. The backtest is designed to be working together with the [pyfolio](https://github.com/quantopian/pyfolio) library.
6 |
7 | One distinctive design in backtest is that it fills market order right away instead of filling against tomorrow's open price. After all, in the daily bar setting, it is better to send out order at 15:59:59 than waiting overnight for next day' open. If you disagree, simply save the market order similar to limit or stop order in the BacktestBrokerage class and then fill it on next tick.
8 |
9 | Currently backtest accepts three data feeds.
10 |
11 | * Daily bar or intraday bar from Yahoo Finance. See [here](https://medium.com/@letian.zj/free-historical-market-data-download-in-python-74e8edd462cf?source=friends_link&sk=5af814910524a593353ed3146290d50e) for how to download.
12 |
13 | * Historical intraday bar from Interactive Brokers. Use [this script](https://github.com/letianzj/quanttrader/blob/master/examples/download_historical_data_from_ib.py) to download.
14 |
15 | * Live tick recorded from live trading session. [This video](https://t.co/rXdW8EIbWw?amp=1) demonstrates how to do it in live session.
16 |
17 | It is possible to load your own data source by following the above examples.
18 |
19 |
--------------------------------------------------------------------------------
/docs/_sources/brokerage.rst.txt:
--------------------------------------------------------------------------------
1 | Brokerage
2 | ==================
3 |
4 | .. autoclass:: quanttrader.brokerage.backtest_brokerage.BacktestBrokerage
5 | :members:
6 |
7 | .. automethod:: __init__
8 |
9 | .. autoclass:: quanttrader.brokerage.ib_brokerage.InteractiveBrokers
10 | :members:
11 |
12 | .. automethod:: __init__
--------------------------------------------------------------------------------
/docs/_sources/data.rst.txt:
--------------------------------------------------------------------------------
1 | Data
2 | ==================
3 |
4 | .. automodule:: quanttrader.data.backtest_data_feed
5 | :members:
6 |
7 | .. automodule:: quanttrader.data.data_board
8 | :members:
9 |
10 | .. automodule:: quanttrader.data.live_data_feed
11 | :members:
--------------------------------------------------------------------------------
/docs/_sources/event.rst.txt:
--------------------------------------------------------------------------------
1 | Event
2 | ==================
3 |
4 | .. automodule:: quanttrader.event.backtest_event_engine
5 | :members:
6 |
7 | .. automodule:: quanttrader.event.live_event_engine
8 | :members:
--------------------------------------------------------------------------------
/docs/_sources/gui.rst.txt:
--------------------------------------------------------------------------------
1 | GUI
2 | ==================
3 |
4 | .. automodule:: quanttrader.gui.ui_account_window
5 | :members:
6 |
7 | .. automodule:: quanttrader.gui.ui_fill_window
8 | :members:
9 |
10 | .. automodule:: quanttrader.gui.ui_log_window
11 | :members:
12 |
13 | .. automodule:: quanttrader.gui.ui_order_window
14 | :members:
15 |
16 | .. automodule:: quanttrader.gui.ui_position_menu
17 | :members:
18 |
19 | .. automodule:: quanttrader.gui.ui_position_window
20 | :members:
21 |
22 | .. automodule:: quanttrader.gui.ui_risk_menu
23 | :members:
24 |
25 | .. automodule:: quanttrader.gui.ui_strategy_window
26 | :members:
27 |
28 | .. automodule:: quanttrader.gui.ui_trade_menu
29 | :members:
--------------------------------------------------------------------------------
/docs/_sources/index.rst.txt:
--------------------------------------------------------------------------------
1 | Welcome to quanttrader documentation!
2 | =======================================
3 |
4 | **Pure Python Backtest and Live Trade Package for Quant Traders**
5 |
6 | .. toctree::
7 | :maxdepth: 2
8 | :caption: Contents
9 |
10 | introduction.md
11 | installation.md
12 | backtest.md
13 | livetrading.md
14 | instrument.md
15 | ordertype.md
16 |
17 | .. toctree::
18 | :maxdepth: 2
19 | :caption: Codes
20 |
21 | brokerage
22 | data
23 | event
24 | gui
25 | order
26 | performance
27 | position
28 | risk
29 | strategy
30 | tradingengine
31 |
32 | Indices and tables
33 | ==================
34 |
35 | * :ref:`genindex`
36 | * :ref:`modindex`
37 | * :ref:`search`
38 |
--------------------------------------------------------------------------------
/docs/_sources/installation.md.txt:
--------------------------------------------------------------------------------
1 | ## Installation
2 |
3 | The quanttrader package is ready for pip install.
4 |
5 | ```python
6 | pip install quanttrader
7 | ```
8 |
9 | To use source code, git pull the repository or use [GitHub desktop](https://desktop.github.com/) and then add the project path to PYTHONPATH environment variable.
10 |
--------------------------------------------------------------------------------
/docs/_sources/instrument.md.txt:
--------------------------------------------------------------------------------
1 | ## Instruments Supported
2 |
3 | Intrument type and example
4 |
5 | * __Stock:__ AMZN STK SMART
6 | * __Foreign Exchange:__ EURGBP CASH IDEALPRO
7 | * __Futures:__ ESM9 FUT GLOBEX
8 | * __Options on Stock:__ AAPL OPT 20201016 128.75 C SMART
9 | * __Options on Futures:__ ES FOP 20200911 3450 C 50 GLOBEX
10 | * __Comdty:__ XAUUSD CMDTY SMART
11 | * __Stock Combo:__: SPY,AAPL BAG 756733 1 SMART 265598 1 SMART SMART
12 | * __Option Combo:__: SPY BAG 398943121 1 SMART 398943218 1 SMART SMART # straddle
13 | * __Calendar Spread__: CL BAG 174230608 1 NYMEX 174230606 1 NYMEX NYMEX
14 | * __Inter-Comdty Spread__: CL.BZ BAG 174230606 1 NYMEX 162929662 1 NYMEX NYMEX
--------------------------------------------------------------------------------
/docs/_sources/intro.md.txt:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | This is introduction
4 |
5 | ```python
6 | s = "Python syntax highlighting"
7 | print s
8 | ```
9 |
--------------------------------------------------------------------------------
/docs/_sources/introduction.md.txt:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | Welcome to quanttrader, a pure python-based event-driven backtest and live trading package for quant traders.
4 |
5 | In most cases, a backtest strategy can be directly used for live trade by simply switching to live brokerage. A control window is provided to monitor live trading sessions for each strategy separately and the portfolio as a whole.
6 |
7 | The source code is completely open-sourced [here on GitHub](https://github.com/letianzj/quanttrader). The package is published [here on pypi](https://pypi.org/project/quanttrader/) and is ready to be pip installed. The document is hosted [here on readthedocs](https://quanttrader.readthedocs.io/).
8 |
9 | This is NOT an ultra-low latency framework that can provide nano-second level executions. The response time, for example, between receiving data from the broker and sending out orders for a pairs-trading strategy that is subscribed to two stock feeds, is in the neighbourhood of milli-seconds. This package is designed mainly for quant traders who do not rely on market-making strategies.
10 |
11 | __Disclaimer: This is an open-source library that is free to use, free to contribute but use at OWN risk. It does NOT promise any future profits nor is responsible for any future loses.__
12 |
13 |
--------------------------------------------------------------------------------
/docs/_sources/livetrading.md.txt:
--------------------------------------------------------------------------------
1 | ## Live Trading
2 |
3 | [This youtube video](https://t.co/rXdW8EIbWw?amp=1) and [accompanying document](https://letianzj.github.io/live-trading-ib-native-python.html) demonstrates step-by-step how to set up quanttrader for live trading. Currently quanttrader only supports Interactive Brokers.
4 |
5 | __Files used for live Trading are__
6 |
7 | * [live_engine.py](https://github.com/letianzj/quanttrader/blob/master/examples/live_engine.py) - the main entry point
8 |
9 | * [config_live.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/config_live.yaml) - config file for live session
10 |
11 | * [instrument_meta.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/instrument_meta.yaml) - meta data for instruments to be traded
12 |
13 | * [prepare_trading_session.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/prepare_trading_session.py) - an example to demonstrate how to prepare data and strategy parameters before today's live session
14 |
--------------------------------------------------------------------------------
/docs/_sources/order.rst.txt:
--------------------------------------------------------------------------------
1 | Order
2 | ==================
3 | .. automodule:: quanttrader.order.order_manager
4 | :members:
--------------------------------------------------------------------------------
/docs/_sources/ordertype.md.txt:
--------------------------------------------------------------------------------
1 | ## Orders Supported
2 |
3 | Basic order types. See [IB Doc](http://interactivebrokers.github.io/tws-api/basic_orders.html) for details.
4 |
5 | * Auction
6 | * Auction Limit
7 | * Market
8 | * Market If Touched
9 | * Market On Close
10 | * Market On Open
11 | * Market to Limit
12 | * Limit Order
13 | * Limit if Touched
14 | * Limit on Close
15 | * Limit on Open
16 | * Stop
17 | * Stop Limit
18 | * Trailing Stop
19 | * Trailing Stop Limit
20 |
--------------------------------------------------------------------------------
/docs/_sources/performance.rst.txt:
--------------------------------------------------------------------------------
1 | Performance
2 | ==================
3 | .. automodule:: quanttrader.performance.performance_manager
4 | :members:
--------------------------------------------------------------------------------
/docs/_sources/position.rst.txt:
--------------------------------------------------------------------------------
1 | Position
2 | ==================
3 | .. automodule:: quanttrader.position.position_manager
4 | :members:
--------------------------------------------------------------------------------
/docs/_sources/risk.rst.txt:
--------------------------------------------------------------------------------
1 | Risk
2 | ==================
3 | .. automodule:: quanttrader.risk.risk_manager
4 | :members:
--------------------------------------------------------------------------------
/docs/_sources/strategy.rst.txt:
--------------------------------------------------------------------------------
1 | Strategy
2 | ==================
3 |
4 | .. automodule:: quanttrader.strategy.strategy_base
5 | :members:
6 | :undoc-members:
7 |
8 | .. automodule:: quanttrader.strategy.strategy_manager
9 | :members:
10 | :undoc-members:
--------------------------------------------------------------------------------
/docs/_sources/trading_engine.rst.txt:
--------------------------------------------------------------------------------
1 | Trading Engine
2 | ==================
3 |
4 | .. automodule:: quanttrader.gui.ui_main_window
5 | :members:
6 | :undoc-members:
7 |
8 | .. automodule:: quanttrader.backtest_engine
9 | :members:
10 | :undoc-members:
--------------------------------------------------------------------------------
/docs/_sources/tradingengine.rst.txt:
--------------------------------------------------------------------------------
1 | Trading Engine
2 | ==================
3 |
4 | .. automodule:: quanttrader.gui.ui_main_window
5 | :members:
6 | :undoc-members:
7 |
8 | .. automodule:: quanttrader.backtest_engine
9 | :members:
10 | :undoc-members:
--------------------------------------------------------------------------------
/docs/_static/css/badge_only.css:
--------------------------------------------------------------------------------
1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
--------------------------------------------------------------------------------
/docs/_static/css/fonts/Roboto-Slab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/Roboto-Slab-Bold.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/Roboto-Slab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/Roboto-Slab-Bold.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/Roboto-Slab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/Roboto-Slab-Regular.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/Roboto-Slab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/Roboto-Slab-Regular.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/_static/css/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/_static/css/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-bold-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/lato-bold-italic.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-bold-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/lato-bold-italic.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/lato-bold.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/lato-bold.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-normal-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/lato-normal-italic.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-normal-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/lato-normal-italic.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/lato-normal.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-normal.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/css/fonts/lato-normal.woff2
--------------------------------------------------------------------------------
/docs/_static/custom.css:
--------------------------------------------------------------------------------
1 | /* This file intentionally left blank. */
2 |
--------------------------------------------------------------------------------
/docs/_static/documentation_options.js:
--------------------------------------------------------------------------------
1 | var DOCUMENTATION_OPTIONS = {
2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 | VERSION: '0.5.0',
4 | LANGUAGE: 'None',
5 | COLLAPSE_INDEX: false,
6 | BUILDER: 'html',
7 | FILE_SUFFIX: '.html',
8 | LINK_SUFFIX: '.html',
9 | HAS_SOURCE: true,
10 | SOURCELINK_SUFFIX: '.txt',
11 | NAVIGATION_WITH_KEYS: false
12 | };
--------------------------------------------------------------------------------
/docs/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/file.png
--------------------------------------------------------------------------------
/docs/_static/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-bold.eot
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-bold.ttf
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-bold.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-bold.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-bolditalic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-bolditalic.eot
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-bolditalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-bolditalic.ttf
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-bolditalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-bolditalic.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-bolditalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-bolditalic.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-italic.eot
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-italic.ttf
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-italic.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-italic.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-regular.eot
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-regular.ttf
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-regular.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/Lato/lato-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Lato/lato-regular.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/Roboto-Slab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Roboto-Slab-Bold.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/Roboto-Slab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Roboto-Slab-Bold.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/Roboto-Slab-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Roboto-Slab-Light.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/Roboto-Slab-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Roboto-Slab-Light.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/Roboto-Slab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Roboto-Slab-Regular.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/Roboto-Slab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Roboto-Slab-Regular.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/Roboto-Slab-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Roboto-Slab-Thin.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/Roboto-Slab-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/Roboto-Slab-Thin.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot
--------------------------------------------------------------------------------
/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf
--------------------------------------------------------------------------------
/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot
--------------------------------------------------------------------------------
/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf
--------------------------------------------------------------------------------
/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/_static/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/_static/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/lato-bold-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/lato-bold-italic.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/lato-bold-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/lato-bold-italic.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/lato-bold.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/lato-bold.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/lato-normal-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/lato-normal-italic.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/lato-normal-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/lato-normal-italic.woff2
--------------------------------------------------------------------------------
/docs/_static/fonts/lato-normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/lato-normal.woff
--------------------------------------------------------------------------------
/docs/_static/fonts/lato-normal.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/docs/_static/fonts/lato-normal.woff2
--------------------------------------------------------------------------------
/docs/_static/js/badge_only.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
--------------------------------------------------------------------------------
/docs/_static/js/html5shiv-printshiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/docs/_static/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/docs/_static/js/theme.js:
--------------------------------------------------------------------------------
1 | !function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap(""),n("table.docutils.citation").wrap(""),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}t.length>0&&($(".wy-menu-vertical .current").removeClass("current"),t.addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l1").parent().addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l2").addClass("current"),t.closest("li.toctree-l3").addClass("current"),t.closest("li.toctree-l4").addClass("current"),t.closest("li.toctree-l5").addClass("current"),t[0].scrollIntoView())}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t None:
22 | super().__init__()
23 | self.invested: bool = False
24 |
25 | def on_tick(self, tick_event: TickEvent) -> None:
26 | print(tick_event.timestamp)
27 | symbol = self.symbols[0]
28 | if not self.invested:
29 | df_hist = self._data_board.get_hist_price(symbol, tick_event.timestamp)
30 | close = df_hist.iloc[-1]["Close"]
31 | timestamp = df_hist.index[-1]
32 | target_size = int(self._position_manager.initial_capital / close)
33 | self.adjust_position(
34 | symbol, size_from=0, size_to=target_size, timestamp=timestamp
35 | )
36 | self.invested = True
37 |
38 |
39 | if __name__ == "__main__":
40 | df = read_ohlcv_csv(
41 | os.path.join(os.path.abspath(os.path.dirname(__file__)), "TEST.csv")
42 | )
43 | INIT_CAPITAL = 100_000.0
44 | test_start_date = datetime(
45 | 2008, 1, 1, 8, 30, 0, 0, pytz.timezone("America/New_York")
46 | )
47 | test_end_date = datetime(
48 | 2008, 12, 31, 6, 0, 0, 0, pytz.timezone("America/New_York")
49 | )
50 | strategy = BuyAndHoldStrategy()
51 | strategy.set_capital(INIT_CAPITAL)
52 | strategy.set_symbols(["TTT"])
53 | # strategy.set_params(None) # no params to set
54 |
55 | backtest_engine = BacktestEngine(test_start_date, test_end_date)
56 | backtest_engine.set_capital(
57 | INIT_CAPITAL
58 | ) # capital or portfolio >= capital for one strategy
59 | backtest_engine.add_data("TTT", df)
60 | backtest_engine.set_strategy(strategy)
61 | equity, df_positions, df_trades = backtest_engine.run()
62 | if df_trades is None:
63 | print("Empty Strategy")
64 | else:
65 | print(equity)
66 |
--------------------------------------------------------------------------------
/examples/config_live.yaml:
--------------------------------------------------------------------------------
1 | account: LU1832
2 | client_id: 0
3 | host: 127.0.0.1
4 | port: 7497
5 | theme: dark
6 | strategy:
7 | #---------- Strategy and params control -----------#
8 | # DoubleMovingAverageCrossStrategy:
9 | # active: false
10 | # capital: 10000
11 | # params:
12 | # n_fast_ma: 20
13 | # n_slow_ma: 200
14 | # symbols:
15 | # - NGZ0 FUT NYMEX
16 | #---------- Strategy and params control -----------#
17 | # DualTimeFrameStrategy:
18 | # active: false
19 | # capital: 10000
20 | # params:
21 | # start_time: '09:30:00'
22 | # end_time: '16:14:58'
23 | # bar_start_time: '09:00:00'
24 | # bar_end_time: '16:15:00'
25 | # lookback_5sec: 50
26 | # lookback_15sec: 20
27 | # symbols:
28 | # - EUM4 FUT GLOBEX
29 | #---------- Strategy and params control -----------#
30 | # DualThrustStrategy:
31 | # active: false
32 | # capital: 10000
33 | # params:
34 | # G: 20
35 | # symbols:
36 | # - MESZ0 FUT GLOBEX
37 | #---------- Strategy and params control -----------#
38 | # MovingAverageCrossStrategy:
39 | # active: false
40 | # capital: 10000
41 | # params:
42 | # G: 20
43 | # symbols:
44 | # - CLZ0 FUT NYMEX
45 | #---------- Strategy and params control -----------#
46 | # ActiveBuySellStrengthStrategy:
47 | # active: false
48 | # capital: 10000
49 | # params:
50 | # strength_abs_threshold: 200
51 | # symbols:
52 | # - NQZ0 FUT GLOBEX
53 | #---------- Strategy, params control, and local risk control -----------#
54 | OrderPerIntervalStrategy:
55 | active: false
56 | capital: 50000
57 | order_start_time: '10:00:00'
58 | order_end_time: '23:15:00'
59 | params:
60 | tick_trigger_threshold: 100
61 | single_trade_limit: 3
62 | symbols:
63 | - ESU4 FUT CME
64 | - VXU4 FUT CFE
65 | total_active_limit: 2
66 | total_cancel_limit: 5
67 | total_loss_limit: 100000
68 | total_trade_limit: 1500
69 | #---------- global risk control -----------#
70 | total_active_limit: 10
71 | total_cancel_limit: 10
72 | total_loss_limit: 10000
73 | total_trade_limit: 200
74 |
--------------------------------------------------------------------------------
/examples/download_ib_contract_info.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import argparse
4 | import logging
5 | import time
6 | from signal import SIG_DFL, SIGINT, signal
7 |
8 | from ibapi.contract import Contract
9 |
10 | from quanttrader.brokerage.ib_brokerage import InteractiveBrokers
11 | from quanttrader.event.live_event_engine import LiveEventEngine
12 |
13 | signal(SIGINT, SIG_DFL)
14 |
15 |
16 | def log_event_handler(log_event):
17 | print(f"{log_event.timestamp}: {log_event.content}")
18 |
19 |
20 | def run(conid):
21 | _logger = logging.getLogger("quanttrader")
22 | _logger.setLevel(logging.DEBUG)
23 | handler1 = logging.StreamHandler()
24 | formatter = logging.Formatter(
25 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
26 | )
27 | handler1.setFormatter(formatter)
28 | _logger.addHandler(handler1)
29 |
30 | events_engine = LiveEventEngine()
31 | tick_event_engine = LiveEventEngine()
32 | broker = InteractiveBrokers(events_engine, tick_event_engine, "DU0001")
33 | broker.reqid = 5000
34 | # events_engine.register_handler(EventType.LOG, log_event_handler)
35 | events_engine.start()
36 | tick_event_engine.start()
37 |
38 | broker.connect("127.0.0.1", 7497, 0)
39 | time.sleep(5) # 5 seconds
40 |
41 | contract = Contract()
42 | contract.conId = conid
43 |
44 | broker.api.reqContractDetails(broker.reqid, contract)
45 |
46 | time.sleep(5) # 5 seconds
47 | broker.disconnect()
48 | events_engine.stop()
49 | tick_event_engine.stop()
50 |
51 |
52 | if __name__ == "__main__":
53 | parser = argparse.ArgumentParser(description="Contract Details")
54 | parser.add_argument("--conid", help="conid e.g. 383974324", required=True)
55 |
56 | args = parser.parse_args()
57 | run(args.conid)
58 |
--------------------------------------------------------------------------------
/examples/gui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/examples/gui.png
--------------------------------------------------------------------------------
/examples/gui/image/logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/examples/gui/image/logo.ico
--------------------------------------------------------------------------------
/examples/instrument_meta.yaml:
--------------------------------------------------------------------------------
1 | # default: multiplier: 1
2 | # margin: 100%
3 |
4 | ES:
5 | Type: FUT
6 | Root: ES
7 | Multiplier: 50.0
8 | Margin: 12000.0
9 | Exchange: GLOBEX
10 | NQ:
11 | Type: FUT
12 | Root: NQ
13 | Multiplier: 20.0
14 | Margin: 16000.0
15 | Exchange: GLOBEX
16 | MES:
17 | Type: FUT
18 | Root: MES
19 | Multiplier: 5.0
20 | Margin: 1200.0
21 | Exchange: GLOBEX
22 | MNQ:
23 | Type: FUT
24 | Root: MNQ
25 | Multiplier: 2.0
26 | Margin: 1600.0
27 | Exchange: GLOBEX
28 | CL:
29 | Type: FUT
30 | Root: CL
31 | Multiplier: 1000.0
32 | Margin: 6200.0
33 | Exchange: NYMEX
34 | HO:
35 | Type: FUT
36 | Root: HO
37 | Multiplier: 42000.0
38 | Margin: 5100.0
39 | Exchange: NYMEX
40 | RB:
41 | Type: FUT
42 | Root: RB
43 | Multiplier: 42000.0
44 | Margin: 6000.0
45 | Exchange: NYMEX
46 | NG:
47 | Type: FUT
48 | Root: NG
49 | Multiplier: 10000.0
50 | Margin: 2300.0
51 | Exchange: NYMEX
52 |
--------------------------------------------------------------------------------
/examples/live_engine.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import argparse
4 | import importlib
5 | import logging
6 | import os
7 | import sys
8 | from datetime import datetime
9 | from signal import SIG_DFL, SIGINT, signal
10 |
11 | import qdarkstyle
12 | import yaml
13 | from PyQt5 import QtGui, QtWidgets
14 |
15 | from quanttrader.gui.ui_main_window import MainWindow
16 |
17 | # https://stackoverflow.com/questions/4938723/what-is-the-correct-way-to-make-my-pyqt-application-quit-when-killed-from-the-co
18 | signal(SIGINT, SIG_DFL)
19 |
20 |
21 | def main(config_file, instrument_meta_file):
22 | config = {}
23 | today = datetime.today().strftime("%Y%m%d")
24 | try:
25 | # path = os.path.abspath(os.path.dirname(__file__))
26 | with open(config_file, encoding="utf8") as fd:
27 | config = yaml.safe_load(fd)
28 | except IOError:
29 | print("config.yaml is missing")
30 | config["root_path"] = os.getcwd()
31 |
32 | instrument_meta = {}
33 | try:
34 | with open(instrument_meta_file, encoding="utf8") as fd:
35 | instrument_meta = yaml.safe_load(fd)
36 | except IOError:
37 | pass
38 |
39 | required_dirs = ["./log/", "./tick/", "./strategy/"]
40 | for d in required_dirs:
41 | if not os.path.exists(d):
42 | os.makedirs(d)
43 |
44 | _logger = logging.getLogger("quanttrader")
45 | _logger.setLevel(logging.DEBUG)
46 | handler1 = logging.StreamHandler()
47 | handler2 = logging.FileHandler(f"./log/{today}.log")
48 | formatter = logging.Formatter(
49 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
50 | )
51 | handler1.setFormatter(formatter)
52 | handler2.setFormatter(formatter)
53 | _logger.addHandler(handler1)
54 | _logger.addHandler(handler2)
55 |
56 | _logger2 = logging.getLogger("qtlive")
57 | _logger2.setLevel(logging.DEBUG)
58 | _logger2.addHandler(handler1)
59 | _logger2.addHandler(handler2)
60 |
61 | _logger3 = logging.getLogger("tick_recorder")
62 | _logger3.setLevel(logging.INFO)
63 | handler3 = logging.FileHandler(f"./tick/{today}.txt")
64 | formatter = logging.Formatter("")
65 | handler3.setFormatter(formatter)
66 | _logger3.addHandler(handler3)
67 |
68 | strategy_dict = {}
69 | for _, _, files in os.walk("./strategy"):
70 | for name in files:
71 | if "strategy" in name and ".pyc" not in name:
72 | s = name.replace(".py", "")
73 | try:
74 | module_name = f"strategy.{s}"
75 | # import module
76 | module = importlib.import_module(module_name)
77 | for k in dir(module):
78 | if (
79 | ("Strategy" in k)
80 | and ("Abstract" not in k)
81 | and (k in config["strategy"])
82 | ):
83 | v = getattr(module, k)
84 | _strategy = v()
85 | _strategy.set_name(k)
86 | strategy_dict[k] = _strategy
87 | except Exception as e: # pylint: disable=broad-except
88 | _logger2.error(f"Unable to load strategy {s}: {str(e)}")
89 |
90 | app = QtWidgets.QApplication(sys.argv) # pylint: disable=c-extension-no-member
91 | app.setWindowIcon(
92 | QtGui.QIcon("gui/image/logo.ico")
93 | ) # pylint: disable=c-extension-no-member
94 | main_window = MainWindow(config, instrument_meta, strategy_dict)
95 |
96 | if config["theme"] == "dark":
97 | app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
98 |
99 | main_window.show() # .showMaximized()
100 | sys.exit(app.exec_())
101 |
102 |
103 | if __name__ == "__main__":
104 | parser = argparse.ArgumentParser(description="Live Engine")
105 | parser.add_argument(
106 | "-f",
107 | "--config_file",
108 | dest="config_file",
109 | default="./config_live.yaml",
110 | help="config yaml file",
111 | )
112 | parser.add_argument(
113 | "-m",
114 | "--instrument_meta",
115 | dest="instrument_meta",
116 | default="./instrument_meta.yaml",
117 | help="instrument meta file",
118 | )
119 | args = parser.parse_args()
120 |
121 | main(args.config_file, args.instrument_meta)
122 |
--------------------------------------------------------------------------------
/examples/prepare_trading_session.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import argparse
4 |
5 | import pandas as pd
6 | import yaml
7 |
8 |
9 | def run(target_path, config_file):
10 | with open(config_file, encoding="utf8") as fd:
11 | config = yaml.safe_load(fd)
12 |
13 | # DualThrustStrategy
14 | # 1. config
15 | config["strategy"]["DualThrustStrategy"]["params"]["G"] = 20
16 |
17 | # 2. data
18 | sname = "dual_thrust"
19 | index = pd.date_range("1/1/2020", periods=100, freq="T")
20 | s1 = pd.Series(range(100), index=index)
21 | s1.name = "price"
22 | s2 = pd.Series(range(100), index=index)
23 | s2.name = "volume"
24 | df = pd.concat([s1, s2], axis=1)
25 | df.to_csv(f"{target_path}{sname}.csv", header=True, index=True)
26 |
27 | # save config
28 | with open(config_file, "w", encoding="utf-8") as file:
29 | yaml.dump(config, file)
30 |
31 |
32 | if __name__ == "__main__":
33 | parser = argparse.ArgumentParser(description="Trading session preparation")
34 | parser.add_argument("--date", help="today")
35 | parser.add_argument(
36 | "-f",
37 | "--config_file",
38 | dest="config_file",
39 | default="./config_live.yaml",
40 | help="config yaml file",
41 | )
42 | parser.add_argument(
43 | "-p", "--path", dest="path", default="./strategy/", help="data path"
44 | )
45 |
46 | args = parser.parse_args()
47 | run(args.path, args.config_file)
48 |
49 | print("Dene session preparation. Ready to trade")
50 |
--------------------------------------------------------------------------------
/examples/strategy/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
--------------------------------------------------------------------------------
/examples/strategy/double_moving_average_cross_strategy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import logging
4 | from datetime import datetime
5 |
6 | import pandas as pd
7 | import ta
8 | import ta.momentum
9 | import ta.trend
10 |
11 | from quanttrader.data.tick_event import TickType
12 | from quanttrader.order.order_event import OrderEvent
13 | from quanttrader.order.order_type import OrderType
14 | from quanttrader.strategy.strategy_base import StrategyBase
15 |
16 | _logger = logging.getLogger("qtlive")
17 |
18 |
19 | class DoubleMovingAverageCrossStrategy(StrategyBase):
20 | """
21 | EMA
22 | """
23 |
24 | def __init__(self):
25 | super(DoubleMovingAverageCrossStrategy, self).__init__()
26 | today = datetime.today()
27 | # midnight = today.replace(hour=0, minute=0, second=0, microsecond=0)
28 | self.start_time = today.replace(
29 | hour=9, minute=30, second=0, microsecond=0
30 | ) # 9:00 to start initiation
31 | self.end_time = today.replace(hour=16, minute=0, second=0, microsecond=0)
32 | seconds = (
33 | self.end_time - self.start_time
34 | ).seconds # start_time is always positive even if start_time - end_time
35 | # 6.5*60*60 = 23400
36 | self.df_bar = pd.DataFrame(
37 | index=range(seconds),
38 | columns=["Open", "High", "Low", "Close", "Volume"],
39 | ) # filled with
40 | self.df_bar_idx = -1
41 | self.current_pos = 0
42 | self.n_fast_ma = 20
43 | self.n_slow_ma = 200
44 | _logger.info("DoubleMovingAverageCrossStrategy initiated")
45 |
46 | def on_tick(self, tick_event):
47 | k = tick_event
48 | super().on_tick(k) # extra mtm calc
49 |
50 | if k.tick_type != TickType.TRADE:
51 | return
52 |
53 | if k.timestamp < self.start_time:
54 | return
55 |
56 | print(k)
57 |
58 | if k.timestamp >= self.end_time: # don't add to new bar
59 | return
60 |
61 | seconds = (k.timestamp - self.start_time).seconds
62 |
63 | if seconds == self.df_bar_idx: # same bar
64 | self.df_bar["High"].iloc[seconds] = max(
65 | self.df_bar["High"].iloc[seconds], k.price
66 | )
67 | self.df_bar["Low"].iloc[seconds] = min(
68 | self.df_bar["Low"].iloc[seconds], k.price
69 | )
70 | self.df_bar["Close"].iloc[seconds] = k.price
71 | self.df_bar["Volume"].iloc[seconds] += k.size
72 | else: # new bar
73 | self.df_bar["Open"].iloc[seconds] = k.price
74 | self.df_bar["High"].iloc[seconds] = k.price
75 | self.df_bar["Low"].iloc[seconds] = k.price
76 | self.df_bar["Close"].iloc[seconds] = k.price
77 | self.df_bar["Volume"].iloc[seconds] = k.size
78 | self.df_bar_idx = seconds
79 |
80 | df1 = self.df_bar["Close"].dropna()
81 |
82 | if df1.shape[0] < self.n_slow_ma:
83 | _logger.info(
84 | f"DoubleMovingAverageCrossStrategy wait for enough bars, {df1.shape[0]} / {self.n_slow_ma}"
85 | )
86 | return
87 |
88 | ma_fast = ta.trend.sma_indicator(df1, self.n_fast_ma).iloc[
89 | -1
90 | ] # talib actually calculates rolling SMA; not as efficient
91 | ma_slow = ta.trend.sma_indicator(df1, self.n_slow_ma).iloc[-1]
92 |
93 | if ma_fast > ma_slow:
94 | if self.current_pos <= 0:
95 | o = OrderEvent()
96 | o.full_symbol = self.symbols[0]
97 | o.order_type = OrderType.MARKET
98 | o.order_size = 1 - self.current_pos
99 | _logger.info(
100 | f"DoubleMovingAverageCrossStrategy long order placed, on tick time {k.timestamp}, current size {self.current_pos}, order size {o.order_size}, ma_fast {ma_fast}, ma_slow {ma_slow}"
101 | )
102 | self.current_pos = 1
103 | self.place_order(o)
104 | elif ma_fast < ma_slow:
105 | if self.current_pos >= 0:
106 | o = OrderEvent()
107 | o.full_symbol = self.symbols[0]
108 | o.order_type = OrderType.MARKET
109 | o.order_size = -1 - self.current_pos
110 | _logger.info(
111 | f"DoubleMovingAverageCrossStrategy short order placed, on tick time {k.timestamp}, current size {self.current_pos}, order size {o.order_size}, ma_fast {ma_fast}, ma_slow {ma_slow}"
112 | )
113 | self.current_pos = -1
114 | self.place_order(o)
115 |
--------------------------------------------------------------------------------
/examples/strategy/dual_thrust.csv:
--------------------------------------------------------------------------------
1 | ,price,volume
2 | 2020-01-01 00:00:00,0,0
3 | 2020-01-01 00:01:00,1,1
4 | 2020-01-01 00:02:00,2,2
5 | 2020-01-01 00:03:00,3,3
6 | 2020-01-01 00:04:00,4,4
7 | 2020-01-01 00:05:00,5,5
8 | 2020-01-01 00:06:00,6,6
9 | 2020-01-01 00:07:00,7,7
10 | 2020-01-01 00:08:00,8,8
11 | 2020-01-01 00:09:00,9,9
12 | 2020-01-01 00:10:00,10,10
13 | 2020-01-01 00:11:00,11,11
14 | 2020-01-01 00:12:00,12,12
15 | 2020-01-01 00:13:00,13,13
16 | 2020-01-01 00:14:00,14,14
17 | 2020-01-01 00:15:00,15,15
18 | 2020-01-01 00:16:00,16,16
19 | 2020-01-01 00:17:00,17,17
20 | 2020-01-01 00:18:00,18,18
21 | 2020-01-01 00:19:00,19,19
22 | 2020-01-01 00:20:00,20,20
23 | 2020-01-01 00:21:00,21,21
24 | 2020-01-01 00:22:00,22,22
25 | 2020-01-01 00:23:00,23,23
26 | 2020-01-01 00:24:00,24,24
27 | 2020-01-01 00:25:00,25,25
28 | 2020-01-01 00:26:00,26,26
29 | 2020-01-01 00:27:00,27,27
30 | 2020-01-01 00:28:00,28,28
31 | 2020-01-01 00:29:00,29,29
32 | 2020-01-01 00:30:00,30,30
33 | 2020-01-01 00:31:00,31,31
34 | 2020-01-01 00:32:00,32,32
35 | 2020-01-01 00:33:00,33,33
36 | 2020-01-01 00:34:00,34,34
37 | 2020-01-01 00:35:00,35,35
38 | 2020-01-01 00:36:00,36,36
39 | 2020-01-01 00:37:00,37,37
40 | 2020-01-01 00:38:00,38,38
41 | 2020-01-01 00:39:00,39,39
42 | 2020-01-01 00:40:00,40,40
43 | 2020-01-01 00:41:00,41,41
44 | 2020-01-01 00:42:00,42,42
45 | 2020-01-01 00:43:00,43,43
46 | 2020-01-01 00:44:00,44,44
47 | 2020-01-01 00:45:00,45,45
48 | 2020-01-01 00:46:00,46,46
49 | 2020-01-01 00:47:00,47,47
50 | 2020-01-01 00:48:00,48,48
51 | 2020-01-01 00:49:00,49,49
52 | 2020-01-01 00:50:00,50,50
53 | 2020-01-01 00:51:00,51,51
54 | 2020-01-01 00:52:00,52,52
55 | 2020-01-01 00:53:00,53,53
56 | 2020-01-01 00:54:00,54,54
57 | 2020-01-01 00:55:00,55,55
58 | 2020-01-01 00:56:00,56,56
59 | 2020-01-01 00:57:00,57,57
60 | 2020-01-01 00:58:00,58,58
61 | 2020-01-01 00:59:00,59,59
62 | 2020-01-01 01:00:00,60,60
63 | 2020-01-01 01:01:00,61,61
64 | 2020-01-01 01:02:00,62,62
65 | 2020-01-01 01:03:00,63,63
66 | 2020-01-01 01:04:00,64,64
67 | 2020-01-01 01:05:00,65,65
68 | 2020-01-01 01:06:00,66,66
69 | 2020-01-01 01:07:00,67,67
70 | 2020-01-01 01:08:00,68,68
71 | 2020-01-01 01:09:00,69,69
72 | 2020-01-01 01:10:00,70,70
73 | 2020-01-01 01:11:00,71,71
74 | 2020-01-01 01:12:00,72,72
75 | 2020-01-01 01:13:00,73,73
76 | 2020-01-01 01:14:00,74,74
77 | 2020-01-01 01:15:00,75,75
78 | 2020-01-01 01:16:00,76,76
79 | 2020-01-01 01:17:00,77,77
80 | 2020-01-01 01:18:00,78,78
81 | 2020-01-01 01:19:00,79,79
82 | 2020-01-01 01:20:00,80,80
83 | 2020-01-01 01:21:00,81,81
84 | 2020-01-01 01:22:00,82,82
85 | 2020-01-01 01:23:00,83,83
86 | 2020-01-01 01:24:00,84,84
87 | 2020-01-01 01:25:00,85,85
88 | 2020-01-01 01:26:00,86,86
89 | 2020-01-01 01:27:00,87,87
90 | 2020-01-01 01:28:00,88,88
91 | 2020-01-01 01:29:00,89,89
92 | 2020-01-01 01:30:00,90,90
93 | 2020-01-01 01:31:00,91,91
94 | 2020-01-01 01:32:00,92,92
95 | 2020-01-01 01:33:00,93,93
96 | 2020-01-01 01:34:00,94,94
97 | 2020-01-01 01:35:00,95,95
98 | 2020-01-01 01:36:00,96,96
99 | 2020-01-01 01:37:00,97,97
100 | 2020-01-01 01:38:00,98,98
101 | 2020-01-01 01:39:00,99,99
102 |
--------------------------------------------------------------------------------
/examples/strategy/dual_thrust_strategy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import logging
4 |
5 | import pandas as pd
6 |
7 | from quanttrader.data.tick_event import TickType
8 | from quanttrader.strategy.strategy_base import StrategyBase
9 |
10 | _logger = logging.getLogger("qtlive")
11 |
12 |
13 | class DualThrustStrategy(StrategyBase):
14 | """
15 | Dual thrust
16 | """
17 |
18 | def __init__(self):
19 | super(DualThrustStrategy, self).__init__()
20 | self.k1 = 0.7
21 | self.k2 = 0.7
22 | df = pd.read_csv("./strategy/dual_thrust.csv", header=0, index_col=0)
23 | df.index = pd.to_datetime(df.index)
24 | df1 = df.resample("5T").agg({"price": "ohlc", "volume": "sum"})
25 | df1.columns = df1.columns.get_level_values(1)
26 | _ = df1.resample("10T").agg(
27 | {
28 | "open": "first",
29 | "high": "max",
30 | "low": "min",
31 | "close": "last",
32 | "volume": "sum",
33 | }
34 | )
35 |
36 | _logger.info("DualThrustStrategy initiated")
37 |
38 | def on_tick(self, tick_event):
39 | k = tick_event
40 | super().on_tick(k) # extra mtm calc
41 |
42 | if k.tick_type != TickType.TRADE:
43 | return
44 |
45 | print(k)
46 |
--------------------------------------------------------------------------------
/examples/strategy/order_per_interval_strategy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import logging
4 |
5 | from quanttrader.data.tick_event import TickType
6 | from quanttrader.order.order_event import OrderEvent
7 | from quanttrader.order.order_type import OrderType
8 | from quanttrader.strategy.strategy_base import StrategyBase
9 |
10 | _logger = logging.getLogger("qtlive")
11 |
12 |
13 | class OrderPerIntervalStrategy(StrategyBase):
14 | """
15 | buy on the first tick then hold to the end
16 | """
17 |
18 | def __init__(self):
19 | super(OrderPerIntervalStrategy, self).__init__()
20 | self.ticks = 0
21 | self.tick_trigger_threshold = 2000
22 | self.direction = 1
23 | _logger.info("OrderPerIntervalStrategy initiated")
24 |
25 | def on_tick(self, tick_event):
26 | k = tick_event
27 | super().on_tick(k) # extra mtm calc
28 |
29 | if k.tick_type != TickType.TRADE:
30 | print(k, f"{self.ticks}/{self.tick_trigger_threshold}")
31 | if self.ticks > self.tick_trigger_threshold:
32 | o1 = OrderEvent()
33 | o1.full_symbol = self.symbols[0]
34 | o1.order_type = OrderType.MARKET
35 | o1.order_size = self.direction
36 |
37 | o2 = OrderEvent()
38 | o2.full_symbol = self.symbols[1]
39 | o2.order_type = OrderType.MARKET
40 | o2.order_size = self.direction
41 |
42 | self.direction = 1 if self.direction == -1 else -1
43 | _logger.info(f"OrderPerIntervalStrategy order placed on ticks {self.ticks}")
44 | self.place_order(o1)
45 | self.place_order(o2)
46 | self.ticks = 0
47 | else:
48 | self.ticks += 1
49 |
--------------------------------------------------------------------------------
/mypy.ini:
--------------------------------------------------------------------------------
1 | [mypy]
2 | ignore_missing_imports = True
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools>=61.0"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [project]
6 | name = "quanttrader"
7 | version = "0.6.0"
8 | description = "quanttrader backtest and live trading library"
9 | readme = "README.md"
10 | authors = [
11 | {name = "Letian Wang", email = "letian.zj@gmail.com"}
12 | ]
13 | maintainers = [
14 | {name = "Letian Wang", email = "letian.zj@gmail.com"}
15 | ]
16 | classifiers = [
17 |
18 | ]
19 | license = { file = "LICENSE" }
20 | dependencies = [
21 |
22 | ]
23 |
24 | [project.optional-dependencies]
25 | dev = [
26 | "coverage", # testing
27 | "mypy", # linting
28 | "pytest", # testing
29 | "ruff" # linting
30 | ]
31 |
32 | [project.urls]
33 |
34 | bugs = "https://github.com/letianzj/quanttrader/issues"
35 | changelog = "https://github.com/letianzj/quanttrader/blob/master/changelog.md"
36 | homepage = "https://github.com/letianzj/quanttrader"
37 |
38 | [tool.setuptools]
39 | package-dir = {"" = "."}
40 |
41 | [tool.setuptools.package-data]
42 | "*" = ["*.*"]
43 |
44 | [tool.poetry]
45 | name = "quanttrader"
46 | version = "0.6.0"
47 | description = "quant trader python"
48 | authors = ["Letian Wang "]
49 |
50 | [tool.poetry.dependencies]
51 | python = "^3.12"
52 | matplotlib = "^3.8.4"
53 | numpy = "^1.26.4"
54 | pandas = "^2.2.2"
55 | psutil = "^5.9.0"
56 | pytz = "^2024.1"
57 | scikit-learn = "^1.5.0"
58 | scipy = "^1.13.1"
59 | seaborn = "^0.12.2"
60 | PyYAML = "^6.0.1"
61 | pyqt5 = "=5.15.10"
62 | pyqt5-qt5 = "=5.15.2"
63 | qdarkstyle = "=2.8"
64 | ibapi = "^9.81.1"
65 | ta = "^0.11.0"
66 | gym = "^0.26.2"
67 |
68 | [tool.poetry.dev-dependencies]
69 | black = "^24.4.2"
70 | isort = "^5.13.2"
71 | pylint = "^3.2.3"
72 | pytest = "^7.4.4"
73 |
74 | [tool.pylint]
75 | disable = ["missing-docstring", "W1203", "fixme"]
76 | max-line-length = 300
77 |
78 | [tool.isort]
79 | profile = "black"
80 |
81 | # Mypy
82 | # ----
83 |
84 | [tool.mypy]
85 | files = "."
86 | ignore_missing_imports = true
87 |
88 | # Use strict defaults
89 | strict = true
90 | warn_unreachable = true
91 | warn_no_return = true
92 |
93 | [[tool.mypy.overrides]]
94 | # Don't require test functions to include types
95 | module = "tests.*"
96 | allow_untyped_defs = true
97 | disable_error_code = "attr-defined"
98 |
99 |
--------------------------------------------------------------------------------
/quanttrader/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # https://docs.python-guide.org/writing/logging/
4 | import logging
5 |
6 | from .account import *
7 | from .backtest_engine import *
8 | from .brokerage import *
9 | from .data import *
10 | from .event import *
11 | from .gui import *
12 | from .log import *
13 | from .order import *
14 | from .performance import *
15 | from .position import *
16 | from .risk import *
17 | from .strategy import *
18 | from .util import *
19 | from .version import VERSION as __version__
20 |
21 | logging.getLogger(__name__).addHandler(logging.NullHandler())
22 |
--------------------------------------------------------------------------------
/quanttrader/account/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .account_event import *
4 | from .account_manager import *
5 |
--------------------------------------------------------------------------------
/quanttrader/account/account_event.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | import pandas as pd
5 |
6 | from ..event.event import Event, EventType
7 |
8 | __all__ = ["AccountEvent"]
9 |
10 |
11 | class AccountEvent(Event):
12 | """
13 | also serve as account
14 | """
15 |
16 | def __init__(self) -> None:
17 | self.event_type: EventType = EventType.ACCOUNT
18 | self.account_id: str = ""
19 | self.preday_balance: float = 0.0
20 | self.balance: float = 0.0
21 | self.available: float = 0.0
22 | self.commission: float = 0.0
23 | self.margin: float = 0.0
24 | self.closed_pnl: float = 0.0
25 | self.open_pnl: float = 0.0
26 | self.brokerage: str = ""
27 | self.timestamp: pd.Timestamp | str = ""
28 |
--------------------------------------------------------------------------------
/quanttrader/account/account_manager.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from .account_event import AccountEvent
5 |
6 | __all__ = ["AccountManager"]
7 |
8 |
9 | class AccountManager(object):
10 | def __init__(self, account_id: str) -> None:
11 | self._account_id: str = account_id
12 | self._account_dict: dict[str, AccountEvent] = {} # account id ==> account
13 | self.reset()
14 |
15 | def reset(self) -> None:
16 | self._account_dict.clear()
17 | # initialize accounts from server_config.yaml
18 | account = AccountEvent()
19 | account.account_id = self._account_id
20 | account.brokerage = "ib"
21 | self._account_dict[self._account_id] = account
22 |
23 | def on_account(self, account_event: AccountEvent) -> None:
24 | if account_event.account_id in self._account_dict:
25 | self._account_dict[account_event.account_id].preday_balance = (
26 | account_event.preday_balance
27 | )
28 | self._account_dict[account_event.account_id].balance = account_event.balance
29 | self._account_dict[account_event.account_id].available = (
30 | account_event.available
31 | )
32 | self._account_dict[account_event.account_id].commission = (
33 | account_event.commission
34 | )
35 | self._account_dict[account_event.account_id].margin = account_event.margin
36 | self._account_dict[account_event.account_id].closed_pnl = (
37 | account_event.closed_pnl
38 | )
39 | self._account_dict[account_event.account_id].open_pnl = (
40 | account_event.open_pnl
41 | )
42 | self._account_dict[account_event.account_id].timestamp = (
43 | account_event.timestamp
44 | )
45 | else:
46 | self._account_dict[account_event.account_id] = account_event
47 |
--------------------------------------------------------------------------------
/quanttrader/brokerage/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .backtest_brokerage import *
4 | from .ib_brokerage import *
5 |
--------------------------------------------------------------------------------
/quanttrader/brokerage/brokerage_base.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from abc import abstractmethod
4 |
5 | from ..order.order_event import OrderEvent
6 |
7 |
8 | class BrokerageBase(object):
9 | """
10 | Brokerage base class
11 | """
12 |
13 | def __init__(self) -> None:
14 | self.orderid: int = 0 # next/available orderid
15 | self.market_data_subscription_reverse_dict: dict[str, int] = {} # sym ==> reqId
16 |
17 | @abstractmethod
18 | def place_order(self, order_event: OrderEvent) -> None:
19 | """
20 | place order
21 | """
22 | raise NotImplementedError("Implement this in your derived class")
23 |
24 | @abstractmethod
25 | def cancel_order(self, order_id: int) -> None:
26 | """
27 | cancel order
28 | """
29 | raise NotImplementedError("Implement this in your derived class")
30 |
31 | @abstractmethod
32 | def next_order_id(self) -> int:
33 | """
34 | request next order id
35 | """
36 | raise NotImplementedError("Implement this in your derived class")
37 |
38 | @abstractmethod
39 | def _calculate_commission(
40 | self, full_symbol: str, fill_price: float, fill_size: int
41 | ) -> float:
42 | """
43 | calc commission
44 | """
45 | raise NotImplementedError("Implement this in your derived class")
46 |
--------------------------------------------------------------------------------
/quanttrader/data/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .backtest_data_feed import *
4 | from .bar_event import *
5 | from .data_board import *
6 | from .live_data_feed import *
7 | from .tick_event import *
8 |
--------------------------------------------------------------------------------
/quanttrader/data/backtest_data_feed.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from typing import Iterator
4 |
5 | import pandas as pd
6 |
7 | from .data_feed_base import DataFeedBase
8 | from .tick_event import TickEvent
9 |
10 | __all__ = ["BacktestDataFeed"]
11 |
12 |
13 | class BacktestDataFeed(DataFeedBase):
14 | """
15 | BacktestDataFeed uses PLACEHOLDER to stream_next;
16 | actual data comes from data_board.get_hist_price
17 | This is an easy way to handle multiple sources
18 | """
19 |
20 | def __init__(
21 | self,
22 | start_date: pd.Timestamp | None = None,
23 | end_date: pd.Timestamp | None = None,
24 | ) -> None:
25 | self._end_date: pd.Timestamp = end_date
26 | self._start_date: pd.Timestamp = start_date
27 | self._data_stream: pd.Index = None
28 | self._data_stream_iter: Iterator[pd.Timestamp] = iter([])
29 |
30 | def set_data_source(self, data: pd.DataFrame) -> None:
31 | if self._data_stream is None:
32 | self._data_stream = data.index
33 | else:
34 | self._data_stream = self._data_stream.join(
35 | data.index, how="outer", sort=True
36 | )
37 |
38 | def subscribe_market_data(self, symbols: str | list[str]) -> None:
39 | _ = symbols
40 | if self._start_date:
41 | if self._end_date:
42 | self._data_stream = self._data_stream[
43 | (self._data_stream >= self._start_date)
44 | & (self._data_stream <= self._end_date)
45 | ]
46 | else:
47 | self._data_stream = self._data_stream[
48 | self._data_stream >= self._start_date
49 | ]
50 |
51 | self._data_stream_iter = self._data_stream.__iter__()
52 |
53 | def unsubscribe_market_data(self, symbols: str | list[str]) -> None:
54 | _ = symbols
55 |
56 | def stream_next(self) -> TickEvent:
57 | """
58 | Place the next TickEvent into the event queue.
59 | """
60 | index = next(self._data_stream_iter)
61 |
62 | t = TickEvent()
63 | t.full_symbol = "PLACEHOLDER" # place holders
64 | t.timestamp = index
65 |
66 | return t
67 |
--------------------------------------------------------------------------------
/quanttrader/data/bar_event.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import pandas as pd
4 |
5 | from ..event.event import Event, EventType
6 |
7 | __all__ = ["BarEvent"]
8 |
9 |
10 | class BarEvent(Event):
11 | """
12 | Bar event, aggregated from TickEvent
13 | """
14 |
15 | def __init__(self) -> None:
16 | """
17 | Initialises bar
18 | """
19 | self.event_type: EventType = EventType.BAR
20 | self.bar_start_time: pd.Timestamp = pd.Timestamp("1970-01-01", tz="UTC")
21 | self.interval: int = 86400 # 1day in secs = 24hrs * 60min * 60sec
22 | self.full_symbol: str = ""
23 | self.open_price: float = 0.0
24 | self.high_price: float = 0.0
25 | self.low_price: float = 0.0
26 | self.close_price: float = 0.0
27 | self.adj_close_price: float = 0.0
28 | self.volume: int = 0
29 |
30 | def bar_end_time(self) -> pd.Timestamp:
31 | # To be consistent with (daily) bar backtest, bar_end_time is set to be bar_start_time
32 | return self.bar_start_time
33 | # return self.bar_start_time + pd.Timedelta(seconds=self.interval)
34 |
35 | def __str__(self) -> str:
36 | return (
37 | "Time: %s, Symbol: %s, Interval: %s, "
38 | "Open: %s, High: %s, Low: %s, Close: %s, "
39 | "Adj Close: %s, Volume: %s"
40 | % (
41 | str(self.bar_start_time),
42 | str(self.full_symbol),
43 | str(self.interval),
44 | str(self.open_price),
45 | str(self.high_price),
46 | str(self.low_price),
47 | str(self.close_price),
48 | str(self.adj_close_price),
49 | str(self.volume),
50 | )
51 | )
52 |
--------------------------------------------------------------------------------
/quanttrader/data/data_board.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import pandas as pd
4 |
5 | from .tick_event import TickEvent
6 |
7 | __all__ = ["DataBoard"]
8 |
9 |
10 | class DataBoard(object):
11 | """
12 | Data tracker that holds current market data info
13 | """
14 |
15 | def __init__(self) -> None:
16 | self._hist_data_dict: dict[str, pd.DataFrame] = {}
17 | self._current_data_dict: dict[str, TickEvent] = {}
18 | self._current_time: pd.Timestamp | None = None
19 | self._PLACEHOLDER: str = "PLACEHOLDER"
20 | self._data_index: pd.Index = None
21 |
22 | def initialize_hist_data(self, data_key: str, data: pd.DataFrame) -> None:
23 | self._hist_data_dict[data_key] = data
24 |
25 | def on_tick(self, tick: TickEvent) -> None:
26 | self._current_data_dict[tick.full_symbol] = tick
27 | self._current_time = tick.timestamp
28 |
29 | def get_last_price(self, symbol: str) -> float:
30 | """
31 | Returns last price for a given ticker
32 | because self._current_time has not been updated by current tick
33 | """
34 | return self.get_current_price(symbol, self._current_time)
35 |
36 | def get_current_price(self, symbol: str, timestamp: pd.Timestamp) -> float:
37 | """
38 | Returns the most recent price for a given ticker
39 | based on current timestamp updated outside of data_board
40 | """
41 | if symbol in self._current_data_dict.keys():
42 | return self._current_data_dict[symbol].price
43 | elif symbol in self._hist_data_dict.keys():
44 | return self._hist_data_dict[symbol].loc[timestamp, "Close"] # type: ignore
45 | elif (
46 | symbol[:-5] in self._hist_data_dict.keys()
47 | ): # FUT root symbol e.g. CL, -5 assumes CLZ2020
48 | # column series up to timestamp inclusive
49 | return self._hist_data_dict[symbol[:-5]].loc[timestamp, symbol] # type: ignore
50 | else:
51 | return 0.0
52 |
53 | def get_last_timestamp(self, symbol: str) -> pd.Timestamp:
54 | """
55 | Returns the most recent timestamp for a given ticker
56 | """
57 | if symbol in self._current_data_dict.keys():
58 | return self._current_data_dict[symbol].timestamp
59 | elif self._PLACEHOLDER in self._current_data_dict:
60 | return self._current_data_dict[self._PLACEHOLDER].timestamp
61 | else:
62 | return self._current_time
63 |
64 | def get_current_timestamp(self) -> pd.Timestamp:
65 | return self._current_time
66 |
67 | def get_hist_price(self, symbol: str, timestamp: pd.Timestamp) -> pd.DataFrame:
68 | if symbol in self._hist_data_dict.keys():
69 | # up to timestamp inclusive
70 | return self._hist_data_dict[symbol][:timestamp] # type: ignore
71 | elif symbol[:-5] in self._hist_data_dict.keys(): # FUT root symbol e.g. CL
72 | # column series up to timestamp inclusive
73 | return self._hist_data_dict[symbol[:-5]][symbol][:timestamp] # type: ignore
74 | else:
75 | raise ValueError(symbol)
76 |
77 | def get_hist_sym_time_index(self, symbol: str) -> pd.Index | None:
78 | """
79 | retrieve historical calendar for a symbol
80 | this is not look forwward
81 | """
82 | if symbol in self._hist_data_dict.keys():
83 | return self._hist_data_dict[symbol].index
84 | elif symbol[:-5] in self._hist_data_dict.keys(): # FUT root symbol e.g. CL
85 | return self._hist_data_dict[symbol[:-5]].index
86 | else:
87 | return None
88 |
89 | def get_hist_time_index(self) -> pd.Index:
90 | """
91 | retrieve historical calendar
92 | this is not look forwward
93 | """
94 | if self._data_index is None:
95 | for _, v in self._hist_data_dict.items():
96 | self._data_index = (
97 | self._data_index.join(v.index, how="outer", sort=True) # type: ignore
98 | if self._data_index is not None
99 | else v.index.copy()
100 | )
101 | return self._data_index
102 |
--------------------------------------------------------------------------------
/quanttrader/data/data_feed_base.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from abc import ABCMeta, abstractmethod
4 |
5 | from ..event.event import Event
6 |
7 |
8 | class DataFeedBase(metaclass=ABCMeta):
9 | """
10 | DateFeed baae class
11 | """
12 |
13 | @abstractmethod
14 | def subscribe_market_data(self, symbols: str | list[str]) -> None:
15 | """subscribe to market data"""
16 |
17 | @abstractmethod
18 | def unsubscribe_market_data(self, symbols: str | list[str]) -> None:
19 | """unsubscribe market data"""
20 |
21 | @abstractmethod
22 | def stream_next(self) -> Event:
23 | """stream next data event"""
24 |
--------------------------------------------------------------------------------
/quanttrader/data/tick_event.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from datetime import datetime
4 | from enum import Enum
5 |
6 | import pandas as pd
7 |
8 | from ..event.event import Event, EventType
9 |
10 | __all__ = ["TickType", "TickEvent"]
11 |
12 |
13 | class TickType(Enum):
14 | """
15 | Unlike IB, it does not have tick_size, e.g., TickTypeEnum.BID_SIZE
16 | """
17 |
18 | TRADE = 0
19 | BID = 1
20 | ASK = 2
21 | FULL = 3
22 |
23 |
24 | class TickEvent(Event):
25 | """
26 | Tick event
27 | """
28 |
29 | def __init__(self) -> None:
30 | """
31 | Initialises Tick
32 | """
33 | self.event_type: EventType = EventType.TICK
34 | self.tick_type: TickType = TickType.TRADE
35 | self.timestamp: pd.Timestamp = pd.Timestamp("1970-01-01", tz="UTC")
36 | self.full_symbol: str = ""
37 | self.price: float = 0.0
38 | self.size: int = 0
39 | self.depth: int = 1
40 | self.bid_price_L1: float = 0.0
41 | self.bid_size_L1: int = 0
42 | self.ask_price_L1: float = 0.0
43 | self.ask_size_L1: int = 0
44 | self.open_interest: int = 0
45 | self.open: float = 0.0
46 | self.high: float = 0.0
47 | self.low: float = 0.0
48 | self.pre_close: float = 0.0
49 | self.upper_limit_price: float = 0.0
50 | self.lower_limit_price: float = 0.0
51 |
52 | def __str__(self) -> str:
53 | return "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s" % (
54 | str(self.timestamp.strftime("%H:%M:%S.%f")),
55 | str(datetime.now().strftime("%H:%M:%S.%f")),
56 | str(self.full_symbol),
57 | (self.tick_type),
58 | str(self.bid_size_L1),
59 | str(self.bid_price_L1),
60 | str(self.ask_price_L1),
61 | str(self.ask_size_L1),
62 | str(self.price),
63 | str(self.size),
64 | )
65 |
--------------------------------------------------------------------------------
/quanttrader/event/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .backtest_event_engine import *
4 | from .event import *
5 | from .live_event_engine import *
6 |
--------------------------------------------------------------------------------
/quanttrader/event/backtest_event_engine.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # from multiprocessing import Queue
4 | import logging
5 | from collections import defaultdict
6 | from queue import Empty, Queue
7 | from typing import Any, Callable
8 |
9 | from ..data.backtest_data_feed import BacktestDataFeed
10 | from .event import Event, EventType
11 |
12 | _logger = logging.getLogger(__name__)
13 |
14 |
15 | __all__ = ["BacktestEventEngine"]
16 |
17 |
18 | class BacktestEventEngine(object):
19 | """
20 | Event queue + a while loop to dispatch events
21 | """
22 |
23 | def __init__(self, datafeed: BacktestDataFeed) -> None:
24 | """
25 | Initialize handler function list
26 | """
27 | # if the data feed is active
28 | self._active = True
29 |
30 | # event queue
31 | self._queue = Queue() # type: ignore
32 |
33 | # pull from backtest data feed
34 | self._datafeed = datafeed
35 |
36 | # event handlers list, dict: specific event key --> Callable[Event]
37 | self._handlers: defaultdict[EventType, list[Callable[[Any], None]]] = (
38 | defaultdict(list)
39 | )
40 |
41 | # ------------------------------------ public functions -----------------------------#
42 | def run(self, nSteps: int = -1) -> None:
43 | """
44 | run backtest,
45 | if nSteps = -1, run to the end; else run nSteps
46 | """
47 | _logger.info("Running Backtest...")
48 | nstep = 0
49 | while self._active:
50 | try:
51 | event = self._queue.get(False)
52 | except Empty: # throw good exception
53 | if (nSteps == -1) or (nstep < nSteps):
54 | try:
55 | event = self._datafeed.stream_next()
56 | self._queue.put(event)
57 | nstep += 1
58 | except:
59 | # stop if not able to next event
60 | self._active = False
61 | else:
62 | break
63 | else: # not empty
64 | try:
65 | # call event handlers
66 | if event.event_type in self._handlers:
67 | [handler(event) for handler in self._handlers[event.event_type]]
68 |
69 | except Exception as e:
70 | logging.error("Error {0}".format(str(e.args[0])).encode("utf-8"))
71 |
72 | def put(self, event: Event) -> None:
73 | """
74 | put event in the queue; call from outside
75 | """
76 | self._queue.put(event)
77 |
78 | def register_handler(
79 | self, type_: EventType, handler: Callable[[Any], None]
80 | ) -> None:
81 | """
82 | register handler/subscriber
83 | """
84 | handler_list = self._handlers[type_]
85 |
86 | if handler not in handler_list:
87 | handler_list.append(handler)
88 |
89 | def unregister_handler(
90 | self, type_: EventType, handler: Callable[[Any], None]
91 | ) -> None:
92 | """
93 | unregister handler/subscriber
94 | """
95 | handler_list = self._handlers[type_]
96 |
97 | if handler in handler_list:
98 | handler_list.remove(handler)
99 |
100 | if not handler_list:
101 | del self._handlers[type_]
102 |
103 | # -------------------------------- end of public functions -----------------------------#
104 |
--------------------------------------------------------------------------------
/quanttrader/event/event.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from enum import Enum
4 |
5 | import pandas as pd
6 |
7 | __all__ = ["EventType", "Event", "LogEvent"]
8 |
9 |
10 | class EventType(Enum):
11 | TICK = 0
12 | BAR = 1
13 | ORDER = 2
14 | FILL = 3
15 | CANCEL = 4
16 | ORDERSTATUS = 5
17 | ACCOUNT = 6
18 | POSITION = 7
19 | CONTRACT = 8
20 | HISTORICAL = 9
21 | TIMER = 10
22 | LOG = 11
23 |
24 |
25 | class Event(object):
26 | """
27 | Base Event class for event-driven system
28 | """
29 |
30 | @property
31 | def typename(self) -> str:
32 | return self.__class__.__name__
33 |
34 |
35 | class LogEvent(Event):
36 | """
37 | Log event:
38 | TODO seperate ErrorEvent
39 | """
40 |
41 | def __init__(self) -> None:
42 | self.event_type: EventType = EventType.LOG
43 | self.timestamp: pd.Timestamp = None
44 | self.content: str = ""
45 |
--------------------------------------------------------------------------------
/quanttrader/event/live_event_engine.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import logging
4 | from collections import defaultdict
5 | from queue import Empty, Queue
6 | from threading import Thread
7 | from typing import Any, Callable
8 |
9 | from ..event.event import Event, EventType
10 |
11 | _logger = logging.getLogger(__name__)
12 |
13 |
14 | __all__ = ["LiveEventEngine"]
15 |
16 |
17 | class LiveEventEngine(object):
18 | """
19 | Event queue + a thread to dispatch events
20 | """
21 |
22 | def __init__(self) -> None:
23 | """
24 | Initialize dispatcher thread and handler function list
25 | """
26 | # if the dispatcher is active
27 | self._active = False
28 |
29 | # event queue
30 | self._queue = Queue() # type: ignore
31 |
32 | # dispatcher thread
33 | self._thread = Thread(target=self._run)
34 |
35 | # event handlers list, dict: specific event key --> Callable[Event]
36 | self._handlers: defaultdict[EventType, list[Callable[[Any], None]]] = (
37 | defaultdict(list)
38 | )
39 |
40 | # ------------------------------- private functions ---------------------------#
41 | def _run(self) -> None:
42 | """
43 | run dispatcher
44 | """
45 | while self._active:
46 | try:
47 | event = self._queue.get(block=True, timeout=1)
48 | # call event handlers
49 | if event.event_type in self._handlers:
50 | [handler(event) for handler in self._handlers[event.event_type]]
51 | except Empty:
52 | pass
53 | except Exception as e:
54 | _logger.error(f"Event {event.event_type}, Error {str(e)}")
55 |
56 | # ----------------------------- end of private functions ---------------------------#
57 |
58 | # ------------------------------------ public functions -----------------------------#
59 | def start(self, timer: bool = True) -> None:
60 | """
61 | start the dispatcher thread
62 | """
63 | self._active = True
64 | self._thread.start()
65 |
66 | def stop(self) -> None:
67 | """
68 | stop the dispatcher thread
69 | """
70 | self._active = False
71 | self._thread.join()
72 |
73 | def put(self, event: Event) -> None:
74 | """
75 | put event in the queue; call from outside
76 | """
77 | self._queue.put(event)
78 |
79 | def register_handler(
80 | self, type_: EventType, handler: Callable[[Any], None]
81 | ) -> None:
82 | """
83 | register handler/subscriber
84 | """
85 | handler_list = self._handlers[type_]
86 |
87 | if handler not in handler_list:
88 | handler_list.append(handler)
89 |
90 | def unregister_handler(
91 | self, type_: EventType, handler: Callable[[Any], None]
92 | ) -> None:
93 | """
94 | unregister handler/subscriber
95 | """
96 | handler_list = self._handlers[type_]
97 |
98 | if handler in handler_list:
99 | handler_list.remove(handler)
100 |
101 | if not handler_list:
102 | del self._handlers[type_]
103 |
104 | # -------------------------------- end of public functions -----------------------------#
105 |
--------------------------------------------------------------------------------
/quanttrader/gui/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .ui_account_window import *
4 | from .ui_fill_window import *
5 | from .ui_log_window import *
6 | from .ui_main_window import *
7 | from .ui_order_window import *
8 | from .ui_position_menu import *
9 | from .ui_position_window import *
10 | from .ui_risk_menu import *
11 | from .ui_strategy_window import *
12 | from .ui_trade_menu import *
13 |
--------------------------------------------------------------------------------
/quanttrader/gui/image/logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/quanttrader/gui/image/logo.ico
--------------------------------------------------------------------------------
/quanttrader/gui/ui_account_window.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import logging
4 | from typing import Any
5 |
6 | from PyQt5 import QtCore, QtWidgets
7 |
8 | from ..account.account_event import AccountEvent
9 | from ..account.account_manager import AccountManager
10 |
11 | _logger = logging.getLogger(__name__)
12 |
13 | __all__ = ["AccountWindow"]
14 |
15 |
16 | class AccountWindow(QtWidgets.QTableWidget):
17 | account_signal = QtCore.pyqtSignal(type(AccountEvent()))
18 |
19 | def __init__(self, account_manager: AccountManager, parent: Any = None) -> None:
20 | super(AccountWindow, self).__init__(parent)
21 |
22 | self.header = [
23 | "AccountID",
24 | "Net",
25 | "Available",
26 | "Margin",
27 | "Closed_PnL",
28 | "Open_PnL",
29 | "Brokerage",
30 | "Time",
31 | ]
32 |
33 | self.init_table()
34 | self._account_manager = account_manager
35 | self._account_ids: list[str] = []
36 | self.account_signal.connect(self.update_table)
37 |
38 | def init_table(self) -> None:
39 | col = len(self.header)
40 | self.setColumnCount(col)
41 |
42 | self.setHorizontalHeaderLabels(self.header)
43 | self.setEditTriggers(self.NoEditTriggers)
44 | _vh = self.verticalHeader()
45 | if _vh:
46 | _vh.setVisible(False)
47 | self.setAlternatingRowColors(True)
48 | self.setSortingEnabled(False)
49 |
50 | def update_table(self, account_event: AccountEvent) -> None:
51 | """
52 | Only add row
53 | """
54 | self._account_manager.on_account(account_event)
55 | _logger.info(f"account id recorded: {account_event.account_id}")
56 |
57 | if account_event.account_id in self._account_ids:
58 | row = self._account_ids.index(account_event.account_id)
59 | self.setItem(row, 1, QtWidgets.QTableWidgetItem(str(account_event.balance)))
60 | self.setItem(
61 | row, 2, QtWidgets.QTableWidgetItem(str(account_event.available))
62 | )
63 | self.setItem(row, 3, QtWidgets.QTableWidgetItem(str(account_event.margin)))
64 | self.setItem(
65 | row,
66 | 4,
67 | QtWidgets.QTableWidgetItem(str(account_event.closed_pnl)),
68 | )
69 | self.setItem(
70 | row, 5, QtWidgets.QTableWidgetItem(str(account_event.open_pnl))
71 | )
72 | self.setItem(row, 6, QtWidgets.QTableWidgetItem(account_event.brokerage))
73 | self.setItem(row, 7, QtWidgets.QTableWidgetItem(account_event.timestamp))
74 |
75 | else:
76 | self._account_ids.insert(0, account_event.account_id)
77 | self.insertRow(0)
78 | self.setItem(0, 0, QtWidgets.QTableWidgetItem(account_event.account_id))
79 | self.setItem(0, 1, QtWidgets.QTableWidgetItem(str(account_event.balance)))
80 | self.setItem(0, 2, QtWidgets.QTableWidgetItem(str(account_event.available)))
81 | self.setItem(0, 3, QtWidgets.QTableWidgetItem(str(account_event.margin)))
82 | self.setItem(
83 | 0, 4, QtWidgets.QTableWidgetItem(str(account_event.closed_pnl))
84 | )
85 | self.setItem(0, 5, QtWidgets.QTableWidgetItem(str(account_event.open_pnl)))
86 | self.setItem(0, 6, QtWidgets.QTableWidgetItem(account_event.brokerage))
87 | self.setItem(0, 7, QtWidgets.QTableWidgetItem(account_event.timestamp))
88 |
--------------------------------------------------------------------------------
/quanttrader/gui/ui_fill_window.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import logging
4 | from typing import Any
5 |
6 | from PyQt5 import QtCore, QtWidgets
7 |
8 | from ..order.fill_event import FillEvent
9 |
10 | _logger = logging.getLogger(__name__)
11 |
12 | __all__ = ["FillWindow"]
13 |
14 |
15 | class FillWindow(QtWidgets.QTableWidget):
16 | """
17 | present fills
18 | """
19 |
20 | fill_signal = QtCore.pyqtSignal(type(FillEvent()))
21 |
22 | def __init__(self, parent: Any = None) -> None:
23 | super(FillWindow, self).__init__(parent)
24 |
25 | self.header = [
26 | "OrderID",
27 | "FillID",
28 | "SID",
29 | "Symbol",
30 | "Fill_Price",
31 | "Filled",
32 | "Fill_Time",
33 | "Exchange",
34 | "Account",
35 | ]
36 |
37 | self.init_table()
38 | self._fillids: list[int] = []
39 | self.fill_signal.connect(self.update_table)
40 |
41 | def init_table(self) -> None:
42 | col = len(self.header)
43 | self.setColumnCount(col)
44 |
45 | self.setHorizontalHeaderLabels(self.header)
46 | self.setEditTriggers(self.NoEditTriggers)
47 | _vh = self.verticalHeader()
48 | if _vh:
49 | _vh.setVisible(False)
50 | self.setAlternatingRowColors(True)
51 | self.setSortingEnabled(False)
52 |
53 | def update_table(self, fill_event: FillEvent) -> None:
54 | """
55 | Only add row
56 | """
57 | if fill_event.fill_id in self._fillids:
58 | row = self._fillids.index(fill_event.fill_id)
59 | _itm = self.item(row, 6)
60 | if _itm:
61 | _itm.setText(
62 | fill_event.fill_time.strftime("%H:%M:%S.%f")
63 | if fill_event.fill_time
64 | else ""
65 | )
66 | _logger.error("received same fill twice")
67 | else: # including empty
68 | try:
69 | self._fillids.insert(0, fill_event.fill_id)
70 | self.insertRow(0)
71 | self.setItem(0, 0, QtWidgets.QTableWidgetItem(str(fill_event.order_id)))
72 | self.setItem(0, 1, QtWidgets.QTableWidgetItem(str(fill_event.fill_id)))
73 | self.setItem(0, 2, QtWidgets.QTableWidgetItem(str(fill_event.source)))
74 | self.setItem(0, 3, QtWidgets.QTableWidgetItem(fill_event.full_symbol))
75 | self.setItem(
76 | 0, 4, QtWidgets.QTableWidgetItem(str(fill_event.fill_price))
77 | )
78 | self.setItem(
79 | 0, 5, QtWidgets.QTableWidgetItem(str(fill_event.fill_size))
80 | )
81 | self.setItem(
82 | 0,
83 | 6,
84 | QtWidgets.QTableWidgetItem(
85 | fill_event.fill_time.strftime("%H:%M:%S.%f")
86 | if fill_event.fill_time
87 | else ""
88 | ),
89 | )
90 | self.setItem(0, 7, QtWidgets.QTableWidgetItem(fill_event.exchange))
91 | self.setItem(0, 8, QtWidgets.QTableWidgetItem(fill_event.account))
92 | except:
93 | _logger.error("unable to insert fill to fill window")
94 |
--------------------------------------------------------------------------------
/quanttrader/gui/ui_log_window.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from typing import Any
4 |
5 | from PyQt5 import QtCore, QtWidgets
6 |
7 | from ..event.event import LogEvent
8 |
9 | __all__ = ["LogWindow"]
10 |
11 |
12 | class LogWindow(QtWidgets.QTableWidget):
13 | msg_signal = QtCore.pyqtSignal(type(LogEvent()))
14 |
15 | def __init__(self, parent: Any = None) -> None:
16 | super(LogWindow, self).__init__(parent)
17 |
18 | self.header = ["Time", "Content"]
19 |
20 | self.init_table()
21 | self.msg_signal.connect(self.update_table)
22 |
23 | def init_table(self) -> None:
24 | col = len(self.header)
25 | self.setColumnCount(col)
26 |
27 | self.setHorizontalHeaderLabels(self.header)
28 | self.setEditTriggers(self.NoEditTriggers)
29 | _vh = self.verticalHeader()
30 | if _vh:
31 | _vh.setVisible(False)
32 | self.setAlternatingRowColors(True)
33 | self.setSortingEnabled(False)
34 |
35 | def update_table(self, geneal_event: LogEvent) -> None:
36 | """
37 | Only add row
38 | """
39 | self.insertRow(0)
40 | self.setItem(
41 | 0,
42 | 0,
43 | QtWidgets.QTableWidgetItem(
44 | geneal_event.timestamp.strftime("%H:%M:%S.%f")
45 | if geneal_event.timestamp
46 | else ""
47 | ),
48 | )
49 | self.setItem(0, 1, QtWidgets.QTableWidgetItem(geneal_event.content))
50 |
--------------------------------------------------------------------------------
/quanttrader/gui/ui_position_window.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import logging
4 | from typing import Any
5 |
6 | from PyQt5 import QtCore, QtWidgets
7 |
8 | from ..order.fill_event import FillEvent
9 | from ..position.position_event import PositionEvent
10 |
11 | _logger = logging.getLogger(__name__)
12 |
13 |
14 | __all__ = ["PositionWindow"]
15 |
16 |
17 | class PositionWindow(QtWidgets.QTableWidget):
18 | position_signal = QtCore.pyqtSignal(type(PositionEvent()))
19 |
20 | def __init__(self, parent: Any = None) -> None:
21 | super(PositionWindow, self).__init__(parent)
22 |
23 | self.header = [
24 | "Symbol",
25 | "Security_Type",
26 | "Quantity",
27 | "Average_Price",
28 | "Open_PnL",
29 | "Closed_PnL",
30 | "Account",
31 | "Time",
32 | ]
33 |
34 | self.init_table()
35 | self._symbols: list[str] = []
36 | self.position_signal.connect(self.update_table)
37 |
38 | def init_table(self) -> None:
39 | col = len(self.header)
40 | self.setColumnCount(col)
41 |
42 | self.setHorizontalHeaderLabels(self.header)
43 | self.setEditTriggers(self.NoEditTriggers)
44 | _vh = self.verticalHeader()
45 | if _vh:
46 | _vh.setVisible(False)
47 | self.setAlternatingRowColors(True)
48 | self.setSortingEnabled(False)
49 |
50 | def update_table(self, position_event: PositionEvent) -> None:
51 | if position_event.full_symbol in self._symbols:
52 | row = self._symbols.index(position_event.full_symbol)
53 | self.setItem(row, 1, QtWidgets.QTableWidgetItem(position_event.sec_type))
54 | self.setItem(row, 2, QtWidgets.QTableWidgetItem(str(position_event.size)))
55 | self.setItem(
56 | row,
57 | 3,
58 | QtWidgets.QTableWidgetItem(str(position_event.average_cost)),
59 | )
60 | self.setItem(
61 | row,
62 | 4,
63 | QtWidgets.QTableWidgetItem(str(position_event.unrealized_pnl)),
64 | )
65 | self.setItem(
66 | row,
67 | 5,
68 | QtWidgets.QTableWidgetItem(str(position_event.realized_pnl)),
69 | )
70 | self.setItem(row, 6, QtWidgets.QTableWidgetItem(position_event.account))
71 | self.setItem(row, 7, QtWidgets.QTableWidgetItem(position_event.timestamp))
72 | else:
73 | self._symbols.insert(0, str(position_event.full_symbol))
74 | self.insertRow(0)
75 | self.setItem(0, 0, QtWidgets.QTableWidgetItem(position_event.full_symbol))
76 | self.setItem(0, 1, QtWidgets.QTableWidgetItem(position_event.sec_type))
77 | self.setItem(0, 2, QtWidgets.QTableWidgetItem(str(position_event.size)))
78 | self.setItem(
79 | 0,
80 | 3,
81 | QtWidgets.QTableWidgetItem(str(position_event.average_cost)),
82 | )
83 | self.setItem(
84 | 0,
85 | 4,
86 | QtWidgets.QTableWidgetItem(str(position_event.unrealized_pnl)),
87 | )
88 | self.setItem(
89 | 0,
90 | 5,
91 | QtWidgets.QTableWidgetItem(str(position_event.realized_pnl)),
92 | )
93 | self.setItem(0, 6, QtWidgets.QTableWidgetItem(position_event.account))
94 | self.setItem(0, 7, QtWidgets.QTableWidgetItem(position_event.timestamp))
95 |
96 | def on_fill(self, fill_event: FillEvent) -> None:
97 | pass
98 |
--------------------------------------------------------------------------------
/quanttrader/log/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .trade_recorder import *
4 |
--------------------------------------------------------------------------------
/quanttrader/log/tick_recorder.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
--------------------------------------------------------------------------------
/quanttrader/log/trade_recorder.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import csv
4 | import datetime
5 | import logging
6 | import os
7 |
8 | _logger = logging.getLogger(__name__)
9 |
10 | from .trade_recorder_base import AbstractTradeRecorder
11 |
12 | __all__ = ["ExampleTradeRecorder"]
13 |
14 |
15 | class ExampleTradeRecorder(AbstractTradeRecorder):
16 | """
17 | A basic compliance module which writes trades to a
18 | CSV file in the output directory.
19 | """
20 |
21 | def __init__(self, output_dir):
22 | """
23 | Wipe the existing trade log for the day, leaving only
24 | the headers in an empty CSV.
25 |
26 | It allows for multiple backtests to be run
27 | in a simple way, but quite likely makes it unsuitable for
28 | a production environment that requires strict record-keeping.
29 | """
30 | self.output_dir = output_dir
31 | # Remove the previous CSV file
32 | today = datetime.datetime.utcnow().date()
33 | self.csv_filename = "tradelog_" + today.strftime("%Y-%m-%d") + ".csv"
34 |
35 | try:
36 | fname = os.path.expanduser(os.path.join(self.output_dir, self.csv_filename))
37 | os.remove(fname)
38 | except (IOError, OSError):
39 | _logger.error("No tradelog files to clean.")
40 |
41 | # Write new file header
42 | fieldnames = [
43 | "timestamp",
44 | "ticker",
45 | "action",
46 | "quantity",
47 | "exchange",
48 | "price",
49 | "commission",
50 | ]
51 | fname = os.path.expanduser(os.path.join(self.output_dir, self.csv_filename))
52 | with open(fname, "a") as csvfile:
53 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
54 | writer.writeheader()
55 |
56 | def record_trade(self, fill):
57 | """
58 | Append all details about the FillEvent to the CSV trade log.
59 | """
60 | fname = os.path.expanduser(os.path.join(self.output_dir, self.csv_filename))
61 | with open(fname, "a") as csvfile:
62 | writer = csv.writer(csvfile)
63 | writer.writerow(
64 | [
65 | fill.timestamp,
66 | fill.ticker,
67 | fill.action,
68 | fill.quantity,
69 | fill.exchange,
70 | round(fill.price, 4),
71 | round(fill.commission, 4),
72 | ]
73 | )
74 |
--------------------------------------------------------------------------------
/quanttrader/log/trade_recorder_base.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from abc import ABCMeta, abstractmethod
4 |
5 |
6 | class AbstractTradeRecorder(object):
7 | """
8 | transaction recorder
9 | """
10 |
11 | __metaclass__ = ABCMeta
12 |
13 | @abstractmethod
14 | def record_trade(self, fill):
15 | """
16 | logs fill event
17 | """
18 | raise NotImplementedError("Should implement record_trade()")
19 |
--------------------------------------------------------------------------------
/quanttrader/order/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .fill_event import *
4 | from .order_event import *
5 | from .order_flag import *
6 | from .order_manager import *
7 | from .order_status import *
8 | from .order_type import *
9 |
--------------------------------------------------------------------------------
/quanttrader/order/fill_event.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import pandas as pd
4 |
5 | from ..event.event import Event, EventType
6 | from ..position.position import Position
7 |
8 | __all__ = ["FillEvent"]
9 |
10 |
11 | class FillEvent(Event):
12 | """
13 | Fill event, with filled quantity/size and price
14 | """
15 |
16 | def __init__(self) -> None:
17 | """
18 | Initialises fill
19 | """
20 | self.event_type: EventType = EventType.FILL
21 | self.order_id: int = -1
22 | self.fill_id: int = -1
23 | self.full_symbol: str = ""
24 | self.fill_time: pd.Timestamp
25 | self.fill_price: float = 0.0
26 | self.fill_size: int = 0 # size < 0 means short order is filled
27 | self.exchange: str = ""
28 | self.commission: float = 0.0
29 | self.account: str = ""
30 | self.source: int = -1
31 | self.api: str = ""
32 |
33 | def to_position(self, multiplier: float = 1.0) -> Position:
34 | """
35 | if there is no existing position for this symbol, this fill will create a new position
36 | (otherwise it will be adjusted to exisitng position)
37 | """
38 | if self.fill_size > 0:
39 | average_price_including_commission = (
40 | self.fill_price + self.commission / multiplier
41 | )
42 | else:
43 | average_price_including_commission = (
44 | self.fill_price - self.commission / multiplier
45 | )
46 |
47 | new_position = Position(
48 | self.full_symbol, average_price_including_commission, self.fill_size
49 | )
50 | return new_position
51 |
52 | def __str__(self) -> str:
53 | return (
54 | "Time: %s, Source: %s, Oid: %s, Ticker: %s, Price: %s, Size %s Comm %s"
55 | % (
56 | self.fill_time,
57 | str(self.source),
58 | str(self.order_id),
59 | self.full_symbol,
60 | str(self.fill_price),
61 | str(self.fill_size),
62 | str(self.commission),
63 | )
64 | )
65 |
--------------------------------------------------------------------------------
/quanttrader/order/order_event.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import pandas as pd
4 |
5 | from ..event.event import Event, EventType
6 | from .order_flag import OrderFlag
7 | from .order_status import OrderStatus
8 | from .order_type import OrderType
9 |
10 | __all__ = ["OrderEvent"]
11 |
12 |
13 | class OrderEvent(Event):
14 | """
15 | Order event
16 | """
17 |
18 | def __init__(self) -> None:
19 | """
20 | order and order status
21 | """
22 | self.event_type: EventType = EventType.ORDER
23 | self.order_id: int = -1
24 | self.order_type: OrderType = OrderType.MARKET
25 | self.order_flag: OrderFlag = OrderFlag.OPEN
26 | self.order_status: OrderStatus = OrderStatus.UNKNOWN
27 | self.full_symbol: str = ""
28 | self.order_size: int = 0 # short < 0, long > 0
29 | self.limit_price: float = 0.0
30 | self.stop_price: float = 0.0
31 | self.fill_size: int = 0
32 | self.fill_price: float = 0.0
33 | self.create_time: pd.Timestamp = None
34 | self.fill_time: pd.Timestamp = None
35 | self.cancel_time: pd.Timestamp = None
36 | self.account: str = ""
37 | self.source: int = -1 # sid, -1: unknown, 0: discretionary
38 |
39 | def __str__(self) -> str:
40 | return "Time: %s, Source: %s, Type: %s, LMT: %s, STP %s Size %s" % (
41 | self.create_time,
42 | str(self.source),
43 | str(self.order_type),
44 | str(self.limit_price),
45 | str(self.stop_price),
46 | str(self.order_size),
47 | )
48 |
--------------------------------------------------------------------------------
/quanttrader/order/order_flag.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from enum import Enum
4 |
5 | __all__ = ["OrderFlag"]
6 |
7 |
8 | class OrderFlag(Enum):
9 | OPEN = 0 # in use
10 | CLOSE = 1
11 | CLOSE_TODAY = 2 # in use
12 | CLOSE_YESTERDAY = 3 # in use
13 |
--------------------------------------------------------------------------------
/quanttrader/order/order_status.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from __future__ import annotations # Only needed if you are using Python < 3.10
4 |
5 | from enum import Enum
6 | from functools import total_ordering
7 |
8 | __all__ = ["OrderStatus"]
9 |
10 |
11 | @total_ordering
12 | class OrderStatus(Enum):
13 | UNKNOWN = 0
14 | NEWBORN = 1 # in use
15 | ACKNOWLEDGED = 2 # in use
16 | PENDING_SUBMIT = 3 # or PRE-SUBMIT
17 | SUBMITTED = 4 # in use
18 | PARTIALLY_FILLED = 5
19 | FILLED = 6 # in use
20 | PENDING_CANCEL = 7
21 | CANCELED = 8 # in use
22 | API_PENDING = 10
23 | API_CANCELLED = 11
24 | ERROR = 12
25 |
26 | def __lt__(self, other: OrderStatus) -> bool:
27 | if self.__class__ is other.__class__:
28 | return self.value < other.value
29 | return NotImplemented
30 |
--------------------------------------------------------------------------------
/quanttrader/order/order_type.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from enum import Enum
4 |
5 | __all__ = ["OrderType"]
6 |
7 |
8 | # OrderType.MKT.name == 'MKT' OderType.MKT.value == 1
9 | class OrderType(Enum):
10 | UNKNOWN = 0
11 | MARKET = 1
12 | LIMIT = 2
13 | STOP = 3
14 | STOP_LIMIT = 4
15 | TRAIING_STOP = 5
16 |
--------------------------------------------------------------------------------
/quanttrader/performance/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .performance_manager import *
4 | from .report_manager import *
5 |
--------------------------------------------------------------------------------
/quanttrader/performance/report_manager.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | __all__ = ["ReportManager"]
5 |
6 |
7 | class ReportManager(object):
8 | def __init__(self):
9 | pass
10 |
--------------------------------------------------------------------------------
/quanttrader/position/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .contract_event import *
4 | from .position import *
5 | from .position_event import *
6 | from .position_manager import *
7 |
--------------------------------------------------------------------------------
/quanttrader/position/contract_event.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from ..event.event import Event, EventType
5 |
6 | __all__ = ["ContractEvent"]
7 |
8 |
9 | class ContractEvent(Event):
10 | """
11 | also serve as contract
12 | """
13 |
14 | def __init__(self) -> None:
15 | self.event_type: EventType = EventType.CONTRACT
16 | self.full_symbol: str = ""
17 | self.local_name: str = ""
18 | self.mininum_tick: int = 0
19 |
--------------------------------------------------------------------------------
/quanttrader/position/position_event.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import pandas as pd
4 |
5 | from ..event.event import Event, EventType
6 | from .position import Position
7 |
8 | __all__ = ["PositionEvent"]
9 |
10 |
11 | class PositionEvent(Event):
12 | """
13 | position event directly from live broker
14 | """
15 |
16 | def __init__(self) -> None:
17 | """
18 | Initialises order
19 | """
20 | self.event_type: EventType = EventType.POSITION
21 | self.full_symbol: str = ""
22 | self.sec_type: str = ""
23 | self.average_cost: float = 0.0
24 | self.size: int = 0
25 | self.pre_size: int = 0
26 | self.freezed_size: int = 0
27 | self.realized_pnl: float = 0.0
28 | self.unrealized_pnl: float = 0.0
29 | self.account: str = ""
30 | self.timestamp: pd.Timestamp = ""
31 |
32 | def to_position(self) -> Position:
33 | pos = Position(self.full_symbol, self.average_cost, self.size)
34 | pos.realized_pnl = self.realized_pnl
35 | pos.unrealized_pnl = self.unrealized_pnl
36 | pos.account = self.account
37 |
38 | return pos
39 |
40 | def __str__(self) -> str:
41 | return "Ticker: %s, Cost: %s, Size: %s, opl: %s, rpl: %s" % (
42 | str(self.full_symbol),
43 | str(self.average_cost),
44 | str(self.size),
45 | str(self.unrealized_pnl),
46 | str(self.realized_pnl),
47 | )
48 |
--------------------------------------------------------------------------------
/quanttrader/risk/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .margin_manager import *
4 | from .risk_manager import *
5 | from .risk_manager_base import *
6 |
--------------------------------------------------------------------------------
/quanttrader/risk/margin_manager.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | __all__ = ["MarginManager"]
6 |
7 |
8 | class MarginManager(object):
9 | def __init__(self):
10 | pass
11 |
--------------------------------------------------------------------------------
/quanttrader/risk/risk_manager_base.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from abc import ABCMeta, abstractmethod
4 |
5 | from ..order.order_event import OrderEvent
6 |
7 | __all__ = ["RiskManagerBase"]
8 |
9 |
10 | class RiskManagerBase(metaclass=ABCMeta):
11 | """
12 | RiskManager base class
13 | """
14 |
15 | @abstractmethod
16 | def order_in_compliance(self, o: OrderEvent, strategy_manager=None) -> bool: # type: ignore
17 | raise NotImplementedError("order_in_compliance should be implemented")
18 |
--------------------------------------------------------------------------------
/quanttrader/strategy/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .strategy_base import *
4 | from .strategy_manager import *
5 |
--------------------------------------------------------------------------------
/quanttrader/util/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from .util_func import *
4 |
--------------------------------------------------------------------------------
/quanttrader/util/util_func.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import os
4 | import pickle
5 | from datetime import datetime
6 |
7 | import pandas as pd
8 |
9 | __all__ = [
10 | "read_ohlcv_csv",
11 | "read_intraday_bar_pickle",
12 | "read_tick_data_txt",
13 | "save_one_run_results",
14 | ]
15 |
16 |
17 | def read_ohlcv_csv(
18 | filepath: str, adjust: bool = True, tz: str = "America/New_York"
19 | ) -> pd.DataFrame:
20 |
21 | df = pd.read_csv(filepath, header=0, parse_dates=True, sep=",", index_col=0)
22 | df.index = df.index + pd.DateOffset(hours=16)
23 | df.index = df.index.tz_localize(tz) # US/Eastern, UTC
24 | # df.index = pd.to_datetime(df.index)
25 | if adjust:
26 | df["Open"] = df["Adj Close"] / df["Close"] * df["Open"]
27 | df["High"] = df["Adj Close"] / df["Close"] * df["High"]
28 | df["Low"] = df["Adj Close"] / df["Close"] * df["Low"]
29 | df["Volume"] = df["Adj Close"] / df["Close"] * df["Volume"]
30 | df["Close"] = df["Adj Close"]
31 |
32 | df = df[["Open", "High", "Low", "Close", "Volume"]]
33 | return df
34 |
35 |
36 | def read_intraday_bar_pickle(
37 | filepath: str, syms: list[str], tz: str = "America/New_York"
38 | ) -> dict[str, pd.DataFrame]:
39 |
40 | dict_hist_data = {}
41 | if os.path.isfile(filepath):
42 | with open(filepath, "rb") as f:
43 | dict_hist_data = pickle.load(f)
44 | dict_ret = {}
45 | for sym in syms:
46 | try:
47 | df = dict_hist_data[sym]
48 | df.index = df.index.tz_localize(tz) # # US/Eastern, UTC
49 | dict_ret[sym] = df
50 | except Exception as e:
51 | print(f"An error occurred: {e}")
52 | return dict_ret
53 |
54 |
55 | def read_tick_data_txt(
56 | filepath: str, remove_bo: bool = True, tz: str = "America/New_York"
57 | ) -> dict[str, pd.DataFrame]:
58 | """
59 | filename = yyyymmdd.txt
60 | """
61 | asofdate = filepath.split("/")[-1].split(".")[0]
62 | data = pd.read_csv(filepath, sep=",", header=None)
63 | data.columns = [
64 | "Time",
65 | "ProcessTime",
66 | "Ticker",
67 | "Type",
68 | "BidSize",
69 | "Bid",
70 | "Ask",
71 | "AskSize",
72 | "Price",
73 | "Size",
74 | ]
75 | data = data[
76 | [
77 | "Time",
78 | "Ticker",
79 | "Type",
80 | "BidSize",
81 | "Bid",
82 | "Ask",
83 | "AskSize",
84 | "Price",
85 | "Size",
86 | ]
87 | ]
88 | if remove_bo:
89 | data = data[data.Type.str.contains("TickType.TRADE")]
90 | data.Time = data.Time.apply(
91 | lambda t: datetime.strptime(f"{asofdate} {t}", "%Y%m%d %H:%M:%S.%f")
92 | )
93 | data.set_index("Time", inplace=True)
94 | data.index = data.index.tz_localize(tz) # # US/Eastern, UTC
95 | dg = data.groupby("Ticker")
96 | dict_ret = {}
97 | for sym, dgf in dg:
98 | dgf = dgf[~dgf.index.duplicated(keep="last")]
99 | dict_ret[sym] = dgf
100 | return dict_ret
101 |
102 |
103 | def save_one_run_results(
104 | output_dir: str,
105 | equity: pd.DataFrame,
106 | df_positions: pd.DataFrame,
107 | df_trades: pd.DataFrame,
108 | batch_tag: bool = False,
109 | ) -> None:
110 |
111 | df_positions.to_csv(f"{output_dir}/positions_{batch_tag if batch_tag else ""}.csv")
112 | df_trades.to_csv(f"{output_dir}/trades_{batch_tag if batch_tag else ""}.csv")
113 | equity.to_csv(f"{output_dir}/equity_{batch_tag if batch_tag else ""}.csv")
114 |
--------------------------------------------------------------------------------
/quanttrader/version.py:
--------------------------------------------------------------------------------
1 | VERSION = "0.5.5"
2 |
--------------------------------------------------------------------------------
/sphinx/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/backtest.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/backtest.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/brokerage.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/brokerage.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/data.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/data.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/environment.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/environment.pickle
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/event.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/event.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/gui.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/gui.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/index.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/index.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/installation.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/installation.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/instrument.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/instrument.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/intro.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/intro.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/introduction.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/introduction.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/livetrading.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/livetrading.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/order.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/order.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/ordertype.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/ordertype.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/performance.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/performance.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/position.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/position.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/risk.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/risk.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/strategy.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/strategy.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/trading_engine.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/trading_engine.doctree
--------------------------------------------------------------------------------
/sphinx/_build/doctrees/tradingengine.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/doctrees/tradingengine.doctree
--------------------------------------------------------------------------------
/sphinx/_build/html/.buildinfo:
--------------------------------------------------------------------------------
1 | # Sphinx build info version 1
2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3 | config: a7f9dea1d954c700f5fc66492ec65237
4 | tags: 645f666f9bcd5a90fca523b33c5a78b7
5 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/backtest.md.txt:
--------------------------------------------------------------------------------
1 | ## Backtest
2 |
3 | [This document](https://letianzj.github.io/quanttrading-backtest.html) explains quanttrader backtest framework and code structure.
4 |
5 | [This repository](https://github.com/letianzj/QuantResearch/tree/master/backtest) contains examples of some classical strategies and their Sharpe ratios, as well as grid-search based parameter optimization. The backtest is designed to be working together with the [pyfolio](https://github.com/quantopian/pyfolio) library.
6 |
7 | One distinctive design in backtest is that it fills market order right away instead of filling against tomorrow's open price. After all, in the daily bar setting, it is better to send out order at 15:59:59 than waiting overnight for next day' open. If you disagree, simply save the market order similar to limit or stop order in the BacktestBrokerage class and then fill it on next tick.
8 |
9 | Currently backtest accepts three data feeds.
10 |
11 | * Daily bar or intraday bar from Yahoo Finance. See [here](https://medium.com/@letian.zj/free-historical-market-data-download-in-python-74e8edd462cf?source=friends_link&sk=5af814910524a593353ed3146290d50e) for how to download.
12 |
13 | * Historical intraday bar from Interactive Brokers. Use [this script](https://github.com/letianzj/quanttrader/blob/master/examples/download_historical_data_from_ib.py) to download.
14 |
15 | * Live tick recorded from live trading session. [This video](https://t.co/rXdW8EIbWw?amp=1) demonstrates how to do it in live session.
16 |
17 | It is possible to load your own data source by following the above examples.
18 |
19 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/brokerage.rst.txt:
--------------------------------------------------------------------------------
1 | Brokerage
2 | ==================
3 |
4 | .. autoclass:: quanttrader.brokerage.backtest_brokerage.BacktestBrokerage
5 | :members:
6 |
7 | .. automethod:: __init__
8 |
9 | .. autoclass:: quanttrader.brokerage.ib_brokerage.InteractiveBrokers
10 | :members:
11 |
12 | .. automethod:: __init__
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/data.rst.txt:
--------------------------------------------------------------------------------
1 | Data
2 | ==================
3 |
4 | .. automodule:: quanttrader.data.backtest_data_feed
5 | :members:
6 |
7 | .. automodule:: quanttrader.data.data_board
8 | :members:
9 |
10 | .. automodule:: quanttrader.data.live_data_feed
11 | :members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/event.rst.txt:
--------------------------------------------------------------------------------
1 | Event
2 | ==================
3 |
4 | .. automodule:: quanttrader.event.backtest_event_engine
5 | :members:
6 |
7 | .. automodule:: quanttrader.event.live_event_engine
8 | :members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/gui.rst.txt:
--------------------------------------------------------------------------------
1 | GUI
2 | ==================
3 |
4 | .. automodule:: quanttrader.gui.ui_account_window
5 | :members:
6 |
7 | .. automodule:: quanttrader.gui.ui_fill_window
8 | :members:
9 |
10 | .. automodule:: quanttrader.gui.ui_log_window
11 | :members:
12 |
13 | .. automodule:: quanttrader.gui.ui_order_window
14 | :members:
15 |
16 | .. automodule:: quanttrader.gui.ui_position_menu
17 | :members:
18 |
19 | .. automodule:: quanttrader.gui.ui_position_window
20 | :members:
21 |
22 | .. automodule:: quanttrader.gui.ui_risk_menu
23 | :members:
24 |
25 | .. automodule:: quanttrader.gui.ui_strategy_window
26 | :members:
27 |
28 | .. automodule:: quanttrader.gui.ui_trade_menu
29 | :members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/index.rst.txt:
--------------------------------------------------------------------------------
1 | Welcome to quanttrader documentation!
2 | =======================================
3 |
4 | **Pure Python Backtest and Live Trade Package for Quant Traders**
5 |
6 | .. toctree::
7 | :maxdepth: 2
8 | :caption: Contents
9 |
10 | introduction.md
11 | installation.md
12 | backtest.md
13 | livetrading.md
14 | instrument.md
15 | ordertype.md
16 |
17 | .. toctree::
18 | :maxdepth: 2
19 | :caption: Codes
20 |
21 | brokerage
22 | data
23 | event
24 | gui
25 | order
26 | performance
27 | position
28 | risk
29 | strategy
30 | tradingengine
31 |
32 | Indices and tables
33 | ==================
34 |
35 | * :ref:`genindex`
36 | * :ref:`modindex`
37 | * :ref:`search`
38 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/installation.md.txt:
--------------------------------------------------------------------------------
1 | ## Installation
2 |
3 | The quanttrader package is ready for pip install.
4 |
5 | ```python
6 | pip install quanttrader
7 | ```
8 |
9 | To use source code, git pull the repository or use [GitHub desktop](https://desktop.github.com/) and then add the project path to PYTHONPATH environment variable.
10 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/instrument.md.txt:
--------------------------------------------------------------------------------
1 | ## Instruments Supported
2 |
3 | Intrument type and example
4 |
5 | * __Stock:__ AMZN STK SMART
6 | * __Foreign Exchange:__ EURGBP CASH IDEALPRO
7 | * __Futures:__ ESM9 FUT GLOBEX
8 | * __Options on Stock:__ AAPL OPT 20201016 128.75 C SMART
9 | * __Options on Futures:__ ES FOP 20200911 3450 C 50 GLOBEX
10 | * __Comdty:__ XAUUSD CMDTY SMART
11 | * __Stock Combo:__: SPY,AAPL BAG 756733 1 SMART 265598 1 SMART SMART
12 | * __Option Combo:__: SPY BAG 398943121 1 SMART 398943218 1 SMART SMART # straddle
13 | * __Calendar Spread__: CL BAG 174230608 1 NYMEX 174230606 1 NYMEX NYMEX
14 | * __Inter-Comdty Spread__: CL.BZ BAG 174230606 1 NYMEX 162929662 1 NYMEX NYMEX
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/intro.md.txt:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | This is introduction
4 |
5 | ```python
6 | s = "Python syntax highlighting"
7 | print s
8 | ```
9 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/introduction.md.txt:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | Welcome to quanttrader, a pure python-based event-driven backtest and live trading package for quant traders.
4 |
5 | In most cases, a backtest strategy can be directly used for live trade by simply switching to live brokerage. A control window is provided to monitor live trading sessions for each strategy separately and the portfolio as a whole.
6 |
7 | The source code is completely open-sourced [here on GitHub](https://github.com/letianzj/quanttrader). The package is published [here on pypi](https://pypi.org/project/quanttrader/) and is ready to be pip installed. The document is hosted [here on readthedocs](https://quanttrader.readthedocs.io/).
8 |
9 | This is NOT an ultra-low latency framework that can provide nano-second level executions. The response time, for example, between receiving data from the broker and sending out orders for a pairs-trading strategy that is subscribed to two stock feeds, is in the neighbourhood of milli-seconds. This package is designed mainly for quant traders who do not rely on market-making strategies.
10 |
11 | __Disclaimer: This is an open-source library that is free to use, free to contribute but use at OWN risk. It does NOT promise any future profits nor is responsible for any future loses.__
12 |
13 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/livetrading.md.txt:
--------------------------------------------------------------------------------
1 | ## Live Trading
2 |
3 | [This youtube video](https://t.co/rXdW8EIbWw?amp=1) and [accompanying document](https://letianzj.github.io/live-trading-ib-native-python.html) demonstrates step-by-step how to set up quanttrader for live trading. Currently quanttrader only supports Interactive Brokers.
4 |
5 | __Files used for live Trading are__
6 |
7 | * [live_engine.py](https://github.com/letianzj/quanttrader/blob/master/examples/live_engine.py) - the main entry point
8 |
9 | * [config_live.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/config_live.yaml) - config file for live session
10 |
11 | * [instrument_meta.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/instrument_meta.yaml) - meta data for instruments to be traded
12 |
13 | * [prepare_trading_session.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/prepare_trading_session.py) - an example to demonstrate how to prepare data and strategy parameters before today's live session
14 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/order.rst.txt:
--------------------------------------------------------------------------------
1 | Order
2 | ==================
3 | .. automodule:: quanttrader.order.order_manager
4 | :members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/ordertype.md.txt:
--------------------------------------------------------------------------------
1 | ## Orders Supported
2 |
3 | Basic order types. See [IB Doc](http://interactivebrokers.github.io/tws-api/basic_orders.html) for details.
4 |
5 | * Auction
6 | * Auction Limit
7 | * Market
8 | * Market If Touched
9 | * Market On Close
10 | * Market On Open
11 | * Market to Limit
12 | * Limit Order
13 | * Limit if Touched
14 | * Limit on Close
15 | * Limit on Open
16 | * Stop
17 | * Stop Limit
18 | * Trailing Stop
19 | * Trailing Stop Limit
20 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/performance.rst.txt:
--------------------------------------------------------------------------------
1 | Performance
2 | ==================
3 | .. automodule:: quanttrader.performance.performance_manager
4 | :members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/position.rst.txt:
--------------------------------------------------------------------------------
1 | Position
2 | ==================
3 | .. automodule:: quanttrader.position.position_manager
4 | :members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/risk.rst.txt:
--------------------------------------------------------------------------------
1 | Risk
2 | ==================
3 | .. automodule:: quanttrader.risk.risk_manager
4 | :members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/strategy.rst.txt:
--------------------------------------------------------------------------------
1 | Strategy
2 | ==================
3 |
4 | .. automodule:: quanttrader.strategy.strategy_base
5 | :members:
6 | :undoc-members:
7 |
8 | .. automodule:: quanttrader.strategy.strategy_manager
9 | :members:
10 | :undoc-members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/trading_engine.rst.txt:
--------------------------------------------------------------------------------
1 | Trading Engine
2 | ==================
3 |
4 | .. automodule:: quanttrader.gui.ui_main_window
5 | :members:
6 | :undoc-members:
7 |
8 | .. automodule:: quanttrader.backtest_engine
9 | :members:
10 | :undoc-members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_sources/tradingengine.rst.txt:
--------------------------------------------------------------------------------
1 | Trading Engine
2 | ==================
3 |
4 | .. automodule:: quanttrader.gui.ui_main_window
5 | :members:
6 | :undoc-members:
7 |
8 | .. automodule:: quanttrader.backtest_engine
9 | :members:
10 | :undoc-members:
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/badge_only.css:
--------------------------------------------------------------------------------
1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/lato-bold-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/lato-bold-italic.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/lato-bold-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/lato-bold-italic.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/lato-bold.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/lato-bold.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/lato-normal-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/lato-normal-italic.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/lato-normal-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/lato-normal-italic.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/lato-normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/lato-normal.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/css/fonts/lato-normal.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/css/fonts/lato-normal.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/custom.css:
--------------------------------------------------------------------------------
1 | /* This file intentionally left blank. */
2 |
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/documentation_options.js:
--------------------------------------------------------------------------------
1 | var DOCUMENTATION_OPTIONS = {
2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 | VERSION: '0.5.0',
4 | LANGUAGE: 'None',
5 | COLLAPSE_INDEX: false,
6 | BUILDER: 'html',
7 | FILE_SUFFIX: '.html',
8 | LINK_SUFFIX: '.html',
9 | HAS_SOURCE: true,
10 | SOURCELINK_SUFFIX: '.txt',
11 | NAVIGATION_WITH_KEYS: false
12 | };
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/file.png
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-bold.eot
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-bold.ttf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-bold.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-bold.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-bolditalic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-bolditalic.eot
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-bolditalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-bolditalic.ttf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-bolditalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-bolditalic.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-bolditalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-bolditalic.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-italic.eot
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-italic.ttf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-italic.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-italic.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-regular.eot
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-regular.ttf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-regular.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Lato/lato-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Lato/lato-regular.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Roboto-Slab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Roboto-Slab-Bold.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Roboto-Slab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Roboto-Slab-Bold.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Roboto-Slab-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Roboto-Slab-Light.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Roboto-Slab-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Roboto-Slab-Light.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Roboto-Slab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Roboto-Slab-Regular.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Roboto-Slab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Roboto-Slab-Regular.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Roboto-Slab-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Roboto-Slab-Thin.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/Roboto-Slab-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/Roboto-Slab-Thin.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/lato-bold-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/lato-bold-italic.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/lato-bold-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/lato-bold-italic.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/lato-bold.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/lato-bold.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/lato-normal-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/lato-normal-italic.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/lato-normal-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/lato-normal-italic.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/lato-normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/lato-normal.woff
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/fonts/lato-normal.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/fonts/lato-normal.woff2
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/js/badge_only.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/js/html5shiv-printshiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/minus.png
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/_static/plus.png
--------------------------------------------------------------------------------
/sphinx/_build/html/_static/pygments.css:
--------------------------------------------------------------------------------
1 | .highlight .hll { background-color: #ffffcc }
2 | .highlight { background: #f8f8f8; }
3 | .highlight .c { color: #408080; font-style: italic } /* Comment */
4 | .highlight .err { border: 1px solid #FF0000 } /* Error */
5 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */
6 | .highlight .o { color: #666666 } /* Operator */
7 | .highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
8 | .highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
9 | .highlight .cp { color: #BC7A00 } /* Comment.Preproc */
10 | .highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
11 | .highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
12 | .highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
13 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
14 | .highlight .ge { font-style: italic } /* Generic.Emph */
15 | .highlight .gr { color: #FF0000 } /* Generic.Error */
16 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
17 | .highlight .gi { color: #00A000 } /* Generic.Inserted */
18 | .highlight .go { color: #888888 } /* Generic.Output */
19 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
20 | .highlight .gs { font-weight: bold } /* Generic.Strong */
21 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
22 | .highlight .gt { color: #0044DD } /* Generic.Traceback */
23 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
24 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
25 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
26 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */
27 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
28 | .highlight .kt { color: #B00040 } /* Keyword.Type */
29 | .highlight .m { color: #666666 } /* Literal.Number */
30 | .highlight .s { color: #BA2121 } /* Literal.String */
31 | .highlight .na { color: #7D9029 } /* Name.Attribute */
32 | .highlight .nb { color: #008000 } /* Name.Builtin */
33 | .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
34 | .highlight .no { color: #880000 } /* Name.Constant */
35 | .highlight .nd { color: #AA22FF } /* Name.Decorator */
36 | .highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
37 | .highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
38 | .highlight .nf { color: #0000FF } /* Name.Function */
39 | .highlight .nl { color: #A0A000 } /* Name.Label */
40 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
41 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
42 | .highlight .nv { color: #19177C } /* Name.Variable */
43 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
44 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
45 | .highlight .mb { color: #666666 } /* Literal.Number.Bin */
46 | .highlight .mf { color: #666666 } /* Literal.Number.Float */
47 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */
48 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */
49 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */
50 | .highlight .sa { color: #BA2121 } /* Literal.String.Affix */
51 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
52 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */
53 | .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
54 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
55 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */
56 | .highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
57 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
58 | .highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
59 | .highlight .sx { color: #008000 } /* Literal.String.Other */
60 | .highlight .sr { color: #BB6688 } /* Literal.String.Regex */
61 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */
62 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */
63 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
64 | .highlight .fm { color: #0000FF } /* Name.Function.Magic */
65 | .highlight .vc { color: #19177C } /* Name.Variable.Class */
66 | .highlight .vg { color: #19177C } /* Name.Variable.Global */
67 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */
68 | .highlight .vm { color: #19177C } /* Name.Variable.Magic */
69 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/sphinx/_build/html/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/sphinx/_build/html/objects.inv
--------------------------------------------------------------------------------
/sphinx/backtest.md:
--------------------------------------------------------------------------------
1 | ## Backtest
2 |
3 | [This document](https://letianzj.github.io/quanttrading-backtest.html) explains quanttrader backtest framework and code structure.
4 |
5 | [This repository](https://github.com/letianzj/QuantResearch/tree/master/backtest) contains examples of some classical strategies and their Sharpe ratios, as well as grid-search based parameter optimization. The backtest is designed to be working together with the [pyfolio](https://github.com/quantopian/pyfolio) library.
6 |
7 | One distinctive design in backtest is that it fills market order right away instead of filling against tomorrow's open price. After all, in the daily bar setting, it is better to send out order at 15:59:59 than waiting overnight for next day' open. If you disagree, simply save the market order similar to limit or stop order in the BacktestBrokerage class and then fill it on next tick.
8 |
9 | Currently backtest accepts three data feeds.
10 |
11 | * Daily bar or intraday bar from Yahoo Finance. See [here](https://medium.com/@letian.zj/free-historical-market-data-download-in-python-74e8edd462cf?source=friends_link&sk=5af814910524a593353ed3146290d50e) for how to download.
12 |
13 | * Historical intraday bar from Interactive Brokers. Use [this script](https://github.com/letianzj/quanttrader/blob/master/examples/download_historical_data_from_ib.py) to download.
14 |
15 | * Live tick recorded from live trading session. [This video](https://t.co/rXdW8EIbWw?amp=1) demonstrates how to do it in live session.
16 |
17 | It is possible to load your own data source by following the above examples.
18 |
19 |
--------------------------------------------------------------------------------
/sphinx/brokerage.rst:
--------------------------------------------------------------------------------
1 | Brokerage
2 | ==================
3 |
4 | .. autoclass:: quanttrader.brokerage.backtest_brokerage.BacktestBrokerage
5 | :members:
6 |
7 | .. automethod:: __init__
8 |
9 | .. autoclass:: quanttrader.brokerage.ib_brokerage.InteractiveBrokers
10 | :members:
11 |
12 | .. automethod:: __init__
--------------------------------------------------------------------------------
/sphinx/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | import os
10 | import sys
11 |
12 | # If extensions (or modules to document with autodoc) are in another directory,
13 | # add these directories to sys.path here. If the directory is relative to the
14 | # documentation root, use os.path.abspath to make it absolute, like shown here.
15 | #
16 | import sphinx_rtd_theme
17 | from recommonmark.parser import CommonMarkParser
18 |
19 | sys.path.insert(0, os.path.abspath(".."))
20 |
21 | # -- Project information -----------------------------------------------------
22 |
23 | project = "quanttrader"
24 | copyright = "2020, Letian Wang"
25 | author = "Letian Wang"
26 |
27 | # The full version, including alpha/beta/rc tags
28 | release = "0.5.0"
29 |
30 |
31 | # -- General configuration ---------------------------------------------------
32 |
33 | # Add any Sphinx extension module names here, as strings. They can be
34 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
35 | # ones.
36 | extensions = [
37 | "sphinx.ext.autodoc",
38 | "sphinx.ext.coverage",
39 | "sphinx.ext.napoleon",
40 | "sphinx_rtd_theme",
41 | "recommonmark",
42 | ]
43 |
44 | # Add any paths that contain templates here, relative to this directory.
45 | templates_path = ["_templates"]
46 |
47 | # List of patterns, relative to source directory, that match files and
48 | # directories to ignore when looking for source files.
49 | # This pattern also affects html_static_path and html_extra_path.
50 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
51 |
52 |
53 | # -- Options for HTML output -------------------------------------------------
54 |
55 | # The theme to use for HTML and HTML Help pages. See the documentation for
56 | # a list of builtin themes.
57 | #
58 | html_theme = "sphinx_rtd_theme"
59 |
60 | # Add any paths that contain custom static files (such as style sheets) here,
61 | # relative to this directory. They are copied after the builtin static files,
62 | # so a file named "default.css" will overwrite the builtin "default.css".
63 | html_static_path = ["_static"]
64 |
65 | master_doc = "index"
66 |
67 | # source_parsers = {'.md': CommonMarkParser}
68 | # source_suffix = ['.rst', '.md']
69 |
--------------------------------------------------------------------------------
/sphinx/data.rst:
--------------------------------------------------------------------------------
1 | Data
2 | ==================
3 |
4 | .. automodule:: quanttrader.data.backtest_data_feed
5 | :members:
6 |
7 | .. automodule:: quanttrader.data.data_board
8 | :members:
9 |
10 | .. automodule:: quanttrader.data.live_data_feed
11 | :members:
--------------------------------------------------------------------------------
/sphinx/event.rst:
--------------------------------------------------------------------------------
1 | Event
2 | ==================
3 |
4 | .. automodule:: quanttrader.event.backtest_event_engine
5 | :members:
6 |
7 | .. automodule:: quanttrader.event.live_event_engine
8 | :members:
--------------------------------------------------------------------------------
/sphinx/googleaa7b60d3069d75c3.html:
--------------------------------------------------------------------------------
1 | google-site-verification: googleaa7b60d3069d75c3.html
--------------------------------------------------------------------------------
/sphinx/gui.rst:
--------------------------------------------------------------------------------
1 | GUI
2 | ==================
3 |
4 | .. automodule:: quanttrader.gui.ui_account_window
5 | :members:
6 |
7 | .. automodule:: quanttrader.gui.ui_fill_window
8 | :members:
9 |
10 | .. automodule:: quanttrader.gui.ui_log_window
11 | :members:
12 |
13 | .. automodule:: quanttrader.gui.ui_order_window
14 | :members:
15 |
16 | .. automodule:: quanttrader.gui.ui_position_menu
17 | :members:
18 |
19 | .. automodule:: quanttrader.gui.ui_position_window
20 | :members:
21 |
22 | .. automodule:: quanttrader.gui.ui_risk_menu
23 | :members:
24 |
25 | .. automodule:: quanttrader.gui.ui_strategy_window
26 | :members:
27 |
28 | .. automodule:: quanttrader.gui.ui_trade_menu
29 | :members:
--------------------------------------------------------------------------------
/sphinx/index.rst:
--------------------------------------------------------------------------------
1 | Welcome to quanttrader documentation!
2 | =======================================
3 |
4 | **Pure Python Backtest and Live Trade Package for Quant Traders**
5 |
6 | .. toctree::
7 | :maxdepth: 2
8 | :caption: Contents
9 |
10 | introduction.md
11 | installation.md
12 | backtest.md
13 | livetrading.md
14 | instrument.md
15 | ordertype.md
16 |
17 | .. toctree::
18 | :maxdepth: 2
19 | :caption: Codes
20 |
21 | brokerage
22 | data
23 | event
24 | gui
25 | order
26 | performance
27 | position
28 | risk
29 | strategy
30 | tradingengine
31 |
32 | Indices and tables
33 | ==================
34 |
35 | * :ref:`genindex`
36 | * :ref:`modindex`
37 | * :ref:`search`
38 |
--------------------------------------------------------------------------------
/sphinx/installation.md:
--------------------------------------------------------------------------------
1 | ## Installation
2 |
3 | The quanttrader package is ready for pip install.
4 |
5 | ```python
6 | pip install quanttrader
7 | ```
8 |
9 | To use source code, git pull the repository or use [GitHub desktop](https://desktop.github.com/) and then add the project path to PYTHONPATH environment variable.
10 |
--------------------------------------------------------------------------------
/sphinx/instrument.md:
--------------------------------------------------------------------------------
1 | ## Instruments Supported
2 |
3 | | Instrument | Example |
4 | | ------------- |:-------------:|
5 | | Stock | AMZN STK SMART|
6 | | Forex | EURGBP CASH IDEALPRO|
7 | | Futures | ESM9 FUT GLOBEX|
8 | | Options on Stock | AAPL OPT 20201016 128.75 C SMART|
9 | | Options on Futures | ES FOP 20200911 3450 C 50 GLOBEX|
10 | | Comdty | XAUUSD CMDTY SMART|
11 | | Stock Combo | SPY,AAPL BAG 756733 1 SMART 265598 1 SMART SMART|
12 | | Option Comb | SPY BAG 398943121 1 SMART 398943218 1 SMART SMART|
13 | | Calendar Spread | CL BAG 174230608 1 NYMEX 174230606 1 NYMEX NYMEX|
14 | | Inter-Comdty Spread | CL.BZ BAG 174230606 1 NYMEX 162929662 1 NYMEX NYMEX|
--------------------------------------------------------------------------------
/sphinx/introduction.md:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | Welcome to quanttrader, a pure python-based event-driven backtest and live trading package for quant traders.
4 |
5 | In most cases, a backtest strategy can be directly used for live trade by simply switching to live brokerage. A control window is provided to monitor live trading sessions for each strategy separately and the portfolio as a whole.
6 |
7 | The source code is completely open-sourced [here on GitHub](https://github.com/letianzj/quanttrader). The package is published [here on pypi](https://pypi.org/project/quanttrader/) and is ready to be pip installed. The document is hosted [here on readthedocs](https://quanttrader.readthedocs.io/).
8 |
9 | This is NOT an ultra-low latency framework that can provide nano-second level executions. The response time, for example, between receiving data from the broker and sending out orders for a pairs-trading strategy that is subscribed to two stock feeds, is in the neighbourhood of milli-seconds. This package is designed mainly for quant traders who do not rely on market-making strategies.
10 |
11 | __Disclaimer: This is an open-source library that is free to use, free to contribute but use at OWN risk. It does NOT promise any future profits nor is responsible for any future loses.__
12 |
13 |
--------------------------------------------------------------------------------
/sphinx/livetrading.md:
--------------------------------------------------------------------------------
1 | ## Live Trading
2 |
3 | [This youtube video](https://t.co/rXdW8EIbWw?amp=1) and [accompanying document](https://letianzj.github.io/live-trading-ib-native-python.html) demonstrates step-by-step how to set up quanttrader for live trading. Currently quanttrader only supports Interactive Brokers.
4 |
5 | __Files used for live Trading are__
6 |
7 | * [live_engine.py](https://github.com/letianzj/quanttrader/blob/master/examples/live_engine.py) - the main entry point
8 |
9 | * [config_live.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/config_live.yaml) - config file for live session
10 |
11 | * [instrument_meta.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/instrument_meta.yaml) - meta data for instruments to be traded
12 |
13 | * [prepare_trading_session.yaml](https://github.com/letianzj/quanttrader/blob/master/examples/prepare_trading_session.py) - an example to demonstrate how to prepare data and strategy parameters before today's live session
14 |
--------------------------------------------------------------------------------
/sphinx/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/sphinx/order.rst:
--------------------------------------------------------------------------------
1 | Order
2 | ==================
3 | .. automodule:: quanttrader.order.order_manager
4 | :members:
--------------------------------------------------------------------------------
/sphinx/ordertype.md:
--------------------------------------------------------------------------------
1 | ## Orders Supported
2 |
3 | Basic order types. See [IB Doc](http://interactivebrokers.github.io/tws-api/basic_orders.html) for details.
4 |
5 | * Auction
6 | * Auction Limit
7 | * Market
8 | * Market If Touched
9 | * Market On Close
10 | * Market On Open
11 | * Market to Limit
12 | * Limit Order
13 | * Limit if Touched
14 | * Limit on Close
15 | * Limit on Open
16 | * Stop
17 | * Stop Limit
18 | * Trailing Stop
19 | * Trailing Stop Limit
20 |
--------------------------------------------------------------------------------
/sphinx/performance.rst:
--------------------------------------------------------------------------------
1 | Performance
2 | ==================
3 | .. automodule:: quanttrader.performance.performance_manager
4 | :members:
--------------------------------------------------------------------------------
/sphinx/position.rst:
--------------------------------------------------------------------------------
1 | Position
2 | ==================
3 | .. automodule:: quanttrader.position.position_manager
4 | :members:
--------------------------------------------------------------------------------
/sphinx/risk.rst:
--------------------------------------------------------------------------------
1 | Risk
2 | ==================
3 | .. automodule:: quanttrader.risk.risk_manager
4 | :members:
--------------------------------------------------------------------------------
/sphinx/strategy.rst:
--------------------------------------------------------------------------------
1 | Strategy
2 | ==================
3 |
4 | .. automodule:: quanttrader.strategy.strategy_base
5 | :members:
6 | :undoc-members:
7 |
8 | .. automodule:: quanttrader.strategy.strategy_manager
9 | :members:
10 | :undoc-members:
--------------------------------------------------------------------------------
/sphinx/tradingengine.rst:
--------------------------------------------------------------------------------
1 | Trading Engine
2 | ==================
3 |
4 | .. automodule:: quanttrader.gui.ui_main_window
5 | :members:
6 | :undoc-members:
7 |
8 | .. automodule:: quanttrader.backtest_engine
9 | :members:
10 | :undoc-members:
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | tests
3 | ~~~~~
4 |
5 | Test suite for the quanttrader package.
6 | """
7 |
--------------------------------------------------------------------------------
/tests/test_strats.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import os
4 | from datetime import datetime
5 |
6 | import pytz
7 |
8 | from quanttrader.backtest_engine import BacktestEngine
9 | from quanttrader.strategy.strategy_base import StrategyBase
10 | from quanttrader.util.util_func import read_ohlcv_csv
11 |
12 |
13 | class BuyAndHoldStrategy(StrategyBase):
14 | """
15 | buy on the first tick then hold to the end
16 | """
17 |
18 | def __init__(self) -> None:
19 | super(BuyAndHoldStrategy, self).__init__()
20 | self.invested = False
21 |
22 | def on_tick(self, tick_event):
23 | print(tick_event.timestamp)
24 | symbol = self.symbols[0]
25 | if not self.invested:
26 | df_hist = self._data_board.get_hist_price(symbol, tick_event.timestamp)
27 | close = df_hist.iloc[-1]["Close"]
28 | timestamp = df_hist.index[-1]
29 | target_size = int(self._position_manager.initial_capital / close)
30 | self.adjust_position(
31 | symbol, size_from=0, size_to=target_size, timestamp=timestamp
32 | )
33 | self.invested = True
34 |
35 |
36 | class TestBuyHold:
37 | def test_buyhold(self):
38 | df = read_ohlcv_csv(
39 | os.path.join(os.path.dirname(__file__), "test_data/TEST.csv")
40 | )
41 | init_capital = 100_000.0
42 | test_start_date = datetime(
43 | 2008, 1, 1, 8, 30, 0, 0, pytz.timezone("America/New_York")
44 | )
45 | test_end_date = datetime(
46 | 2008, 12, 31, 6, 0, 0, 0, pytz.timezone("America/New_York")
47 | )
48 | strategy = BuyAndHoldStrategy()
49 | strategy.set_capital(init_capital)
50 | strategy.set_symbols(["TTT"])
51 | # strategy.set_params(None)
52 |
53 | backtest_engine = BacktestEngine(test_start_date, test_end_date)
54 | backtest_engine.set_capital(
55 | init_capital
56 | ) # capital or portfolio >= capital for one strategy
57 | backtest_engine.add_data("TTT", df)
58 | backtest_engine.set_strategy(strategy)
59 | equity, df_positions, df_trades = backtest_engine.run()
60 | assert df_trades.shape[0] > 0
61 |
--------------------------------------------------------------------------------
/tick/20240618.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letianzj/quanttrader/224341d57e146aeaa143516049d2f37ff102dbf0/tick/20240618.txt
--------------------------------------------------------------------------------