├── .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 | [![pypi](https://img.shields.io/pypi/v/nseazy.svg)](https://pypi.python.org/pypi/quanttrader) 3 | [![python](https://img.shields.io/pypi/pyversions/nseazy.svg)](https://pypi.python.org/pypi/quanttrader) 4 | [![License Apache 2.0](https://badgen.net/badge/license/apache2.0/blue)](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 | ![gui](https://github.com/letianzj/quanttrader/blob/master/examples/gui.png) 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 --------------------------------------------------------------------------------