├── .gitignore ├── 1_数据获取 ├── DataStruct(QA_fetch_adv).ipynb ├── JQDATA.ipynb ├── JQDATA.md ├── QAFetch.ipynb ├── QA_FINANCIAL.ipynb └── 直接获取数据.ipynb ├── 2_类的测试与讲解 ├── QAACCOUNT 保证金冻结释放测试.ipynb ├── QAAccount.ipynb └── QAUSER.ipynb ├── 4_回测实盘交易 ├── Monitor.ipynb ├── QATTS_caitong_test.py ├── QATTS_caitong_with_QAMarket.ipynb ├── QA_MARKETENGINE.py ├── TEST_ACCOUNT_SELLOPEN_T0.ipynb └── 回测 │ ├── 期货回测 │ └── future_min_backtest.py │ ├── 股票回测 │ ├── 基于QAMARKET的回测 │ │ ├── backtest.py │ │ ├── minstrategy.py │ │ └── strategy.py │ ├── 多季度选股择时回测.py │ ├── 简易回测 │ │ ├── MACD_JCSC.py │ │ ├── simple_minbacktest.py │ │ └── simplebacktest.py │ └── 超级简化版回测 │ │ ├── MACD_JCSC.py │ │ ├── simple_minbacktest.py │ │ └── simplebacktest.py │ └── 股票日内交易回测 │ └── T0backtest.py ├── QAMARKET 相关 ├── MARKET.ipynb ├── QA_MARKETENGINE.ipynb ├── generate_trade.ipynb └── 期货账户测试.ipynb ├── config ├── install_ubuntu.sh ├── readme.md ├── run_backend.sh ├── startjupyter.sh ├── ubuntu16.sh ├── update_all.py ├── update_data.py ├── update_x.py └── windows_autojob_updatedata.md ├── readme.md ├── research ├── RNN_EXAMPLE │ ├── RNN-example_using_keras.ipynb │ └── RNN-example_using_keras.py ├── 一个VIX指标的实现.ipynb ├── 盘中涨停分析 │ ├── 盘中涨停_2018-07-13.ipynb │ └── 盘中涨停_2018-07-13.md └── 马科维茨有效前沿实现 │ ├── output_19_1.png │ ├── output_34_1.png │ ├── output_6_1.png │ ├── output_9_1.png │ ├── 马科维茨的QUANTAXIS实现.ipynb │ └── 马科维茨的QUANTAXIS实现.md ├── startjupyter.bat ├── startjupyter.sh └── test_backtest ├── FUTURE ├── TEST 期货的多空下单.ipynb ├── TEST_保证金账户.ipynb ├── test_开平仓.ipynb ├── 期货TEST.ipynb └── 期货分钟线回测.ipynb ├── MIN LEVEL SIMPLE BACKTEST.ipynb ├── PERFORMANCE.ipynb ├── PERFORMANCE.py ├── QAMARKET_SyncOrderExample.py ├── QUANTAXIS回测分析全过程讲解.ipynb ├── T0backtest.ipynb ├── T0backtest.py ├── TEST_ ORDER(stock+T0+Future).ipynb ├── TEST_MARKET_SETTLE.ipynb ├── TEST_MARKET_SETTLE.py ├── TEST_MULTI_ACCOUNT_INSERT_ORDER.ipynb ├── backtest_debug.py ├── example ├── indicator │ └── macd.py └── simple_backtest_day.py ├── make_order.md ├── strategy_qsdd.py ├── test_insert_orderspeed.py ├── test_开平仓_保证金.ipynb ├── 关于1.1.0的quantaxis的账户,市场,实盘模拟盘回测.ipynb └── 国产软件指数计算.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | # html file generate by QUANTAXIS 104 | *.html -------------------------------------------------------------------------------- /1_数据获取/JQDATA.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from jqdatasdk import *\n", 10 | "from pyecharts import Kline,Bar,Grid" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "首先我们先应JQDATA 的活动演示一下如何调用pyecharts 画图" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 3, 23 | "metadata": {}, 24 | "outputs": [ 25 | { 26 | "name": "stdout", 27 | "output_type": "stream", 28 | "text": [ 29 | "auth success\n" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "auth('acc','password')\n", 35 | "data=get_price('000001.XSHE')" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "先打印下 data\n", 43 | "我们可以看到 jqdata返回的格式是 一个单index的Dataframe" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 9, 49 | "metadata": {}, 50 | "outputs": [ 51 | { 52 | "data": { 53 | "text/html": [ 54 | "
\n", 55 | "\n", 68 | "\n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | "
openclosehighlowvolumemoney
2015-01-0510.5310.5510.7210.27434357784.04.565388e+09
2015-01-0610.4410.3910.7910.24328971478.03.453446e+09
2015-01-0710.2510.1910.4210.08258163619.02.634796e+09
2015-01-0810.219.8510.259.81213761656.02.128003e+09
2015-01-099.819.9310.459.69380916192.03.835378e+09
\n", 128 | "
" 129 | ], 130 | "text/plain": [ 131 | " open close high low volume money\n", 132 | "2015-01-05 10.53 10.55 10.72 10.27 434357784.0 4.565388e+09\n", 133 | "2015-01-06 10.44 10.39 10.79 10.24 328971478.0 3.453446e+09\n", 134 | "2015-01-07 10.25 10.19 10.42 10.08 258163619.0 2.634796e+09\n", 135 | "2015-01-08 10.21 9.85 10.25 9.81 213761656.0 2.128003e+09\n", 136 | "2015-01-09 9.81 9.93 10.45 9.69 380916192.0 3.835378e+09" 137 | ] 138 | }, 139 | "execution_count": 9, 140 | "metadata": {}, 141 | "output_type": "execute_result" 142 | } 143 | ], 144 | "source": [ 145 | "\n", 146 | "data.head()" 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "在画K线图的时候, 我们需要的是上下两个部分\n", 154 | "![](http://pic.yutiansut.com/jq.png)" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": 12, 160 | "metadata": {}, 161 | "outputs": [], 162 | "source": [ 163 | "\n", 164 | "# 因此我们初始化2个部分\n", 165 | "\n", 166 | "kline=Kline(width=1360, height=700, page_title='000001')\n", 167 | "\n", 168 | "bar = Bar()\n", 169 | "\n" 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "metadata": {}, 175 | "source": [ 176 | "然后我们需要对数据进行初步的处理:\n", 177 | "\n", 178 | "- 首先处理横坐标轴(时间轴)\n", 179 | "- 分别处理 价格轴/量轴" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": 13, 185 | "metadata": {}, 186 | "outputs": [], 187 | "source": [ 188 | "import numpy as np\n", 189 | "import pandas as pd\n", 190 | "\n", 191 | "# 做横轴的处理\n", 192 | "datetime = np.array(data.index.map(str))" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 15, 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [ 201 | "ohlc = np.array(data.loc[:, ['open', 'close', 'low', 'high']])\n", 202 | "vol = np.array(data.volume)" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "将数据加载到kline和bar中" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 17, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "kline.add('000001', datetime, ohlc, mark_point=[\n", 219 | " \"max\", \"min\"], is_datazoom_show=False, datazoom_orient='horizontal')\n", 220 | "\n", 221 | "bar.add('000001', datetime, vol,\n", 222 | " is_datazoom_show=True,\n", 223 | " datazoom_xaxis_index=[0, 1])" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": {}, 229 | "source": [ 230 | "使用Grid组合两个图" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 19, 236 | "metadata": {}, 237 | "outputs": [], 238 | "source": [ 239 | "grid = Grid(width=1360, height=700, page_title='QUANTAXIS')\n", 240 | "grid.add(bar, grid_top=\"80%\")\n", 241 | "grid.add(kline, grid_bottom=\"30%\")\n" 242 | ] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": 21, 247 | "metadata": {}, 248 | "outputs": [], 249 | "source": [ 250 | "grid.render('000001_plot.html')" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "使用 webbrowser 打开并渲染这个图\n", 258 | "![](http://pic.yutiansut.com/QQ%E6%88%AA%E5%9B%BE20181109203715.png)" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": 23, 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "data": { 268 | "text/plain": [ 269 | "True" 270 | ] 271 | }, 272 | "execution_count": 23, 273 | "metadata": {}, 274 | "output_type": "execute_result" 275 | } 276 | ], 277 | "source": [ 278 | "import webbrowser\n", 279 | "webbrowser.open('000001_plot.html')" 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "execution_count": 21, 285 | "metadata": {}, 286 | "outputs": [ 287 | { 288 | "data": { 289 | "text/plain": [ 290 | "'\\n以上是jqdata和pyecharts的结合, 不过QUANTAXIS已经对于这些进行了封装 只需要转化jqdata获取回来的数据为QADataStruct即可\\n'" 291 | ] 292 | }, 293 | "execution_count": 21, 294 | "metadata": {}, 295 | "output_type": "execute_result" 296 | } 297 | ], 298 | "source": [ 299 | "\"\"\"\n", 300 | "以上是jqdata和pyecharts的结合, 不过QUANTAXIS已经对于这些进行了封装 只需要转化jqdata获取回来的数据为QADataStruct即可\n", 301 | "\"\"\"" 302 | ] 303 | }, 304 | { 305 | "cell_type": "code", 306 | "execution_count": 22, 307 | "metadata": {}, 308 | "outputs": [], 309 | "source": [ 310 | "import QUANTAXIS as QA" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 23, 316 | "metadata": {}, 317 | "outputs": [], 318 | "source": [ 319 | "qads=QA.QAData.QA_DataStruct_Stock_day(data.assign(date=data.index,code='000001').set_index(['date','code']))" 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "execution_count": 24, 325 | "metadata": {}, 326 | "outputs": [ 327 | { 328 | "data": { 329 | "text/plain": [ 330 | "< QA_DataStruct_Stock_day with 1 securities >" 331 | ] 332 | }, 333 | "execution_count": 24, 334 | "metadata": {}, 335 | "output_type": "execute_result" 336 | } 337 | ], 338 | "source": [ 339 | "qads" 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 38, 345 | "metadata": {}, 346 | "outputs": [ 347 | { 348 | "name": "stderr", 349 | "output_type": "stream", 350 | "text": [ 351 | "QUANTAXIS>> The Pic has been saved to your path: .\\QA_stock_day_000001_bfq.html\n" 352 | ] 353 | } 354 | ], 355 | "source": [ 356 | "qads.plot('000001')" 357 | ] 358 | } 359 | ], 360 | "metadata": { 361 | "kernelspec": { 362 | "display_name": "Python 3", 363 | "language": "python", 364 | "name": "python3" 365 | }, 366 | "language_info": { 367 | "codemirror_mode": { 368 | "name": "ipython", 369 | "version": 3 370 | }, 371 | "file_extension": ".py", 372 | "mimetype": "text/x-python", 373 | "name": "python", 374 | "nbconvert_exporter": "python", 375 | "pygments_lexer": "ipython3", 376 | "version": "3.6.6" 377 | } 378 | }, 379 | "nbformat": 4, 380 | "nbformat_minor": 2 381 | } 382 | -------------------------------------------------------------------------------- /1_数据获取/JQDATA.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```python 4 | from jqdatasdk import * 5 | from pyecharts import Kline,Bar,Grid 6 | ``` 7 | 8 | 首先我们先应JQDATA 的活动演示一下如何调用pyecharts 画图 9 | 10 | 11 | ```python 12 | auth('acc','password') 13 | data=get_price('000001.XSHE') 14 | ``` 15 | 16 | auth success 17 | 18 | 19 | 先打印下 data 20 | 我们可以看到 jqdata返回的格式是 一个单index的Dataframe 21 | 22 | 23 | ```python 24 | 25 | data.head() 26 | ``` 27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
openclosehighlowvolumemoney
2015-01-0510.5310.5510.7210.27434357784.04.565388e+09
2015-01-0610.4410.3910.7910.24328971478.03.453446e+09
2015-01-0710.2510.1910.4210.08258163619.02.634796e+09
2015-01-0810.219.8510.259.81213761656.02.128003e+09
2015-01-099.819.9310.459.69380916192.03.835378e+09
93 |
94 | 95 | 96 | 97 | 在画K线图的时候, 我们需要的是上下两个部分 98 | ![](http://pic.yutiansut.com/jq.png) 99 | 100 | 101 | ```python 102 | 103 | # 因此我们初始化2个部分 104 | 105 | kline=Kline(width=1360, height=700, page_title='000001') 106 | 107 | bar = Bar() 108 | 109 | 110 | ``` 111 | 112 | 然后我们需要对数据进行初步的处理: 113 | 114 | - 首先处理横坐标轴(时间轴) 115 | - 分别处理 价格轴/量轴 116 | 117 | 118 | ```python 119 | import numpy as np 120 | import pandas as pd 121 | 122 | # 做横轴的处理 123 | datetime = np.array(data.index.map(str)) 124 | ``` 125 | 126 | 127 | ```python 128 | ohlc = np.array(data.loc[:, ['open', 'close', 'low', 'high']]) 129 | vol = np.array(data.volume) 130 | ``` 131 | 132 | 将数据加载到kline和bar中 133 | 134 | 135 | ```python 136 | kline.add('000001', datetime, ohlc, mark_point=[ 137 | "max", "min"], is_datazoom_show=False, datazoom_orient='horizontal') 138 | 139 | bar.add('000001', datetime, vol, 140 | is_datazoom_show=True, 141 | datazoom_xaxis_index=[0, 1]) 142 | ``` 143 | 144 | 使用Grid组合两个图 145 | 146 | 147 | ```python 148 | grid = Grid(width=1360, height=700, page_title='QUANTAXIS') 149 | grid.add(bar, grid_top="80%") 150 | grid.add(kline, grid_bottom="30%") 151 | 152 | ``` 153 | 154 | 155 | ```python 156 | grid.render('000001_plot.html') 157 | ``` 158 | 159 | 使用 webbrowser 打开并渲染这个图 160 | ![](http://pic.yutiansut.com/QQ%E6%88%AA%E5%9B%BE20181109203715.png) 161 | 162 | 163 | ```python 164 | import webbrowser 165 | webbrowser.open('000001_plot.html') 166 | ``` 167 | 168 | 169 | 170 | 171 | True 172 | 173 | 174 | 175 | 176 | ```python 177 | """ 178 | 以上是jqdata和pyecharts的结合, 不过QUANTAXIS已经对于这些进行了封装 只需要转化jqdata获取回来的数据为QADataStruct即可 179 | """ 180 | ``` 181 | 182 | 183 | 184 | 185 | '\n以上是jqdata和pyecharts的结合, 不过QUANTAXIS已经对于这些进行了封装 只需要转化jqdata获取回来的数据为QADataStruct即可\n' 186 | 187 | 188 | 189 | 190 | ```python 191 | import QUANTAXIS as QA 192 | ``` 193 | 194 | 195 | ```python 196 | qads=QA.QAData.QA_DataStruct_Stock_day(data.assign(date=data.index,code='000001').set_index(['date','code'])) 197 | ``` 198 | 199 | 200 | ```python 201 | qads 202 | ``` 203 | 204 | 205 | 206 | 207 | < QA_DataStruct_Stock_day with 1 securities > 208 | 209 | 210 | 211 | 212 | ```python 213 | qads.plot('000001') 214 | ``` 215 | 216 | QUANTAXIS>> The Pic has been saved to your path: .\QA_stock_day_000001_bfq.html 217 | 218 | -------------------------------------------------------------------------------- /2_类的测试与讲解/QAAccount.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# QAACCOUNT 账户类" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "QA_Account() 是quantaxis的核心类, 其作用是一个可以使用规则兼容各种市场的账户类\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## 调用方式" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 2, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "data": { 31 | "text/plain": [ 32 | "< QA_Account Acc_nPadcmUk market: stock_cn>" 33 | ] 34 | }, 35 | "execution_count": 2, 36 | "metadata": {}, 37 | "output_type": "execute_result" 38 | } 39 | ], 40 | "source": [ 41 | "import QUANTAXIS as QA\n", 42 | "QA.QA_Account()" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "## 参数详解" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# strategy_name=None,\n", 59 | "# user_cookie=None,\n", 60 | "# portfolio_cookie=None,\n", 61 | "# account_cookie=None,\n", 62 | "# market_type=MARKET_TYPE.STOCK_CN,\n", 63 | "# frequence=FREQUENCE.DAY,\n", 64 | "# broker=BROKER_TYPE.BACKETEST,\n", 65 | "# init_hold={},\n", 66 | "# init_cash=1000000,\n", 67 | "# commission_coeff=0.00025,\n", 68 | "# tax_coeff=0.001,\n", 69 | "# margin_level={},\n", 70 | "# allow_t0=False,\n", 71 | "# allow_sellopen=False,\n", 72 | "# allow_margin=False,\n", 73 | "# running_environment=RUNNING_ENVIRONMENT.BACKETEST" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "## 基于规则实例化\n", 81 | "\n", 82 | "基于不同市场的不同规则, 我们可以实例化不同的账户类\n", 83 | "\n", 84 | "- 允许保证金交易: allow_marigin = True\n", 85 | "\n", 86 | "- 允许买入后当日卖出: allow_t0 = True\n", 87 | "\n", 88 | "- 允许卖空开仓(裸卖空): allow_sellopen= True" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "### 股票普通账户" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "stock_account= QA.QA_Account(allow_t0=False,allow_margin=False,allow_sellopen=False,running_environment=QA.MARKET_TYPE.STOCK_CN)" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "### 股票融资融券账户" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "rzrq_account = QA.QA_Account(allow_t0=False,allow_margin=True,allow_sellopen=True,running_environment=QA.MARKET_TYPE.STOCK_CN)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "### 期货账户" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [ 136 | "future_account = QA.QA_Account(allow_t0=True,allow_margin=True,allow_sellopen=True, running_environment=QA.MARKET_TYPE.FUTURE_CN)" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "metadata": {}, 142 | "source": [ 143 | "### 期权账户" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "metadata": {}, 150 | "outputs": [], 151 | "source": [ 152 | "option_account = QA.QA_Account(allow_t0=True,allow_margin=True,allow_sellopen=True, running_environment=QA.MARKET_TYPE.OPTION_CN)" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "### 其他市场账户\n" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": null, 165 | "metadata": {}, 166 | "outputs": [], 167 | "source": [ 168 | "xxx = QA.QA_Account(allow_t0=True,allow_margin=True,allow_sellopen=True, running_environment=QA.MARKET_TYPE.CRYPTOCURRENCY)" 169 | ] 170 | }, 171 | { 172 | "cell_type": "markdown", 173 | "metadata": {}, 174 | "source": [ 175 | "## 账户的初始资金/初始仓位\n", 176 | "\n", 177 | "默认账户是无仓位, 默认现金 1000000 RMB\n" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": null, 183 | "metadata": {}, 184 | "outputs": [], 185 | "source": [ 186 | "stock_account.init_assets" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": null, 192 | "metadata": {}, 193 | "outputs": [], 194 | "source": [ 195 | "stock_account.init_cash" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": null, 201 | "metadata": {}, 202 | "outputs": [], 203 | "source": [ 204 | "stock_account.init_hold" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "metadata": {}, 210 | "source": [ 211 | "### 在实例化的时候初始化仓位信息\n", 212 | "\n", 213 | "使用json/dict的格式初始化 \n", 214 | "\n", 215 | "```python\n", 216 | "# init_hold参数\n", 217 | "init_hold={code1:amount1,code2:amount2}\n", 218 | "```\n", 219 | "\n", 220 | "实例化完 会显示在 account.hold中\n", 221 | "\n", 222 | "[注意] 在t+1的账户中, 初始化仓位依然可以当日交易" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": null, 228 | "metadata": {}, 229 | "outputs": [], 230 | "source": [ 231 | "stock_account= QA.QA_Account(init_hold={'000001':500}, allow_t0=False,allow_margin=False,allow_sellopen=False,running_environment=QA.MARKET_TYPE.STOCK_CN)" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "stock_account.init_assets" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": null, 246 | "metadata": {}, 247 | "outputs": [], 248 | "source": [ 249 | "stock_account.hold" 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": null, 255 | "metadata": {}, 256 | "outputs": [], 257 | "source": [ 258 | "stock_account.sell_available" 259 | ] 260 | }, 261 | { 262 | "cell_type": "markdown", 263 | "metadata": {}, 264 | "source": [ 265 | "### 在实例化的时候初始现金信息\n", 266 | "\n", 267 | "```python\n", 268 | "# init_cash 参数\n", 269 | "init_cash= 200000\n", 270 | "```\n" 271 | ] 272 | }, 273 | { 274 | "cell_type": "code", 275 | "execution_count": null, 276 | "metadata": {}, 277 | "outputs": [], 278 | "source": [ 279 | "stock_account= QA.QA_Account(init_cash= 200000,init_hold={'000002':500}, allow_t0=False,allow_margin=False,allow_sellopen=False,running_environment=QA.MARKET_TYPE.STOCK_CN)" 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "execution_count": null, 285 | "metadata": {}, 286 | "outputs": [], 287 | "source": [ 288 | "stock_account.init_assets" 289 | ] 290 | }, 291 | { 292 | "cell_type": "code", 293 | "execution_count": null, 294 | "metadata": {}, 295 | "outputs": [], 296 | "source": [ 297 | "stock_account.init_cash" 298 | ] 299 | }, 300 | { 301 | "cell_type": "code", 302 | "execution_count": null, 303 | "metadata": {}, 304 | "outputs": [], 305 | "source": [ 306 | "stock_account.cash" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": null, 312 | "metadata": {}, 313 | "outputs": [], 314 | "source": [ 315 | "stock_account.cash_available" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "### 在已经实例化的账户中修改现金/ 重置现金操作\n", 323 | "\n", 324 | "此操作无法撤销\n", 325 | "\n", 326 | "- 现金记录全部消除\n", 327 | "- 账户的持仓不会消除\n", 328 | "\n" 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": null, 334 | "metadata": {}, 335 | "outputs": [], 336 | "source": [ 337 | "stock_account.reset_assets(init_cash=50000)" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": null, 343 | "metadata": {}, 344 | "outputs": [], 345 | "source": [ 346 | "stock_account.init_assets" 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "execution_count": null, 352 | "metadata": {}, 353 | "outputs": [], 354 | "source": [ 355 | "stock_account.cash" 356 | ] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "execution_count": null, 361 | "metadata": {}, 362 | "outputs": [], 363 | "source": [ 364 | "stock_account.cash_available" 365 | ] 366 | }, 367 | { 368 | "cell_type": "markdown", 369 | "metadata": {}, 370 | "source": [ 371 | "## 买入/卖出操作\n", 372 | "\n", 373 | "有2种方式可以买入/卖出品种\n", 374 | "\n", 375 | "1. send_order 接口 + Order类调用receive_deal 接口\n", 376 | "2. receive_simpledeal 接口\n", 377 | "\n", 378 | "\n", 379 | "其中 \n", 380 | "- 1 是基于账户-发出订单- 订单成交回报的模式更新账户\n", 381 | "- 2 是直接修改账户的模式, 由用户自行确认和保证成交\n" 382 | ] 383 | }, 384 | { 385 | "cell_type": "markdown", 386 | "metadata": {}, 387 | "source": [ 388 | "### 订单/更新账户的模式\n", 389 | "\n", 390 | "在此我们只演示订单/成交, 至于order.trade怎么成交, 则是市场类/broker类的问题, 在此不去演示" 391 | ] 392 | }, 393 | { 394 | "cell_type": "markdown", 395 | "metadata": {}, 396 | "source": [ 397 | "#### 生成订单" 398 | ] 399 | }, 400 | { 401 | "cell_type": "code", 402 | "execution_count": null, 403 | "metadata": {}, 404 | "outputs": [], 405 | "source": [ 406 | "order=stock_account.send_order(code='000001',amount=100,time='2019-01-19',\n", 407 | " amount_model=QA.AMOUNT_MODEL.BY_AMOUNT,order_model=QA.ORDER_MODEL.CLOSE,\n", 408 | " price=10,towards=QA.ORDER_DIRECTION.BUY)" 409 | ] 410 | }, 411 | { 412 | "cell_type": "code", 413 | "execution_count": null, 414 | "metadata": {}, 415 | "outputs": [], 416 | "source": [ 417 | "future_order=future_account.send_order(code='RB1905',amount=100,time='2019-01-19',\n", 418 | " amount_model=QA.AMOUNT_MODEL.BY_AMOUNT,order_model=QA.ORDER_MODEL.CLOSE,\n", 419 | " price=3500,towards=QA.ORDER_DIRECTION.BUY_OPEN)" 420 | ] 421 | }, 422 | { 423 | "cell_type": "markdown", 424 | "metadata": {}, 425 | "source": [ 426 | "#### 订单类 QA_Order" 427 | ] 428 | }, 429 | { 430 | "cell_type": "code", 431 | "execution_count": null, 432 | "metadata": {}, 433 | "outputs": [], 434 | "source": [ 435 | "order" 436 | ] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "execution_count": null, 441 | "metadata": {}, 442 | "outputs": [], 443 | "source": [ 444 | "future_order" 445 | ] 446 | }, 447 | { 448 | "cell_type": "markdown", 449 | "metadata": {}, 450 | "source": [ 451 | "#### 订单交易(成交在Market/Broker中判断,此处只演示成交回报)" 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": null, 457 | "metadata": {}, 458 | "outputs": [], 459 | "source": [ 460 | "order.trade(trade_price=10.1,trade_amount=100,trade_id='example_trade1',trade_time='2019-01-19 15:00:00')" 461 | ] 462 | }, 463 | { 464 | "cell_type": "code", 465 | "execution_count": null, 466 | "metadata": {}, 467 | "outputs": [], 468 | "source": [ 469 | "future_order.trade(trade_price=3600,trade_amount=100,trade_id='example_trade2',trade_time='2019-01-19 21:00:00')" 470 | ] 471 | }, 472 | { 473 | "cell_type": "markdown", 474 | "metadata": {}, 475 | "source": [ 476 | "#### 账户成交表 QA_Account.history/QA_Account.history_table" 477 | ] 478 | }, 479 | { 480 | "cell_type": "code", 481 | "execution_count": null, 482 | "metadata": {}, 483 | "outputs": [], 484 | "source": [ 485 | "stock_account.history_table" 486 | ] 487 | }, 488 | { 489 | "cell_type": "code", 490 | "execution_count": null, 491 | "metadata": {}, 492 | "outputs": [], 493 | "source": [ 494 | "future_account.history_table" 495 | ] 496 | }, 497 | { 498 | "cell_type": "markdown", 499 | "metadata": {}, 500 | "source": [ 501 | "#### 账户现金表/ 期货账户还会冻结资金(保证金)" 502 | ] 503 | }, 504 | { 505 | "cell_type": "code", 506 | "execution_count": null, 507 | "metadata": {}, 508 | "outputs": [], 509 | "source": [ 510 | "stock_account.cash" 511 | ] 512 | }, 513 | { 514 | "cell_type": "code", 515 | "execution_count": null, 516 | "metadata": {}, 517 | "outputs": [], 518 | "source": [ 519 | "future_account.cash" 520 | ] 521 | }, 522 | { 523 | "cell_type": "code", 524 | "execution_count": null, 525 | "metadata": {}, 526 | "outputs": [], 527 | "source": [ 528 | "future_account.frozen" 529 | ] 530 | }, 531 | { 532 | "cell_type": "markdown", 533 | "metadata": {}, 534 | "source": [ 535 | "#### 账户可用现金" 536 | ] 537 | }, 538 | { 539 | "cell_type": "code", 540 | "execution_count": null, 541 | "metadata": {}, 542 | "outputs": [], 543 | "source": [ 544 | "stock_account.cash_available" 545 | ] 546 | }, 547 | { 548 | "cell_type": "code", 549 | "execution_count": null, 550 | "metadata": {}, 551 | "outputs": [], 552 | "source": [ 553 | "future_account.cash_available" 554 | ] 555 | }, 556 | { 557 | "cell_type": "markdown", 558 | "metadata": {}, 559 | "source": [ 560 | "#### 账户持仓" 561 | ] 562 | }, 563 | { 564 | "cell_type": "code", 565 | "execution_count": null, 566 | "metadata": {}, 567 | "outputs": [], 568 | "source": [ 569 | "stock_account.hold" 570 | ] 571 | }, 572 | { 573 | "cell_type": "code", 574 | "execution_count": null, 575 | "metadata": {}, 576 | "outputs": [], 577 | "source": [ 578 | "future_account.hold" 579 | ] 580 | }, 581 | { 582 | "cell_type": "markdown", 583 | "metadata": {}, 584 | "source": [ 585 | "#### 账户可卖余额(股票T+1 因此可卖部分不增加/ 期货账户 t+0 因此可卖部分增加)" 586 | ] 587 | }, 588 | { 589 | "cell_type": "code", 590 | "execution_count": null, 591 | "metadata": {}, 592 | "outputs": [], 593 | "source": [ 594 | "stock_account.sell_available" 595 | ] 596 | }, 597 | { 598 | "cell_type": "code", 599 | "execution_count": null, 600 | "metadata": {}, 601 | "outputs": [], 602 | "source": [ 603 | "future_account.sell_available" 604 | ] 605 | }, 606 | { 607 | "cell_type": "markdown", 608 | "metadata": {}, 609 | "source": [ 610 | "### 直接操作账户模式\n", 611 | "\n", 612 | "该模式直接操作账户" 613 | ] 614 | }, 615 | { 616 | "cell_type": "code", 617 | "execution_count": null, 618 | "metadata": {}, 619 | "outputs": [], 620 | "source": [ 621 | "stock_account.receive_simpledeal(code='000004',order_id='model2',realorder_id='model2_real',trade_id='trade2',trade_amount=1000,trade_price=16,trade_time='2019-01-21',trade_towards=QA.ORDER_DIRECTION.BUY,message='model2')" 622 | ] 623 | }, 624 | { 625 | "cell_type": "code", 626 | "execution_count": null, 627 | "metadata": {}, 628 | "outputs": [], 629 | "source": [ 630 | "stock_account.history_table" 631 | ] 632 | }, 633 | { 634 | "cell_type": "code", 635 | "execution_count": null, 636 | "metadata": {}, 637 | "outputs": [], 638 | "source": [ 639 | "stock_account.cash" 640 | ] 641 | }, 642 | { 643 | "cell_type": "code", 644 | "execution_count": null, 645 | "metadata": {}, 646 | "outputs": [], 647 | "source": [ 648 | "stock_account.cash_available" 649 | ] 650 | }, 651 | { 652 | "cell_type": "code", 653 | "execution_count": null, 654 | "metadata": {}, 655 | "outputs": [], 656 | "source": [ 657 | "stock_account.hold" 658 | ] 659 | }, 660 | { 661 | "cell_type": "code", 662 | "execution_count": null, 663 | "metadata": {}, 664 | "outputs": [], 665 | "source": [ 666 | "stock_account.sell_available" 667 | ] 668 | }, 669 | { 670 | "cell_type": "markdown", 671 | "metadata": {}, 672 | "source": [ 673 | "## 结算\n", 674 | "\n", 675 | "主要是股票账户的可卖股数的结算\n", 676 | "\n", 677 | "目前期货账户不采用逐日盯市的结算方式(及无结算价/无当日盈亏)" 678 | ] 679 | }, 680 | { 681 | "cell_type": "code", 682 | "execution_count": null, 683 | "metadata": {}, 684 | "outputs": [], 685 | "source": [ 686 | "stock_account.settle()" 687 | ] 688 | }, 689 | { 690 | "cell_type": "code", 691 | "execution_count": null, 692 | "metadata": {}, 693 | "outputs": [], 694 | "source": [ 695 | "stock_account.sell_available" 696 | ] 697 | }, 698 | { 699 | "cell_type": "code", 700 | "execution_count": null, 701 | "metadata": {}, 702 | "outputs": [], 703 | "source": [ 704 | "future_account.settle()" 705 | ] 706 | }, 707 | { 708 | "cell_type": "code", 709 | "execution_count": null, 710 | "metadata": {}, 711 | "outputs": [], 712 | "source": [ 713 | "## 关于账户存储和恢复" 714 | ] 715 | }, 716 | { 717 | "cell_type": "code", 718 | "execution_count": null, 719 | "metadata": {}, 720 | "outputs": [], 721 | "source": [] 722 | }, 723 | { 724 | "cell_type": "markdown", 725 | "metadata": {}, 726 | "source": [ 727 | "## 存储" 728 | ] 729 | }, 730 | { 731 | "cell_type": "code", 732 | "execution_count": null, 733 | "metadata": {}, 734 | "outputs": [], 735 | "source": [ 736 | "#stock_account.save()" 737 | ] 738 | }, 739 | { 740 | "cell_type": "code", 741 | "execution_count": null, 742 | "metadata": {}, 743 | "outputs": [], 744 | "source": [] 745 | }, 746 | { 747 | "cell_type": "code", 748 | "execution_count": null, 749 | "metadata": {}, 750 | "outputs": [], 751 | "source": [] 752 | }, 753 | { 754 | "cell_type": "code", 755 | "execution_count": null, 756 | "metadata": {}, 757 | "outputs": [], 758 | "source": [] 759 | }, 760 | { 761 | "cell_type": "code", 762 | "execution_count": null, 763 | "metadata": {}, 764 | "outputs": [], 765 | "source": [] 766 | } 767 | ], 768 | "metadata": { 769 | "kernelspec": { 770 | "display_name": "Python 3", 771 | "language": "python", 772 | "name": "python3" 773 | }, 774 | "language_info": { 775 | "codemirror_mode": { 776 | "name": "ipython", 777 | "version": 3 778 | }, 779 | "file_extension": ".py", 780 | "mimetype": "text/x-python", 781 | "name": "python", 782 | "nbconvert_exporter": "python", 783 | "pygments_lexer": "ipython3", 784 | "version": "3.6.7" 785 | }, 786 | "latex_envs": { 787 | "LaTeX_envs_menu_present": true, 788 | "autoclose": false, 789 | "autocomplete": true, 790 | "bibliofile": "biblio.bib", 791 | "cite_by": "apalike", 792 | "current_citInitial": 1, 793 | "eqLabelWithNumbers": true, 794 | "eqNumInitial": 1, 795 | "hotkeys": { 796 | "equation": "Ctrl-E", 797 | "itemize": "Ctrl-I" 798 | }, 799 | "labels_anchors": false, 800 | "latex_user_defs": false, 801 | "report_style_numbering": false, 802 | "user_envs_cfg": false 803 | }, 804 | "toc": { 805 | "base_numbering": 1, 806 | "nav_menu": {}, 807 | "number_sections": true, 808 | "sideBar": true, 809 | "skip_h1_title": false, 810 | "title_cell": "Table of Contents", 811 | "title_sidebar": "Contents", 812 | "toc_cell": false, 813 | "toc_position": {}, 814 | "toc_section_display": true, 815 | "toc_window_display": false 816 | }, 817 | "varInspector": { 818 | "cols": { 819 | "lenName": 16, 820 | "lenType": 16, 821 | "lenVar": 40 822 | }, 823 | "kernels_config": { 824 | "python": { 825 | "delete_cmd_postfix": "", 826 | "delete_cmd_prefix": "del ", 827 | "library": "var_list.py", 828 | "varRefreshCmd": "print(var_dic_list())" 829 | }, 830 | "r": { 831 | "delete_cmd_postfix": ") ", 832 | "delete_cmd_prefix": "rm(", 833 | "library": "var_list.r", 834 | "varRefreshCmd": "cat(var_dic_list()) " 835 | } 836 | }, 837 | "types_to_exclude": [ 838 | "module", 839 | "function", 840 | "builtin_function_or_method", 841 | "instance", 842 | "_Feature" 843 | ], 844 | "window_display": false 845 | } 846 | }, 847 | "nbformat": 4, 848 | "nbformat_minor": 2 849 | } 850 | -------------------------------------------------------------------------------- /4_回测实盘交易/Monitor.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "scrolled": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "#\n", 12 | "import datetime\n", 13 | "import QUANTAXIS as QA\n", 14 | "import time\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "market = QA.QA_Market(if_start_orderthreading=True)\n", 24 | "market.connect(QA.BROKER_TYPE.SHIPANE)\n", 25 | "market.start()\n", 26 | "haitong_acc = 'account:141'\n", 27 | "moni = 'account:1391'" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "market.connect(QA.BROKER_TYPE.BACKETEST)\n" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "#market.register('木偶',QA.QA_BacktestBroker())" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "#market.broker" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "#market.login('木偶', '睿瞳深邃')\n", 64 | "#market.login(QA.BROKER_TYPE.BACKETEST, 'account_2')" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "market.login(QA.BROKER_TYPE.SHIPANE, haitong_acc)" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "market.session" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": null, 88 | "metadata": {}, 89 | "outputs": [], 90 | "source": [ 91 | "market.get_account(haitong_acc).init_assets" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [ 100 | "market.login(QA.BROKER_TYPE.SHIPANE, moni)" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": null, 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [ 109 | "market.broker[QA.BROKER_TYPE.SHIPANE].query_orders(moni,'')" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "market._sync_orders()" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "market.sync_order_and_deal()" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [ 136 | "rx=market.get_account(moni)" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [ 145 | "rx" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": null, 151 | "metadata": {}, 152 | "outputs": [], 153 | "source": [ 154 | "rx.hold_table()" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": null, 160 | "metadata": {}, 161 | "outputs": [], 162 | "source": [ 163 | "rx.init_assets" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": null, 169 | "metadata": {}, 170 | "outputs": [], 171 | "source": [ 172 | "rx.cash" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "market.get_account_cookie()" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": null, 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "market.order_handler.order_status" 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": null, 196 | "metadata": {}, 197 | "outputs": [], 198 | "source": [ 199 | "market.order_handler.deal_status" 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": null, 205 | "metadata": {}, 206 | "outputs": [], 207 | "source": [] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": null, 212 | "metadata": {}, 213 | "outputs": [], 214 | "source": [] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": null, 219 | "metadata": {}, 220 | "outputs": [], 221 | "source": [] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": null, 226 | "metadata": {}, 227 | "outputs": [], 228 | "source": [] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": null, 233 | "metadata": {}, 234 | "outputs": [], 235 | "source": [ 236 | "res2 = market.insert_order(moni, code='601318', amount=1600, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT, order_model=QA.ORDER_MODEL.LIMIT,\n", 237 | " frequence=QA.FREQUENCE.CURRENT, broker_name=QA.BROKER_TYPE.SHIPANE, market_type=QA.MARKET_TYPE.STOCK_CN,\n", 238 | " towards=QA.ORDER_DIRECTION.BUY, price=0, time=datetime.datetime.now())\n", 239 | "\n" 240 | ] 241 | }, 242 | { 243 | "cell_type": "code", 244 | "execution_count": null, 245 | "metadata": {}, 246 | "outputs": [], 247 | "source": [ 248 | "rx.orders.order_list" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": null, 254 | "metadata": {}, 255 | "outputs": [], 256 | "source": [ 257 | "res2 = market.insert_order(moni, code='000001', amount=1000, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT, order_model=QA.ORDER_MODEL.LIMIT,\n", 258 | " frequence=QA.FREQUENCE.CURRENT, broker_name=QA.BROKER_TYPE.SHIPANE, market_type=QA.MARKET_TYPE.STOCK_CN,\n", 259 | " towards=QA.ORDER_DIRECTION.BUY, price=8.9, time=datetime.datetime.now())\n", 260 | "\n", 261 | "\n" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": null, 267 | "metadata": {}, 268 | "outputs": [], 269 | "source": [ 270 | "# res1= market.insert_order(moni, code='000001', amount=1450, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT, order_model=QA.ORDER_MODEL.LIMIT,\n", 271 | "# frequence=QA.FREQUENCE.CURRENT, broker_name=QA.BROKER_TYPE.SHIPANE, market_type=QA.MARKET_TYPE.STOCK_CN,\n", 272 | "# towards=QA.ORDER_DIRECTION.SELL, price=8.91, time=datetime.datetime.now())\n", 273 | "\n", 274 | "\n" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": null, 280 | "metadata": {}, 281 | "outputs": [], 282 | "source": [ 283 | "market.stop_sync_order_and_deal()" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": null, 289 | "metadata": {}, 290 | "outputs": [], 291 | "source": [ 292 | "market.sync_order_and_deal()" 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": null, 298 | "metadata": {}, 299 | "outputs": [], 300 | "source": [ 301 | "#market.order_handler.deal_status.loc['account:141','3112'].trade_id" 302 | ] 303 | }, 304 | { 305 | "cell_type": "code", 306 | "execution_count": null, 307 | "metadata": {}, 308 | "outputs": [], 309 | "source": [ 310 | "market.order_handler.order_status" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": null, 316 | "metadata": {}, 317 | "outputs": [], 318 | "source": [ 319 | "z=market.get_account(moni).history_table" 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "execution_count": null, 325 | "metadata": {}, 326 | "outputs": [], 327 | "source": [ 328 | "z=market.get_account(moni)" 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": null, 334 | "metadata": {}, 335 | "outputs": [], 336 | "source": [ 337 | "z.orders.order_list" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": null, 343 | "metadata": {}, 344 | "outputs": [], 345 | "source": [ 346 | "#order=market.order_handler.order_queue.pending[1]" 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "execution_count": null, 352 | "metadata": {}, 353 | "outputs": [], 354 | "source": [] 355 | }, 356 | { 357 | "cell_type": "code", 358 | "execution_count": null, 359 | "metadata": {}, 360 | "outputs": [], 361 | "source": [] 362 | }, 363 | { 364 | "cell_type": "code", 365 | "execution_count": null, 366 | "metadata": {}, 367 | "outputs": [], 368 | "source": [ 369 | "#order.transact_time" 370 | ] 371 | }, 372 | { 373 | "cell_type": "code", 374 | "execution_count": null, 375 | "metadata": {}, 376 | "outputs": [], 377 | "source": [ 378 | "# for index, deal in market.order_handler.deal_status.loc[order.account_cookie,order.realorder_id].iterrows():\n", 379 | "# order.trade(str(deal.trade_id),float(deal.trade_price),int(deal.trade_amount))" 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": null, 385 | "metadata": {}, 386 | "outputs": [], 387 | "source": [ 388 | "# for order in market.order_handler.order_queue.pending:\n", 389 | "# if order.realorder_id in market.order_handler.deal_status.index.levels[1]:\n", 390 | "# # 此时有成交推送(但可能是多条)\n", 391 | "# market.order_handler.deal_status.loc[order.account_cookie,order.realorder_id]\n" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": null, 397 | "metadata": {}, 398 | "outputs": [], 399 | "source": [ 400 | "# res1= market.insert_order(moni, code='600521', amount=1500, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT, order_model=QA.ORDER_MODEL.LIMIT,\n", 401 | "# frequence=QA.FREQUENCE.CURRENT, broker_name=QA.BROKER_TYPE.SHIPANE, market_type=QA.MARKET_TYPE.STOCK_CN,\n", 402 | "# towards=QA.ORDER_DIRECTION.SELL, price=19.82, time=datetime.datetime.now())\n", 403 | "\n", 404 | "\n" 405 | ] 406 | } 407 | ], 408 | "metadata": { 409 | "kernelspec": { 410 | "display_name": "Python 3", 411 | "language": "python", 412 | "name": "python3" 413 | }, 414 | "language_info": { 415 | "codemirror_mode": { 416 | "name": "ipython", 417 | "version": 3 418 | }, 419 | "file_extension": ".py", 420 | "mimetype": "text/x-python", 421 | "name": "python", 422 | "nbconvert_exporter": "python", 423 | "pygments_lexer": "ipython3", 424 | "version": "3.6.6" 425 | } 426 | }, 427 | "nbformat": 4, 428 | "nbformat_minor": 2 429 | } 430 | -------------------------------------------------------------------------------- /4_回测实盘交易/QATTS_caitong_test.py: -------------------------------------------------------------------------------- 1 | import QUANTAXIS as QA 2 | 3 | if __name__ == '__main__': 4 | api = QA.QA_TTSBroker() 5 | 6 | print("Check API Server, Ping...") 7 | result = api.ping() 8 | print("Check API Server, Result") 9 | print(result) 10 | 11 | if result["success"]: 12 | for i in (0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14, 15): 13 | print("---查询信息 cate=%d--" % i) 14 | print(api.data_to_df(api.query_data(i))) 15 | 16 | print('==============================下面是下单部分========================') 17 | print('即将演示的是 下单000001 数量100股 价格9.8 的限价单模式') 18 | 19 | if str(input('我已知晓, 并下单 按y继续 n 退出'))[0] == 'y': 20 | 21 | # 市价单可能需要开通权限 22 | # order_model=QA.ORDER_MODEL.LIMIT 限价单 23 | print( 24 | api.send_order( 25 | code='000001', 26 | price=1.0, 27 | amount=100, 28 | towards=QA.ORDER_DIRECTION.BUY, 29 | order_model=QA.ORDER_MODEL.LIMIT 30 | ) 31 | ) 32 | 33 | print("---登出---") 34 | print(api.logoff()) 35 | -------------------------------------------------------------------------------- /4_回测实盘交易/QATTS_caitong_with_QAMarket.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"source":"# Change directory to VSCode workspace root so that relative path loads work correctly. Turn this addition off with the DataScience.changeDirOnImportExport setting\r\nimport os\r\ntry:\r\n\tos.chdir(os.path.join(os.getcwd(), 'github\\ToBeQuanter'))\r\n\tprint(os.getcwd())\r\nexcept:\r\n\tpass\r\n","cell_type":"code","outputs":[],"metadata":{},"execution_count":0},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["import QUANTAXIS as QA\n","import datetime\n","\n","account = QA.QA_Account(\n"," user_cookie='tts',\n"," portfolio_cookie='tts',\n"," account_cookie='tts',\n"," broker=QA.BROKER_TYPE.TTS, \n"," running_environment=QA.RUNNING_ENVIRONMENT.TTS\n",")\n","\n",""]},{"cell_type":"code","execution_count":2,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"subscribe\n[<_MainThread(MainThread, started 17540)>, , , , , , , , , ]\n"}],"source":["market = QA.QA_Market(if_start_orderthreading=True)\n","market.connect(QA.BROKER_TYPE.TTS)\n","market.login(QA.BROKER_TYPE.TTS, account_cookie=account.account_cookie, account=account)\n","market.start()\n","\n",""]},{"cell_type":"code","execution_count":3,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"184707.03\n"}],"source":["print(market.query_cash(account.account_cookie))\n","\n",""]},{"cell_type":"code","execution_count":4,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"{'cash': 184707.03, 'hold': {'510050': 0.0, '510300': 0.0, '600612': 1200.0, '600886': 0.0, '002697': 5400.0}}\n"}],"source":["print(market.query_assets(account.account_cookie))\n","\n",""]},{"cell_type":"code","execution_count":5,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":" order_time code name towards trade_price \\\nrealorder_id \n11378 2019-04-02 10:12:55 002697 红旗连锁 1 0.000 \n12246 2019-04-02 10:23:13 510050 50ETF -1 0.000 \n12307 2019-04-02 10:23:44 510300 300ETF -1 0.000 \n12359 2019-04-02 10:24:21 002697 红旗连锁 1 0.000 \n12384 2019-04-02 10:24:39 600886 国投电力 -1 8.430 \n1256 2019-04-02 09:22:44 600886 国投电力 -1 0.000 \n1316 2019-04-02 09:23:40 510300 300ETF -1 0.000 \n1362 2019-04-02 09:24:03 510300 300ETF -1 0.000 \n13962 2019-04-02 10:48:20 510050 50ETF -1 0.000 \n14011 2019-04-02 10:49:10 510300 300ETF -1 3.956 \n14019 2019-04-02 10:49:17 510050 50ETF -1 2.863 \n1430 2019-04-02 09:24:32 510050 50ETF -1 0.000 \n1479 2019-04-02 09:24:54 510050 50ETF -1 0.000 \n1613 2019-04-02 09:26:05 002697 红旗连锁 1 5.800 \n1730 2019-04-02 09:27:12 002697 红旗连锁 1 5.740 \n1791 2019-04-02 09:27:40 002697 红旗连锁 1 0.000 \n24310 2019-04-02 14:53:22 002697 红旗连锁 1 0.000 \n2791 2019-04-02 09:32:27 002697 红旗连锁 1 5.790 \n\n order_price status order_amount trade_amount \\\nrealorder_id \n11378 5.680 cancel_all 2700.0 0.0 \n12246 2.889 cancel_all 7200.0 0.0 \n12307 3.988 cancel_all 5400.0 0.0 \n12359 5.680 cancel_all 2700.0 0.0 \n12384 8.430 success_all 2400.0 2400.0 \n1256 8.460 cancel_all 2400.0 0.0 \n1316 3.996 cancel_all 2700.0 0.0 \n1362 4.020 cancel_all 2700.0 0.0 \n13962 2.869 cancel_all 7200.0 0.0 \n14011 1.000 success_all 5400.0 5400.0 \n14019 1.000 success_all 7200.0 7200.0 \n1430 2.893 cancel_all 3600.0 0.0 \n1479 2.912 cancel_all 3600.0 0.0 \n1613 5.800 success_all 1800.0 1800.0 \n1730 5.740 success_all 1800.0 1800.0 \n1791 5.680 cancel_all 1800.0 0.0 \n24310 5.720 queued 2700.0 0.0 \n2791 5.800 success_all 1800.0 1800.0 \n\n cancel_amount \nrealorder_id \n11378 0 \n12246 0 \n12307 0 \n12359 0 \n12384 0 \n1256 0 \n1316 0 \n1362 0 \n13962 0 \n14011 0 \n14019 0 \n1430 0 \n1479 0 \n1613 0 \n1730 0 \n1791 0 \n24310 0 \n2791 0 \n"}],"source":["print(market.query_orders(account.account_cookie))\n",""]},{"cell_type":"code","execution_count":6,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"order_time 2019-04-02 10:24:39\ncode 600886\nname 国投电力\ntowards -1\ntrade_price 8.43\norder_price 8.43\nstatus success_all\norder_amount 2400\ntrade_amount 2400\ncancel_amount 0\nName: (tts, 12384), dtype: object\n"}],"source":["print(market.query_order(account.account_cookie, '12384'))\n",""]},{"cell_type":"code","execution_count":7,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"code\n002697 5400.0\n600612 1200.0\nName: amount, dtype: float64\n"}],"source":["print(market.query_position(account.account_cookie))\n",""]},{"cell_type":"code","execution_count":8,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":">-----------------------insert_order-----------------------------> QA_Market.insert_order\n100 by_amount 2019-04-02 16:35:22.004487 600825 1 LIMIT 1 None\nFAILED FOR CREATE ORDER tts failed\n< QA_Order realorder_id Order_CItwbsoq datetime:2019-04-02 09:31:00 code:600825 amount:100 price:1 towards:1 btype:stock_cn order_id:Order_CItwbsoq account:tts status:failed >\nfailed\n"}],"source":["market.insert_order(account_cookie=account.account_cookie, code='600825', amount=100, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT, order_model=QA.ORDER_MODEL.LIMIT,\n"," frequence=QA.FREQUENCE.CURRENT, broker_name=account.broker, market_type=account.market_type,\n"," towards=QA.ORDER_DIRECTION.BUY, price=1, time=datetime.datetime.now())\n",""]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"None\n"}],"source":["print(market.query_trade(account.account_cookie))\n","\n",""]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[],"source":""}],"nbformat":4,"nbformat_minor":2,"metadata":{"language_info":{"name":"python","codemirror_mode":{"name":"ipython","version":3}},"orig_nbformat":2,"file_extension":".py","mimetype":"text/x-python","name":"python","npconvert_exporter":"python","pygments_lexer":"ipython3","version":3}} -------------------------------------------------------------------------------- /4_回测实盘交易/QA_MARKETENGINE.py: -------------------------------------------------------------------------------- 1 | #%% Change working directory from the workspace root to the ipynb file location. Turn this addition off with the DataScience.changeDirOnImportExport setting 2 | import os 3 | try: 4 | os.chdir(os.path.join(os.getcwd(), 'EXAMPLE\QAMARKET 相关')) 5 | print(os.getcwd()) 6 | except: 7 | pass 8 | 9 | #%% 10 | import QUANTAXIS as QA 11 | import threading 12 | import pandas as pd 13 | 14 | 15 | #%% 16 | user = QA.QA_User(username='admin',password='940809x') 17 | portfolio = user.new_portfolio('example') 18 | # 创建两个account 19 | #这里是创建一个资产组合,然后在组合里面创建两个account 你可以想象成股票里面的两个策略账户 20 | #然后返回的是这个账户的id 21 | a_1 = portfolio.new_account(account_cookie='a1') 22 | a_2 = portfolio.new_account(account_cookie='a2') 23 | 24 | 25 | #%% 26 | a_1 27 | 28 | 29 | #%% 30 | """ 31 | 然后这里 是创建一个交易前置 你可以理解成 创建了一个无界面的通达信客户端 32 | 然后start()开启这个客户端 33 | 连接到backtest的broker上 这个broker可以更换 34 | """ 35 | # 创建一个交易前置 36 | market = QA.QA_Market() 37 | # 交易前置连接broker 38 | market.start() 39 | market.connect(QA.RUNNING_ENVIRONMENT.BACKETEST) 40 | 41 | # 打印market 42 | print(market) 43 | 44 | 45 | #%% 46 | 47 | """ 48 | 登陆到这个交易前置上 把你刚才的两个账户 49 | """ 50 | # 登陆交易 51 | market.login(QA.BROKER_TYPE.BACKETEST,a_1.account_cookie, a_1) 52 | market.login(QA.BROKER_TYPE.BACKETEST,a_2.account_cookie, a_2) 53 | # 打印市场中的交易账户 54 | print(market.get_account_cookie()) 55 | 56 | 57 | #%% 58 | #然后这里 往交易前置里面添加订单 这个操作是异步的 59 | 60 | 61 | #%% 62 | market.insert_order(account_cookie=a_1.account_cookie, money=100000, amount=None,price=None, amount_model=QA.AMOUNT_MODEL.BY_MONEY,time='2017-12-01', code='600010', 63 | order_model=QA.ORDER_MODEL.CLOSE, towards=QA.ORDER_DIRECTION.BUY,market_type=QA.MARKET_TYPE.STOCK_CN, 64 | frequence=QA.FREQUENCE.DAY,broker_name=QA.BROKER_TYPE.BACKETEST) 65 | 66 | 67 | #%% 68 | market.insert_order(account_cookie=a_1.account_cookie, amount=100,price=None, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT,time='2017-12-01', code='000001', 69 | order_model=QA.ORDER_MODEL.CLOSE, towards=QA.ORDER_DIRECTION.BUY,market_type=QA.MARKET_TYPE.STOCK_CN, 70 | frequence=QA.FREQUENCE.DAY,broker_name=QA.BROKER_TYPE.BACKETEST) 71 | 72 | 73 | #%% 74 | # 75 | """ 76 | 下单以后 现金不会减少 但是可用现金会被扣除 77 | 因为如果是市价单 你的成交价未定 78 | 没法直接减少现金 79 | 可用现金减少 cash不减少 等到settle 等到成功交易的时候 才会扣cash 80 | 81 | """ 82 | 83 | 84 | #%% 85 | market.session[a_1.account_cookie].cash_available 86 | 87 | 88 | #%% 89 | market.session[a_1.account_cookie].cash 90 | 91 | 92 | #%% 93 | """ 94 | 这里是交易前置内部的订单队列 95 | """ 96 | 97 | 98 | #%% 99 | market.order_handler.order_queue() 100 | 101 | 102 | 103 | 104 | #%% 105 | market.order_handler.order_queue.order_list 106 | 107 | 108 | #%% 109 | #pending 是指的待成交列表 110 | 111 | 112 | #%% 113 | market.order_handler.order_queue.pending 114 | 115 | 116 | #%% 117 | """ 118 | 这个_trade是一个私有方法 只有模拟盘和回测才会有 实盘就是真的交易了 119 | 这个_trade是backtest类去调用的 120 | 121 | """ 122 | #market._trade(QA.QA_Event(broker_name=QA.BROKER_TYPE.BACKETEST,after_success=None)) 123 | 124 | 125 | #%% 126 | """下面这两个是 查询 一个是异步查询 一个是同步的(no_wait) 127 | 异步不会阻塞当前线程 同步会阻塞""" 128 | 129 | 130 | #%% 131 | market.query_data(broker_name=QA.BROKER_TYPE.BACKETEST,frequence=QA.FREQUENCE.DAY,market_type=QA.MARKET_TYPE.STOCK_CN, 132 | code='600010',start='2017-12-01') 133 | 134 | 135 | #%% 136 | market.query_data_no_wait(broker_name=QA.BROKER_TYPE.BACKETEST,frequence=QA.FREQUENCE.DAY,market_type=QA.MARKET_TYPE.STOCK_CN, 137 | code='000001',start='2017-12-14') 138 | 139 | 140 | #%% 141 | """成交了以后 你可以看到账户的资产变化了""" 142 | market.session[a_1.account_cookie] 143 | 144 | 145 | #%% 146 | """待成交列表被清空""" 147 | 148 | 149 | #%% 150 | market.order_handler.order_queue.pending 151 | 152 | 153 | #%% 154 | """待成交队列清空""" 155 | 156 | 157 | #%% 158 | market.order_handler.order_queue.order_list 159 | 160 | 161 | #%% 162 | market.order_handler.order_queue() 163 | 164 | 165 | #%% 166 | """ 167 | cash 现金减少 168 | """ 169 | market.session[a_1.account_cookie].cash 170 | 171 | 172 | #%% 173 | """ 174 | 因为没有触发每日结算时间 在T+1的市场 即使买入了也没有可卖的 175 | """ 176 | market.session[a_1.account_cookie].sell_available 177 | 178 | 179 | #%% 180 | sa=market.session[a_1.account_cookie].sell_available 181 | 182 | 183 | #%% 184 | ac=market.session[a_1.account_cookie] 185 | 186 | 187 | #%% 188 | ac.hold 189 | 190 | 191 | #%% 192 | sa 193 | 194 | 195 | #%% 196 | market.session[a_1.account_cookie].history 197 | 198 | 199 | #%% 200 | """ 201 | 持仓表增加 202 | """ 203 | market.session[a_1.account_cookie].hold 204 | 205 | 206 | #%% 207 | """ 208 | 账户信息 209 | 210 | 可以看到 减少的资产 主要是因为收了手续费 211 | """ 212 | market.session[a_1.account_cookie].message 213 | 214 | 215 | #%% 216 | """结算事件""" 217 | market._settle(QA.BROKER_TYPE.BACKETEST) 218 | 219 | 220 | #%% 221 | """ 222 | 结算完以后 可卖数量就会变成和持仓数一样 223 | """ 224 | 225 | 226 | #%% 227 | market.session[a_1.account_cookie].hold 228 | 229 | 230 | #%% 231 | market.session[a_1.account_cookie].sell_available 232 | 233 | 234 | #%% 235 | """ 236 | 结算完以后 待成交队列也被清空 237 | """ 238 | 239 | 240 | #%% 241 | market.order_handler.order_queue() 242 | 243 | 244 | #%% 245 | market.insert_order(account_cookie=a_1.account_cookie, amount=market.session[a_1.account_cookie].sell_available.get('600010',0),price=None, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT,time='2017-12-05', code='600010', 246 | order_model=QA.ORDER_MODEL.CLOSE, towards=QA.ORDER_DIRECTION.SELL,market_type=QA.MARKET_TYPE.STOCK_CN, 247 | frequence=QA.FREQUENCE.DAY,broker_name=QA.BROKER_TYPE.BACKETEST) 248 | 249 | 250 | #%% 251 | market.order_handler.order_queue.order_list 252 | 253 | 254 | #%% 255 | market.order_handler.order_queue() 256 | 257 | 258 | #%% 259 | market.session[a_1.account_cookie].sell_available 260 | 261 | 262 | #%% 263 | #market._trade(QA.QA_Event(broker_name=QA.BROKER_TYPE.BACKETEST,after_success=None)) 264 | 265 | 266 | #%% 267 | market.session[a_1.account_cookie].cash 268 | 269 | 270 | #%% 271 | market.session[a_1.account_cookie].history 272 | 273 | 274 | #%% 275 | ac.save() 276 | 277 | 278 | -------------------------------------------------------------------------------- /4_回测实盘交易/TEST_ACCOUNT_SELLOPEN_T0.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "QUANTAXIS>> start QUANTAXIS\n", 13 | "QUANTAXIS>> Welcome to QUANTAXIS, the Version is 1.1.0\n", 14 | "QUANTAXIS>> \n", 15 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 16 | " ``########`````##````````##``````````##`````````####````````##```##########````````#``````##``````###```##`````######`` \n", 17 | " `##``````## ```##````````##`````````####````````##`##```````##```````##```````````###``````##````##`````##```##`````##` \n", 18 | " ##````````##```##````````##````````##`##````````##``##``````##```````##``````````####```````#```##``````##```##``````## \n", 19 | " ##````````##```##````````##```````##```##```````##```##`````##```````##`````````##`##```````##`##```````##````##``````` \n", 20 | " ##````````##```##````````##``````##`````##``````##````##````##```````##````````##``###```````###````````##`````##`````` \n", 21 | " ##````````##```##````````##``````##``````##`````##`````##```##```````##```````##````##```````###````````##``````###```` \n", 22 | " ##````````##```##````````##`````##````````##````##``````##``##```````##``````##``````##`````##`##```````##````````##``` \n", 23 | " ##````````##```##````````##````#############````##```````##`##```````##`````###########`````##``##``````##`````````##`` \n", 24 | " ###```````##```##````````##```##```````````##```##```````##`##```````##````##`````````##```##```##``````##```##`````##` \n", 25 | " `##``````###````##``````###``##`````````````##``##````````####```````##```##``````````##``###````##`````##````##`````## \n", 26 | " ``#########``````########```##``````````````###`##``````````##```````##``##````````````##`##``````##````##`````###``### \n", 27 | " ````````#####`````````````````````````````````````````````````````````````````````````````````````````````````````##`` \n", 28 | " ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 29 | " ``````````````````````````Copyright``yutiansut``2018``````QUANTITATIVE FINANCIAL FRAMEWORK````````````````````````````` \n", 30 | " ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 31 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 32 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 33 | " \n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "import QUANTAXIS as QA" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 2, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "account=QA.QA_Account(account_cookie='future_1',allow_t0=True,allow_sellopen=True)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 5, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "data": { 57 | "text/plain": [ 58 | "{'source': 'account',\n", 59 | " 'account_cookie': 'future_1',\n", 60 | " 'portfolio_cookie': None,\n", 61 | " 'user_cookie': None,\n", 62 | " 'broker': 'backtest',\n", 63 | " 'market_type': 'stock_cn',\n", 64 | " 'strategy_name': None,\n", 65 | " 'current_time': 'None',\n", 66 | " 'allow_sellopen': True,\n", 67 | " 'allow_t0': True,\n", 68 | " 'margin_level': False,\n", 69 | " 'init_assets': {'cash': 1000000, 'hold': {}},\n", 70 | " 'commission_coeff': 0.00025,\n", 71 | " 'tax_coeff': 0.0015,\n", 72 | " 'cash': [1000000],\n", 73 | " 'history': [],\n", 74 | " 'trade_index': [],\n", 75 | " 'running_time': '2018-08-23 09:54:14.005020',\n", 76 | " 'quantaxis_version': '1.1.0',\n", 77 | " 'running_environment': 'backtest'}" 78 | ] 79 | }, 80 | "execution_count": 5, 81 | "metadata": {}, 82 | "output_type": "execute_result" 83 | } 84 | ], 85 | "source": [ 86 | "account.message" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 9, 92 | "metadata": {}, 93 | "outputs": [ 94 | { 95 | "data": { 96 | "text/plain": [ 97 | "< QA_Order realorder_id Order_pgXJEKQY datetime:2018-08-23 09:31:00 code:RB1810 amount:1000 price:800 towards:-1 btype:stock_cn order_id:Order_pgXJEKQY account:future_1 status:queued >" 98 | ] 99 | }, 100 | "execution_count": 9, 101 | "metadata": {}, 102 | "output_type": "execute_result" 103 | } 104 | ], 105 | "source": [ 106 | "account.send_order('RB1810',amount=1000,time='2018-08-23 9:50:00',towards=QA.ORDER_DIRECTION.SELL_OPEN,price=800,order_model=QA.ORDER_MODEL.LIMIT,amount_model=QA.AMOUNT_MODEL.BY_AMOUNT)" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 15, 112 | "metadata": {}, 113 | "outputs": [ 114 | { 115 | "data": { 116 | "text/html": [ 117 | "
\n", 118 | "\n", 131 | "\n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | "
datetimeactive1active2last_closecodeopenhighlowpricecur_vol...bid3bid_vol3ask4ask_vol4bid4bid_vol4ask5ask_vol5bid5bid_vol5
code
0000012018-08-23 10:09:40.7169737707709.290000019.39.429.39.3470...9.3118659.3719679.322829.3827409.293788
\n", 209 | "

1 rows × 33 columns

\n", 210 | "
" 211 | ], 212 | "text/plain": [ 213 | " datetime active1 active2 last_close code open \\\n", 214 | "code \n", 215 | "000001 2018-08-23 10:09:40.716973 770 770 9.29 000001 9.3 \n", 216 | "\n", 217 | " high low price cur_vol ... bid3 bid_vol3 ask4 ask_vol4 \\\n", 218 | "code ... \n", 219 | "000001 9.42 9.3 9.34 70 ... 9.31 1865 9.37 1967 \n", 220 | "\n", 221 | " bid4 bid_vol4 ask5 ask_vol5 bid5 bid_vol5 \n", 222 | "code \n", 223 | "000001 9.3 2282 9.38 2740 9.29 3788 \n", 224 | "\n", 225 | "[1 rows x 33 columns]" 226 | ] 227 | }, 228 | "execution_count": 15, 229 | "metadata": {}, 230 | "output_type": "execute_result" 231 | } 232 | ], 233 | "source": [ 234 | "QA.QA_fetch_get_stock_realtime('tdx','000001')" 235 | ] 236 | } 237 | ], 238 | "metadata": { 239 | "kernelspec": { 240 | "display_name": "Python 3", 241 | "language": "python", 242 | "name": "python3" 243 | }, 244 | "language_info": { 245 | "codemirror_mode": { 246 | "name": "ipython", 247 | "version": 3 248 | }, 249 | "file_extension": ".py", 250 | "mimetype": "text/x-python", 251 | "name": "python", 252 | "nbconvert_exporter": "python", 253 | "pygments_lexer": "ipython3", 254 | "version": "3.6.6" 255 | } 256 | }, 257 | "nbformat": 4, 258 | "nbformat_minor": 2 259 | } 260 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/期货回测/future_min_backtest.py: -------------------------------------------------------------------------------- 1 | # %% Change working directory from the workspace root to the ipynb file location. Turn this addition off with the DataScience.changeDirOnImportExport setting 2 | import os 3 | try: 4 | os.chdir(os.path.join(os.getcwd(), 'EXAMPLE\test_backtest\FUTURE')) 5 | print(os.getcwd()) 6 | except: 7 | pass 8 | 9 | # %% 10 | import QUANTAXIS as QA 11 | import sys 12 | 13 | 14 | # %% 15 | user = QA.QA_User(username='quantaxis', password='quantaxis') 16 | portfolio = user.new_portfolio('qatestportfolio') 17 | Account = portfolio.new_account(allow_sellopen=True, allow_margin=True, init_cash=5000, allow_t0=True, 18 | account_cookie='future_test', market_type=QA.MARKET_TYPE.FUTURE_CN, frequence=QA.FREQUENCE.FIFTEEN_MIN) 19 | 20 | 21 | # %% 22 | Broker = QA.QA_BacktestBroker() 23 | 24 | 25 | # %% 26 | rb_ds = QA.QA_fetch_future_min_adv( 27 | 'RBL8', '2018-01-01', '2018-08-28', frequence='15min') 28 | 29 | 30 | # %% 31 | import numpy as np 32 | import pandas as pd 33 | 34 | 35 | def MACD_JCSC(dataframe, SHORT=12, LONG=26, M=9): 36 | """ 37 | 1.DIF向上突破DEA,买入信号参考。 38 | 2.DIF向下跌破DEA,卖出信号参考。 39 | """ 40 | CLOSE = dataframe.close 41 | DIFF = QA.EMA(CLOSE, SHORT) - QA.EMA(CLOSE, LONG) 42 | DEA = QA.EMA(DIFF, M) 43 | MACD = 2*(DIFF-DEA) 44 | 45 | CROSS_JC = QA.CROSS(DIFF, DEA) 46 | CROSS_SC = QA.CROSS(DEA, DIFF) 47 | ZERO = 0 48 | return pd.DataFrame({'DIFF': DIFF, 'DEA': DEA, 'MACD': MACD, 'CROSS_JC': CROSS_JC, 'CROSS_SC': CROSS_SC, 'ZERO': ZERO}) 49 | 50 | 51 | ind = rb_ds.add_func(MACD_JCSC) 52 | 53 | 54 | # %% 55 | _date = None 56 | for items in rb_ds.panel_gen: 57 | if _date != items.date[0]: 58 | print('try to settle') 59 | _date = items.date[0] 60 | Account.settle() 61 | 62 | for item in items.security_gen: 63 | daily_ind = ind.loc[item.index] 64 | if daily_ind.CROSS_JC.iloc[0] > 0: 65 | order = Account.send_order( 66 | code=item.code[0], 67 | time=item.datetime[0], 68 | amount=1, 69 | towards=QA.ORDER_DIRECTION.BUY_OPEN, 70 | price=0, 71 | order_model=QA.ORDER_MODEL.CLOSE, 72 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 73 | ) 74 | 75 | if order: 76 | print(order) 77 | print(item) 78 | Broker.receive_order(QA.QA_Event( 79 | order=order, market_data=item)) 80 | 81 | trade_mes = Broker.query_orders( 82 | Account.account_cookie, 'filled') 83 | res = trade_mes.loc[order.account_cookie, order.realorder_id] 84 | order.trade(res.trade_id, res.trade_price, 85 | res.trade_amount, res.trade_time) 86 | elif daily_ind.CROSS_SC.iloc[0] > 0: 87 | if Account.sell_available.get(item.code[0], 0) > 0: 88 | order = Account.send_order( 89 | code=item.code[0], 90 | time=item.datetime[0], 91 | amount=Account.sell_available.get(item.code[0], 0), 92 | towards=QA.ORDER_DIRECTION.SELL_CLOSE, 93 | price=0, 94 | order_model=QA.ORDER_MODEL.MARKET, 95 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 96 | ) 97 | if order: 98 | Broker.receive_order(QA.QA_Event( 99 | order=order, market_data=item)) 100 | 101 | trade_mes = Broker.query_orders( 102 | Account.account_cookie, 'filled') 103 | res = trade_mes.loc[order.account_cookie, 104 | order.realorder_id] 105 | order.trade(res.trade_id, res.trade_price, 106 | res.trade_amount, res.trade_time) 107 | Account.settle() 108 | 109 | 110 | # %% 111 | Risk = QA.QA_Risk(Account) 112 | 113 | 114 | # %% 115 | Risk.plot_assets_curve() 116 | 117 | 118 | # %% 119 | Risk.profit_construct 120 | 121 | 122 | Account.save() 123 | Risk.save() 124 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/基于QAMARKET的回测/backtest.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | from QUANTAXIS.QAARP.QARisk import QA_Risk 27 | from QUANTAXIS.QAARP.QAUser import QA_User 28 | from QUANTAXIS.QAApplication.QABacktest import QA_Backtest 29 | from QUANTAXIS.QAUtil.QALogs import QA_util_log_info 30 | from QUANTAXIS.QAUtil.QAParameter import FREQUENCE, MARKET_TYPE 31 | from minstrategy import MAMINStrategy 32 | from strategy import MAStrategy 33 | 34 | 35 | class Backtest(QA_Backtest): 36 | ''' 37 | 多线程模式回测示例 38 | 39 | ''' 40 | 41 | def __init__(self, market_type, frequence, start, end, code_list, commission_fee): 42 | super().__init__(market_type, frequence, start, end, code_list, commission_fee) 43 | mastrategy = MAStrategy(user_cookie=self.user.user_cookie, portfolio_cookie= self.portfolio.portfolio_cookie, account_cookie= 'mastrategy') 44 | #maminstrategy = MAMINStrategy() 45 | self.account = self.portfolio.add_account(mastrategy) 46 | 47 | def after_success(self): 48 | QA_util_log_info(self.account.history_table) 49 | risk = QA_Risk(self.account, benchmark_code='000300', 50 | benchmark_type=MARKET_TYPE.INDEX_CN) 51 | 52 | print(risk().T) 53 | fig=risk.plot_assets_curve() 54 | fig.show() 55 | fig=risk.plot_dailyhold() 56 | fig.show() 57 | fig=risk.plot_signal() 58 | fig.show() 59 | self.account.save() 60 | risk.save() 61 | 62 | 63 | def run_daybacktest(): 64 | import QUANTAXIS as QA 65 | backtest = Backtest(market_type=MARKET_TYPE.STOCK_CN, 66 | frequence=FREQUENCE.DAY, 67 | start='2017-01-01', 68 | end='2017-02-10', 69 | code_list=QA.QA_fetch_stock_block_adv().code[0:5], 70 | commission_fee=0.00015) 71 | print(backtest.account) 72 | backtest.start_market() 73 | 74 | backtest.run() 75 | backtest.stop() 76 | 77 | 78 | def run_minbacktest(): 79 | import QUANTAXIS as QA 80 | backtest = Backtest(market_type=MARKET_TYPE.STOCK_CN, 81 | frequence=FREQUENCE.FIFTEEN_MIN, 82 | start='2017-11-01', 83 | end='2017-11-10', 84 | code_list=QA.QA_fetch_stock_block_adv().code[0:5], 85 | commission_fee=0.00015) 86 | backtest.start_market() 87 | 88 | backtest.run() 89 | backtest.stop() 90 | 91 | 92 | if __name__ == '__main__': 93 | run_daybacktest() 94 | #run_minbacktest() 95 | 96 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/基于QAMARKET的回测/minstrategy.py: -------------------------------------------------------------------------------- 1 | # utf-8 2 | from QUANTAXIS.QAARP.QAStrategy import QA_Strategy 3 | from QUANTAXIS.QAUtil.QAParameter import (AMOUNT_MODEL, MARKET_TYPE, 4 | FREQUENCE, ORDER_DIRECTION, 5 | ORDER_MODEL) 6 | 7 | 8 | class MAMINStrategy(QA_Strategy): 9 | def __init__(self): 10 | super().__init__() 11 | self.frequence = FREQUENCE.FIFTEEN_MIN 12 | self.market_type = MARKET_TYPE.STOCK_CN 13 | 14 | def on_bar(self, event): 15 | try: 16 | # 新数据推送进来 17 | for item in event.market_data.code: 18 | # 如果持仓 19 | if self.sell_available.get(item, 0) > 0: 20 | # 全部卖出 21 | event.send_order(account_cookie=self.account_cookie, 22 | amount=self.sell_available[item], amount_model=AMOUNT_MODEL.BY_AMOUNT, 23 | time=self.current_time, code=item, price=0, 24 | order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.SELL, 25 | market_type=self.market_type, frequence=self.frequence, 26 | broker_name=self.broker 27 | ) 28 | else: # 如果不持仓 29 | # 买入1000股 30 | event.send_order(account_cookie=self.account_cookie, 31 | amount=100, amount_model=AMOUNT_MODEL.BY_AMOUNT, 32 | time=self.current_time, code=item, price=0, 33 | order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.BUY, 34 | market_type=self.market_type, frequence=self.frequence, 35 | broker_name=self.broker) 36 | except: 37 | pass 38 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/基于QAMARKET的回测/strategy.py: -------------------------------------------------------------------------------- 1 | # utf-8 2 | import time 3 | import threading 4 | from QUANTAXIS.QAARP.QAAccount import QA_Account 5 | from QUANTAXIS.QAUtil.QALogs import QA_util_log_info 6 | from QUANTAXIS.QAUtil.QAParameter import (AMOUNT_MODEL, FREQUENCE, MARKET_TYPE, 7 | ORDER_DIRECTION, ORDER_MODEL) 8 | 9 | 10 | class MAStrategy(QA_Account): 11 | def __init__(self, user_cookie, portfolio_cookie, account_cookie, init_cash=100000, init_hold={}): 12 | super().__init__(user_cookie=user_cookie, portfolio_cookie=portfolio_cookie, account_cookie= account_cookie, 13 | init_cash=init_cash, init_hold=init_hold) 14 | self.frequence = FREQUENCE.DAY 15 | self.market_type = MARKET_TYPE.STOCK_CN 16 | self.commission_coeff = 0.00015 17 | self.tax_coeff = 0.0001 18 | self.reset_assets(100000) # 这是第二种修改办法 19 | 20 | def on_bar(self, event): 21 | print(threading.enumerate()) 22 | sellavailable = self.sell_available 23 | try: 24 | for item in event.market_data.code: 25 | if sellavailable.get(item, 0) > 0: 26 | event.send_order(account_cookie=self.account_cookie, 27 | amount=sellavailable[item], amount_model=AMOUNT_MODEL.BY_AMOUNT, 28 | time=self.current_time, code=item, price=0, 29 | order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.SELL, 30 | market_type=self.market_type, frequence=self.frequence, 31 | broker_name=self.broker 32 | ) 33 | else: 34 | event.send_order(account_cookie=self.account_cookie, 35 | amount=100, amount_model=AMOUNT_MODEL.BY_AMOUNT, 36 | time=self.current_time, code=item, price=0, 37 | order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.BUY, 38 | market_type=self.market_type, frequence=self.frequence, 39 | broker_name=self.broker) 40 | 41 | except Exception as e: 42 | print(e) 43 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/多季度选股择时回测.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | import QUANTAXIS as QA 27 | import random 28 | """ 29 | 单线程模式回测示例 30 | 该代码旨在给出一个极其容易实现的小回测 高效 无事件驱动 31 | """ 32 | Broker = QA.QA_BacktestBroker() 33 | User = QA.QA_User(username='quantaxis', password='quantaxis') 34 | Portfolio = User.new_portfolio('qatestportfolio') 35 | AC = Portfolio.new_account(account_cookie='supersimple', init_cash=200000) 36 | """ 37 | # 账户设置初始资金 38 | AC.reset_assets(assets) 39 | 40 | # 发送订单 41 | Order=AC.send_order(code='000001',amount=1000,time='2018-03-21',towards=QA.ORDER_DIRECTION.BUY,price=0,order_model=QA.ORDER_MODEL.MARKET,amount_model=QA.AMOUNT_MODEL.BY_AMOUNT) 42 | # 撮合订单 43 | B.receive_order(QA.QA_Event(order=Order,market_data=data)) 44 | 45 | # 查询账户的订单状态 46 | trade_mes=Broker.query_orders(AC.account_cookie, 'filled') 47 | res=trade_mes.loc[order.account_cookie, order.realorder_id] 48 | 49 | # 更新订单 50 | 51 | order.trade(res.trade_id, res.trade_price,res.trade_amount, res.trade_time) 52 | 53 | # 查询订单的状态 54 | 55 | order.status 56 | 57 | 58 | # 分析结果 59 | 60 | risk=QA.QA_Risk(AC) 61 | 62 | """ 63 | 64 | QA.QA_SU_save_strategy('test','test_day',AC.account_cookie,if_save=True) 65 | 66 | 67 | def select_code(report_date): 68 | QA.QA_fetch_financial_report 69 | 70 | def simple_backtest(AC, code, start, end): 71 | DATA = QA.QA_fetch_stock_day_adv(code, start, end).to_qfq() 72 | for items in DATA.panel_gen: # 一天过去了 73 | 74 | for item in items.security_gen: 75 | if random.random() > 0.5: # 加入一个随机 模拟买卖的 76 | if AC.sell_available.get(item.code[0], 0) == 0: 77 | order = AC.send_order( 78 | code=item.code[0], time=item.date[0], amount=1000, towards=QA.ORDER_DIRECTION.BUY, price=0, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 79 | ) 80 | if order: 81 | order.trade('unknownTrade', order.price, 82 | order.amount, order.datetime) 83 | 84 | else: 85 | order = AC.send_order( 86 | code=item.code[0], time=item.date[0], amount=1000, towards=QA.ORDER_DIRECTION.SELL, price=0, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 87 | ) 88 | if order: 89 | order.trade('unknownTrade', order.price, 90 | order.amount, order.datetime) 91 | AC.settle() 92 | 93 | # 先选股 94 | code = select_code('2012-03') 95 | 96 | simple_backtest(AC, QA.QA_fetch_stock_block_adv( 97 | ).code, '2012-01-01', '2012-03-31') 98 | 99 | code = select_code('2012-06') 100 | 101 | simple_backtest(AC, QA.QA_fetch_stock_block_adv( 102 | ).code, '2012-04-01', '2012-06-30') 103 | 104 | 105 | print(AC.message) 106 | AC.save() 107 | risk = QA.QA_Risk(AC) 108 | print(risk.message) 109 | risk.save() -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/简易回测/MACD_JCSC.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Demo: MACD strategy 3 | # src: ./test_backtest/MACD_JCSC.py 4 | # jupyter: ./test_backtest/QUANTAXIS回测分析全过程讲解.ipynb 5 | # paper: ./test_backtest/QUANTAXIS回测分析全过程讲解.md 6 | 7 | import QUANTAXIS as QA 8 | import numpy as np 9 | import pandas as pd 10 | import datetime 11 | st1 = datetime.datetime.now() 12 | # define the MACD strategy 13 | 14 | 15 | def MACD_JCSC(dataframe, SHORT=12, LONG=26, M=9): 16 | """ 17 | 1.DIF向上突破DEA,买入信号参考。 18 | 2.DIF向下跌破DEA,卖出信号参考。 19 | """ 20 | CLOSE = dataframe.close 21 | DIFF = QA.EMA(CLOSE, SHORT) - QA.EMA(CLOSE, LONG) 22 | DEA = QA.EMA(DIFF, M) 23 | MACD = 2*(DIFF-DEA) 24 | 25 | CROSS_JC = QA.CROSS(DIFF, DEA) 26 | CROSS_SC = QA.CROSS(DEA, DIFF) 27 | ZERO = 0 28 | return pd.DataFrame({'DIFF': DIFF, 'DEA': DEA, 'MACD': MACD, 'CROSS_JC': CROSS_JC, 'CROSS_SC': CROSS_SC, 'ZERO': ZERO}) 29 | 30 | 31 | # create account 32 | user = QA.QA_User(username='quantaxis', password='quantaxis') 33 | portfolio = user.new_portfolio('qatestportfolio') 34 | 35 | 36 | Account = portfolio.new_account(account_cookie='macd_stock', init_cash=1000000) 37 | Broker = QA.QA_BacktestBroker() 38 | 39 | 40 | QA.QA_SU_save_strategy('MACD_JCSC', 'Indicator', 41 | Account.account_cookie, if_save=True) 42 | # get data from mongodb 43 | data = QA.QA_fetch_stock_day_adv( 44 | ['000001', '000002', '000004', '600000'], '2017-09-01', '2018-05-20') 45 | data = data.to_qfq() 46 | 47 | # add indicator 48 | ind = data.add_func(MACD_JCSC) 49 | # ind.xs('000001',level=1)['2018-01'].plot() 50 | 51 | data_forbacktest = data.select_time('2018-01-01', '2018-05-01') 52 | 53 | 54 | for items in data_forbacktest.panel_gen: 55 | for item in items.security_gen: 56 | daily_ind = ind.loc[item.index] 57 | 58 | if daily_ind.CROSS_JC.iloc[0] > 0: 59 | order = Account.send_order( 60 | code=item.code[0], 61 | time=item.date[0], 62 | amount=1000, 63 | towards=QA.ORDER_DIRECTION.BUY, 64 | price=0, 65 | order_model=QA.ORDER_MODEL.CLOSE, 66 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 67 | ) 68 | # print(item.to_json()[0]) 69 | Broker.receive_order(QA.QA_Event(order=order, market_data=item)) 70 | trade_mes = Broker.query_orders(Account.account_cookie, 'filled') 71 | res = trade_mes.loc[order.account_cookie, order.realorder_id] 72 | order.trade(res.trade_id, res.trade_price, 73 | res.trade_amount, res.trade_time) 74 | elif daily_ind.CROSS_SC.iloc[0] > 0: 75 | # print(item.code) 76 | if Account.sell_available.get(item.code[0], 0) > 0: 77 | order = Account.send_order( 78 | code=item.code[0], 79 | time=item.date[0], 80 | amount=Account.sell_available.get(item.code[0], 0), 81 | towards=QA.ORDER_DIRECTION.SELL, 82 | price=0, 83 | order_model=QA.ORDER_MODEL.MARKET, 84 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 85 | ) 86 | # print 87 | Broker.receive_order(QA.QA_Event( 88 | order=order, market_data=item)) 89 | trade_mes = Broker.query_orders( 90 | Account.account_cookie, 'filled') 91 | res = trade_mes.loc[order.account_cookie, order.realorder_id] 92 | order.trade(res.trade_id, res.trade_price, 93 | res.trade_amount, res.trade_time) 94 | Account.settle() 95 | 96 | print('TIME -- {}'.format(datetime.datetime.now()-st1)) 97 | print(Account.history) 98 | print(Account.history_table) 99 | print(Account.daily_hold) 100 | 101 | # create Risk analysis 102 | Risk = QA.QA_Risk(Account) 103 | 104 | Account.save() 105 | Risk.save() 106 | 107 | 108 | # print(Risk.message) 109 | # print(Risk.assets) 110 | # Risk.plot_assets_curve() 111 | # plt=Risk.plot_dailyhold() 112 | # plt.show() 113 | # plt1=Risk.plot_signal() 114 | # plt.show() 115 | 116 | # performance=QA.QA_Performance(Account) 117 | # plt=performance.plot_pnlmoney(performance.pnl_fifo) 118 | # plt.show() 119 | # Risk.assets.plot() 120 | # Risk.benchmark_assets.plot() 121 | 122 | # save result 123 | 124 | #account_info = QA.QA_fetch_account({'account_cookie': 'user_admin_macd'}) 125 | #account = QA.QA_Account().from_message(account_info[0]) 126 | # print(account) 127 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/简易回测/simple_minbacktest.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # In[21]: 5 | 6 | 7 | import QUANTAXIS as QA 8 | import pandas as pd 9 | 10 | data = QA.QA_fetch_stock_min_adv('601318', '2018-03-22', '2018-08-23', '30min') 11 | 12 | 13 | 14 | res = data.add_func(QA.QA_indicator_KDJ) 15 | sig = QA.CROSS(res.KDJ_J, res.KDJ_K) 16 | sig2 = QA.CROSS(res.KDJ_K, res.KDJ_J) 17 | 18 | User = QA.QA_User(username='quantaxis', password='quantaxis') 19 | Portfolio = User.new_portfolio('qatestportfolio') 20 | Account = Portfolio.new_account(account_cookie='macdmin_601318' ,init_cash=20000, 21 | frequence=QA.FREQUENCE.THIRTY_MIN) 22 | Broker = QA.QA_BacktestBroker() 23 | 24 | QA.QA_SU_save_strategy(Account.account_cookie, 25 | Account.portfolio_cookie, Account.account_cookie, if_save=True) 26 | 27 | _date = None 28 | for items in data.panel_gen: 29 | if _date != items.date[0]: 30 | print('try to settle') 31 | _date = items.date[0] 32 | Account.settle() 33 | 34 | for item in items.security_gen: 35 | if sig[item.index].iloc[0] > 0: 36 | order = Account.send_order( 37 | code=item.code[0], 38 | time=item.datetime[0], 39 | amount=100, 40 | towards=QA.ORDER_DIRECTION.BUY, 41 | price=0, 42 | order_model=QA.ORDER_MODEL.CLOSE, 43 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 44 | ) 45 | if order: 46 | Broker.receive_order(QA.QA_Event(order=order, market_data=item)) 47 | trade_mes = Broker.query_orders(Account.account_cookie, 'filled') 48 | res = trade_mes.loc[order.account_cookie, order.realorder_id] 49 | print('buy') 50 | order.trade(res.trade_id, res.trade_price, 51 | res.trade_amount, res.trade_time) 52 | elif sig2[item.index].iloc[0] > 0: 53 | if Account.sell_available.get(item.code[0], 0) > 0: 54 | order1 = Account.send_order( 55 | code=item.code[0], 56 | time=item.datetime[0], 57 | amount=100, 58 | towards=QA.ORDER_DIRECTION.SELL, 59 | price=0, 60 | order_model=QA.ORDER_MODEL.CLOSE, 61 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 62 | ) 63 | if order1: 64 | Broker.receive_order(QA.QA_Event( 65 | order=order1, market_data=item)) 66 | trade_mes = Broker.query_orders( 67 | Account.account_cookie, 'filled') 68 | res = trade_mes.loc[order1.account_cookie, order1.realorder_id] 69 | print('sell') 70 | order1.trade(res.trade_id, res.trade_price, 71 | res.trade_amount, res.trade_time) 72 | 73 | 74 | print(Account.history_table) 75 | 76 | 77 | r = QA.QA_Risk(Account) 78 | 79 | 80 | r.plot_assets_curve().show() 81 | 82 | print(r.profit_construct) 83 | 84 | Account.save() 85 | r.save() 86 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/简易回测/simplebacktest.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | import QUANTAXIS as QA 27 | import random 28 | """ 29 | 单线程模式回测示例 30 | 该代码旨在给出一个极其容易实现的小回测 高效 无事件驱动 31 | """ 32 | Broker = QA.QA_BacktestBroker() 33 | User = QA.QA_User(username='quantaxis', password='quantaxis') 34 | Portfolio = User.new_portfolio('qatestportfolio') 35 | AC = Portfolio.new_account(account_cookie='simplebacktest', init_cash=200000) 36 | """ 37 | # 账户设置初始资金 38 | AC.reset_assets(assets) 39 | 40 | # 发送订单 41 | Order=AC.send_order(code='000001',amount=1000,time='2018-03-21',towards=QA.ORDER_DIRECTION.BUY,price=0,order_model=QA.ORDER_MODEL.MARKET,amount_model=QA.AMOUNT_MODEL.BY_AMOUNT) 42 | # 撮合订单 43 | B.receive_order(QA.QA_Event(order=Order,market_data=data)) 44 | 45 | # 查询账户的订单状态 46 | trade_mes=Broker.query_orders(AC.account_cookie, 'filled') 47 | res=trade_mes.loc[order.account_cookie, order.realorder_id] 48 | 49 | # 更新订单 50 | 51 | order.trade(res.trade_id, res.trade_price,res.trade_amount, res.trade_time) 52 | 53 | # 查询订单的状态 54 | 55 | order.status 56 | 57 | 58 | # 分析结果 59 | 60 | risk=QA.QA_Risk(AC) 61 | 62 | """ 63 | 64 | QA.QA_SU_save_strategy('test','test_day',AC.account_cookie,if_save=True) 65 | 66 | def simple_backtest(AC, code, start, end): 67 | DATA = QA.QA_fetch_stock_day_adv(code, start, end).to_qfq() 68 | for items in DATA.panel_gen: # 一天过去了 69 | 70 | for item in items.security_gen: 71 | if random.random() > 0.5: # 加入一个随机 模拟买卖的 72 | if AC.sell_available.get(item.code[0], 0) == 0: 73 | order = AC.send_order( 74 | code=item.code[0], time=item.date[0], amount=1000, towards=QA.ORDER_DIRECTION.BUY, price=0, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 75 | ) 76 | if order: 77 | Broker.receive_order(QA.QA_Event( 78 | order=order, market_data=item)) 79 | trade_mes = Broker.query_orders( 80 | AC.account_cookie, 'filled') 81 | res = trade_mes.loc[order.account_cookie, 82 | order.realorder_id] 83 | print('order {} {} {} {}'.format( 84 | res.trade_id, res.trade_price, res.trade_amount, res.trade_time)) 85 | order.trade(res.trade_id, res.trade_price, 86 | res.trade_amount, res.trade_time) 87 | 88 | else: 89 | order = AC.send_order( 90 | code=item.code[0], time=item.date[0], amount=1000, towards=QA.ORDER_DIRECTION.SELL, price=0, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 91 | ) 92 | if order: 93 | Broker.receive_order(QA.QA_Event( 94 | order=order, market_data=item)) 95 | trade_mes = Broker.query_orders( 96 | AC.account_cookie, 'filled') 97 | res = trade_mes.loc[order.account_cookie, 98 | order.realorder_id] 99 | print('order {} {} {} {}'.format( 100 | res.trade_id, res.trade_price, res.trade_amount, res.trade_time)) 101 | order.trade(res.trade_id, res.trade_price, 102 | res.trade_amount, res.trade_time) 103 | AC.settle() 104 | 105 | 106 | simple_backtest(AC, QA.QA_fetch_stock_block_adv( 107 | ).code[0:10], '2017-01-01', '2018-01-31') 108 | print(AC.message) 109 | AC.save() 110 | risk = QA.QA_Risk(AC) 111 | print(risk.message) 112 | risk.save() 113 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/超级简化版回测/MACD_JCSC.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Demo: MACD strategy 3 | # src: ./test_backtest/MACD_JCSC.py 4 | # jupyter: ./test_backtest/QUANTAXIS回测分析全过程讲解.ipynb 5 | # paper: ./test_backtest/QUANTAXIS回测分析全过程讲解.md 6 | 7 | import QUANTAXIS as QA 8 | import numpy as np 9 | import pandas as pd 10 | import datetime 11 | st1=datetime.datetime.now() 12 | # define the MACD strategy 13 | def MACD_JCSC(dataframe, SHORT=12, LONG=26, M=9): 14 | """ 15 | 1.DIF向上突破DEA,买入信号参考。 16 | 2.DIF向下跌破DEA,卖出信号参考。 17 | """ 18 | CLOSE = dataframe.close 19 | DIFF = QA.EMA(CLOSE, SHORT) - QA.EMA(CLOSE, LONG) 20 | DEA = QA.EMA(DIFF, M) 21 | MACD = 2*(DIFF-DEA) 22 | 23 | CROSS_JC = QA.CROSS(DIFF, DEA) 24 | CROSS_SC = QA.CROSS(DEA, DIFF) 25 | ZERO = 0 26 | return pd.DataFrame({'DIFF': DIFF, 'DEA': DEA, 'MACD': MACD, 'CROSS_JC': CROSS_JC, 'CROSS_SC': CROSS_SC, 'ZERO': ZERO}) 27 | 28 | 29 | # create account 30 | user = QA.QA_User(username='quantaxis', password='quantaxis') 31 | portfolio = user.new_portfolio('qatestportfolio') 32 | 33 | 34 | Account = portfolio.new_account(account_cookie='macd_stock', init_cash=1000000) 35 | Broker = QA.QA_BacktestBroker() 36 | 37 | QA.QA_SU_save_strategy('MACD_JCSC','Indicator',Account.account_cookie) 38 | # get data from mongodb 39 | QA.QA_SU_save_strategy('MACD_JCSC', 'Indicator', 40 | Account.account_cookie, if_save=True) 41 | data = QA.QA_fetch_stock_day_adv( 42 | ['000001', '000002', '000004', '600000'], '2017-09-01', '2018-05-20') 43 | data = data.to_qfq() 44 | 45 | # add indicator 46 | ind = data.add_func(MACD_JCSC) 47 | # ind.xs('000001',level=1)['2018-01'].plot() 48 | 49 | data_forbacktest=data.select_time('2018-01-01','2018-05-01') 50 | 51 | 52 | for items in data_forbacktest.panel_gen: 53 | for item in items.security_gen: 54 | daily_ind=ind.loc[item.index] 55 | 56 | if daily_ind.CROSS_JC.iloc[0]>0: 57 | order=Account.send_order( 58 | code=item.code[0], 59 | time=item.date[0], 60 | amount=1000, 61 | towards=QA.ORDER_DIRECTION.BUY, 62 | price=0, 63 | order_model=QA.ORDER_MODEL.CLOSE, 64 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 65 | ) 66 | #print(item.to_json()[0]) 67 | Broker.receive_order(QA.QA_Event(order=order,market_data=item)) 68 | trade_mes=Broker.query_orders(Account.account_cookie,'filled') 69 | res=trade_mes.loc[order.account_cookie,order.realorder_id] 70 | order.trade(res.trade_id,res.trade_price,res.trade_amount,res.trade_time) 71 | elif daily_ind.CROSS_SC.iloc[0]>0: 72 | #print(item.code) 73 | if Account.sell_available.get(item.code[0], 0)>0: 74 | order=Account.send_order( 75 | code=item.code[0], 76 | time=item.date[0], 77 | amount=Account.sell_available.get(item.code[0], 0), 78 | towards=QA.ORDER_DIRECTION.SELL, 79 | price=0, 80 | order_model=QA.ORDER_MODEL.MARKET, 81 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 82 | ) 83 | #print 84 | Broker.receive_order(QA.QA_Event(order=order,market_data=item)) 85 | trade_mes=Broker.query_orders(Account.account_cookie,'filled') 86 | res=trade_mes.loc[order.account_cookie,order.realorder_id] 87 | order.trade(res.trade_id,res.trade_price,res.trade_amount,res.trade_time) 88 | Account.settle() 89 | 90 | print('TIME -- {}'.format(datetime.datetime.now()-st1)) 91 | print(Account.history) 92 | print(Account.history_table) 93 | print(Account.daily_hold) 94 | 95 | # create Risk analysis 96 | Risk = QA.QA_Risk(Account) 97 | 98 | Account.save() 99 | Risk.save() 100 | 101 | 102 | # print(Risk.message) 103 | # print(Risk.assets) 104 | # Risk.plot_assets_curve() 105 | # plt=Risk.plot_dailyhold() 106 | # plt.show() 107 | # plt1=Risk.plot_signal() 108 | # plt.show() 109 | 110 | # performance=QA.QA_Performance(Account) 111 | # plt=performance.plot_pnlmoney(performance.pnl_fifo) 112 | # plt.show() 113 | # Risk.assets.plot() 114 | # Risk.benchmark_assets.plot() 115 | 116 | # save result 117 | 118 | #account_info = QA.QA_fetch_account({'account_cookie': 'user_admin_macd'}) 119 | #account = QA.QA_Account().from_message(account_info[0]) 120 | #print(account) 121 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/超级简化版回测/simple_minbacktest.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # In[21]: 5 | 6 | 7 | import QUANTAXIS as QA 8 | import pandas as pd 9 | 10 | data = QA.QA_fetch_stock_min_adv('601318', '2018-03-22', '2018-08-23', '30min') 11 | 12 | 13 | res = data.add_func(QA.QA_indicator_KDJ) 14 | sig = QA.CROSS(res.KDJ_J, res.KDJ_K) 15 | sig2 = QA.CROSS(res.KDJ_K, res.KDJ_J) 16 | 17 | User = QA.QA_User(username='quantaxis', password='quantaxis') 18 | Portfolio = User.new_portfolio('qatestportfolio') 19 | Account = Portfolio.new_account(account_cookie='supersimple', init_cash=100000, init_hold={'601318': 1000}, 20 | frequence=QA.FREQUENCE.THIRTY_MIN) 21 | Broker = QA.QA_BacktestBroker() 22 | QA.QA_SU_save_strategy(Account.account_cookie, 23 | Account.portfolio_cookie, Account.account_cookie, if_save=True) 24 | 25 | _date = None 26 | for items in data.panel_gen: 27 | if _date != items.date[0]: 28 | print('try to settle') 29 | _date = items.date[0] 30 | Account.settle() 31 | 32 | for item in items.security_gen: 33 | if sig[item.index].iloc[0] > 0: 34 | order = Account.send_order( 35 | code=item.code[0], 36 | time=item.datetime[0], 37 | amount=1000, 38 | towards=QA.ORDER_DIRECTION.BUY, 39 | price=0, 40 | order_model=QA.ORDER_MODEL.CLOSE, 41 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 42 | ) 43 | if order: 44 | order.trade('unknownTrade', order.price, 45 | order.amount, order.datetime) 46 | elif sig2[item.index].iloc[0] > 0: 47 | if Account.sell_available.get(item.code[0], 0) > 0: 48 | order1 = Account.send_order( 49 | code=item.code[0], 50 | time=item.datetime[0], 51 | amount=1000, 52 | towards=QA.ORDER_DIRECTION.SELL, 53 | price=0, 54 | order_model=QA.ORDER_MODEL.CLOSE, 55 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 56 | ) 57 | if order1: 58 | order1.trade('unknownTrade', order1.price, 59 | order1.amount, order1.datetime) 60 | 61 | 62 | print(Account.history_table) 63 | 64 | 65 | r = QA.QA_Risk(Account) 66 | 67 | 68 | r.plot_assets_curve().show() 69 | 70 | print(r.profit_construct) 71 | 72 | Account.save() 73 | r.save() 74 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票回测/超级简化版回测/simplebacktest.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | import QUANTAXIS as QA 27 | import random 28 | """ 29 | 单线程模式回测示例 30 | 该代码旨在给出一个极其容易实现的小回测 高效 无事件驱动 31 | """ 32 | Broker = QA.QA_BacktestBroker() 33 | User = QA.QA_User(username='quantaxis', password='quantaxis') 34 | Portfolio = User.new_portfolio('qatestportfolio') 35 | AC = Portfolio.new_account(account_cookie='supersimple', init_cash=200000) 36 | """ 37 | # 账户设置初始资金 38 | AC.reset_assets(assets) 39 | 40 | # 发送订单 41 | Order=AC.send_order(code='000001',amount=1000,time='2018-03-21',towards=QA.ORDER_DIRECTION.BUY,price=0,order_model=QA.ORDER_MODEL.MARKET,amount_model=QA.AMOUNT_MODEL.BY_AMOUNT) 42 | # 撮合订单 43 | B.receive_order(QA.QA_Event(order=Order,market_data=data)) 44 | 45 | # 查询账户的订单状态 46 | trade_mes=Broker.query_orders(AC.account_cookie, 'filled') 47 | res=trade_mes.loc[order.account_cookie, order.realorder_id] 48 | 49 | # 更新订单 50 | 51 | order.trade(res.trade_id, res.trade_price,res.trade_amount, res.trade_time) 52 | 53 | # 查询订单的状态 54 | 55 | order.status 56 | 57 | 58 | # 分析结果 59 | 60 | risk=QA.QA_Risk(AC) 61 | 62 | """ 63 | 64 | QA.QA_SU_save_strategy('test','test_day',AC.account_cookie,if_save=True) 65 | 66 | def simple_backtest(AC, code, start, end): 67 | DATA = QA.QA_fetch_stock_day_adv(code, start, end).to_qfq() 68 | for items in DATA.panel_gen: # 一天过去了 69 | 70 | for item in items.security_gen: 71 | if random.random() > 0.5: # 加入一个随机 模拟买卖的 72 | if AC.sell_available.get(item.code[0], 0) == 0: 73 | order = AC.send_order( 74 | code=item.code[0], time=item.date[0], amount=1000, towards=QA.ORDER_DIRECTION.BUY, price=0, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 75 | ) 76 | if order: 77 | order.trade('unknownTrade', order.price, 78 | order.amount, order.datetime) 79 | 80 | else: 81 | order = AC.send_order( 82 | code=item.code[0], time=item.date[0], amount=1000, towards=QA.ORDER_DIRECTION.SELL, price=0, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 83 | ) 84 | if order: 85 | order.trade('unknownTrade', order.price, 86 | order.amount, order.datetime) 87 | AC.settle() 88 | 89 | 90 | simple_backtest(AC, QA.QA_fetch_stock_block_adv( 91 | ).code[0:10], '2017-01-01', '2018-01-31') 92 | print(AC.message) 93 | AC.save() 94 | risk = QA.QA_Risk(AC) 95 | print(risk.message) 96 | risk.save() 97 | -------------------------------------------------------------------------------- /4_回测实盘交易/回测/股票日内交易回测/T0backtest.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # In[1]: 5 | 6 | 7 | from QUANTAXIS.QAARP.QAStrategy import QA_Strategy 8 | from QUANTAXIS.QAARP.QAAccount import QA_Account 9 | from QUANTAXIS.QAUtil.QAParameter import (AMOUNT_MODEL, MARKET_TYPE, 10 | FREQUENCE, ORDER_DIRECTION, 11 | ORDER_MODEL, RUNNING_ENVIRONMENT) 12 | 13 | 14 | import random 15 | 16 | 17 | # In[2]: 18 | 19 | 20 | class MAMINT0Strategy(QA_Account): 21 | def __init__(self, user_cookie='default', portfolio_cookie='default', init_hold={'000001': 10000}): 22 | super().__init__(user_cookie, portfolio_cookie, init_hold=init_hold) 23 | self.account_cookie = 'T0BACKTEST' 24 | self.running_environment = RUNNING_ENVIRONMENT.TZERO 25 | self.frequence = FREQUENCE.ONE_MIN 26 | self.market_type = MARKET_TYPE.STOCK_CN 27 | 28 | self.result = {} 29 | 30 | def on_bar(self, event): 31 | 32 | # min5= self.market_data.min5 33 | # min15= self.market_data.min15 34 | 35 | # min5macd=QA.QA_indicator_MACD(min5) 36 | # min15macd=QA.QA_indicator_MACD(min15) 37 | # self.result['min5macd']=min5macd 38 | 39 | # self.cash_available # 当前剩余现金 40 | # self.sell_available # 当前可卖股票 41 | # self.history_table # 当前的历史交易 42 | # self.hold_time # 当前的持仓时间 43 | # self.hold_price # 当前持仓的成本价格 44 | # self.get_orders # 获取历史订单 45 | # self.allow_sellopen # 账户是否允许卖空 46 | # self.allow_t0 # 账户是否允许t0 47 | # self.commission_coeff # 账户的手续费(可自行调整) 48 | 49 | try: 50 | for item in event.market_data.code: 51 | 52 | print('================') 53 | print(self.sell_available) 54 | print('================') 55 | print(self.hold_available) 56 | if self.sell_available.get(item, 0) > 0: 57 | event.send_order(account_cookie=self.account_cookie, 58 | amount=self.sell_available[item], amount_model=AMOUNT_MODEL.BY_AMOUNT, 59 | time=self.current_time, code=item, price=0, 60 | order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.SELL, 61 | market_type=self.market_type, frequence=self.frequence, 62 | broker_name=self.broker 63 | ) 64 | else: 65 | event.send_order(account_cookie=self.account_cookie, 66 | amount=100, amount_model=AMOUNT_MODEL.BY_AMOUNT, 67 | time=self.current_time, code=item, price=0, 68 | order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.BUY, 69 | market_type=self.market_type, frequence=self.frequence, 70 | broker_name=self.broker) 71 | except: 72 | pass 73 | 74 | 75 | # In[3]: 76 | 77 | 78 | from QUANTAXIS.QAARP.QARisk import QA_Risk 79 | from QUANTAXIS.QAARP.QAUser import QA_User 80 | from QUANTAXIS.QAApplication.QABacktest import QA_Backtest 81 | from QUANTAXIS.QAUtil.QALogs import QA_util_log_info 82 | from QUANTAXIS.QAUtil.QAParameter import FREQUENCE, MARKET_TYPE 83 | 84 | 85 | class Backtest(QA_Backtest): 86 | ''' 87 | 多线程模式回测示例 88 | 89 | ''' 90 | 91 | def __init__(self, market_type, frequence, start, end, code_list, commission_fee): 92 | super().__init__(market_type, frequence, start, end, code_list, commission_fee) 93 | self.account = self.portfolio.add_account( MAMINT0Strategy(user_cookie=self.user.user_cookie, portfolio_cookie= self.portfolio.portfolio_cookie)) 94 | 95 | def after_success(self): 96 | QA_util_log_info(self.account.history_table) 97 | risk = QA_Risk(self.account, benchmark_code='000300', 98 | benchmark_type=MARKET_TYPE.INDEX_CN) 99 | 100 | print(risk().T) 101 | self.account.save() 102 | risk.save() 103 | risk.plot_assets_curve() 104 | print(risk.profit_construct) 105 | 106 | 107 | # In[4]: 108 | 109 | 110 | import QUANTAXIS as QA 111 | backtest = Backtest(market_type=MARKET_TYPE.STOCK_CN, 112 | frequence=FREQUENCE.FIFTEEN_MIN, 113 | start='2018-11-01', 114 | end='2018-12-10', 115 | code_list=['000001'], 116 | commission_fee=0.00015) 117 | backtest.start_market() 118 | 119 | backtest.run() 120 | backtest.stop() 121 | 122 | 123 | # In[5]: 124 | 125 | 126 | print(backtest.account.history_table) 127 | -------------------------------------------------------------------------------- /config/install_ubuntu.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QADemoOLD/ed8cc09fc373fe665459e0e8e3d362d5d48894f3/config/install_ubuntu.sh -------------------------------------------------------------------------------- /config/readme.md: -------------------------------------------------------------------------------- 1 | # 配置/脚本区 2 | 3 | - ubuntu16.sh ubuntu 16 一键安装脚本 4 | - startjupyter.sh 开启jupyter notebook 5 | - run_backend.sh 开启mongod后台,WEBKIT前后台 6 | - update_data.py 更新数据脚本 7 | -------------------------------------------------------------------------------- /config/run_backend.sh: -------------------------------------------------------------------------------- 1 | # run mongo 2 | 3 | service mongod restart 4 | 5 | # nohup mongod & 6 | 7 | 8 | cd ../QUANTAXIS_WEBKIT/backend 9 | forever start bin/www 10 | 11 | cd ../web 12 | forever start build/dev-server.js -------------------------------------------------------------------------------- /config/startjupyter.sh: -------------------------------------------------------------------------------- 1 | #sudo python3.6 -m pip install jupyter -i https://pypi.doubanio.com/simple 2 | 3 | cd ../jupyterexample 4 | jupyter notebook --ip=0.0.0.0 --allow-root 5 | -------------------------------------------------------------------------------- /config/ubuntu16.sh: -------------------------------------------------------------------------------- 1 | echo 'INSTALL_QUANTAXIS' 2 | 3 | echo 'USING ALIYUN deb' 4 | 5 | echo "deb-src http://archive.ubuntu.com/ubuntu xenial main restricted #Added by software-properties 6 | deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted 7 | deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted multiverse universe #Added by software-properties 8 | deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted 9 | deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted multiverse universe #Added by software-properties 10 | deb http://mirrors.aliyun.com/ubuntu/ xenial universe 11 | deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe 12 | deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse 13 | deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse 14 | deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse 15 | deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse #Added by software-properties 16 | deb http://archive.canonical.com/ubuntu xenial partner 17 | deb-src http://archive.canonical.com/ubuntu xenial partner 18 | deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted 19 | deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted multiverse universe #Added by software-properties 20 | deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe 21 | deb http://mirrors.aliyun.com/ubuntu/ xenial-security multiverse " | tee /etc/apt/sources.list.d/sources.list 22 | 23 | apt-get update 24 | 25 | apt install software-properties-common 26 | 27 | # add-apt-repository ppa:jonathonf/python-3.6 28 | # apt-get update 29 | 30 | 31 | # apt-get install python3.6-dev 32 | wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.1.0-Linux-x86_64.sh 33 | bash Anaconda3-5.1.0-Linux-x86_64.sh 34 | 35 | source ~/.bashrc 36 | 37 | wget https://bootstrap.pypa.io/get-pip.py 38 | 39 | python get-pip.py 40 | 41 | 42 | apt-get install libxml2-dev libxslt-dev 43 | apt-get install git 44 | cd ~ 45 | git clone https://github.com/yutiansut/quantaxis 46 | # add some permission for quantaxis 47 | chmod -R 777 ./quantaxis 48 | cd ~/quantaxis 49 | python -m pip install pillow -i https://pypi.doubanio.com/simple 50 | python -m pip install -r requirements.txt -i https://pypi.doubanio.com/simple 51 | python -m pip install tushare 52 | python -m pip install pytdx 53 | python -m pip install -e . 54 | 55 | 56 | 57 | apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5 58 | # Ubuntu 16.04 59 | echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.6 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.6.list 60 | 61 | # 更新 62 | apt-get update 63 | # 安装MongoDB 64 | apt-get install -y mongodb-org --allow-unauthenticated 65 | cd / 66 | mkdir data 67 | cd data 68 | mkdir data 69 | mkdir log 70 | 71 | # 开启MongoDB服务 72 | service mongod start 73 | 74 | apt-get install curl 75 | curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - 76 | apt-get install -y nodejs 77 | apt-get install npm 78 | npm install npm -g #更新npm 79 | npm install forever -g #安装一个全局的forever 用于之后启动 80 | npm install cnpm -g 81 | 82 | cd ~/quantaxis/QUANTAXIS_Webkit/backend 83 | npm install 84 | 85 | 86 | cd ~/quantaxis/QUANTAXIS_Webkit/web 87 | npm install 88 | 89 | 90 | -------------------------------------------------------------------------------- /config/update_all.py: -------------------------------------------------------------------------------- 1 | #coding :utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | """对应于save all 27 | """ 28 | 29 | from QUANTAXIS.QASU.main import (QA_SU_save_etf_day, QA_SU_save_etf_min, 30 | QA_SU_save_financialfiles, 31 | QA_SU_save_index_day, QA_SU_save_index_min, 32 | QA_SU_save_stock_block, QA_SU_save_stock_day, 33 | QA_SU_save_stock_info, 34 | QA_SU_save_stock_info_tushare, 35 | QA_SU_save_stock_list, QA_SU_save_stock_min, 36 | QA_SU_save_stock_xdxr) 37 | from QUANTAXIS.QASU.save_binance import (QA_SU_save_binance, 38 | QA_SU_save_binance_1day, 39 | QA_SU_save_binance_1hour, 40 | QA_SU_save_binance_1min, 41 | QA_SU_save_binance_symbol) 42 | 43 | 44 | QA_SU_save_stock_day('tdx') 45 | QA_SU_save_stock_xdxr('tdx') 46 | # QA_SU_save_stock_min('tdx') 47 | QA_SU_save_index_day('tdx') 48 | # QA_SU_save_index_min('tdx') 49 | # QA_SU_save_etf_day('tdx') 50 | # QA_SU_save_etf_min('tdx') 51 | QA_SU_save_stock_list('tdx') 52 | QA_SU_save_stock_block('tdx') 53 | # QA_SU_save_stock_info('tdx') -------------------------------------------------------------------------------- /config/update_data.py: -------------------------------------------------------------------------------- 1 | #coding :utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | import datetime 26 | from QUANTAXIS import (QA_SU_save_etf_day, QA_SU_save_index_day, QA_SU_save_stock_min, 27 | QA_SU_save_stock_block, QA_SU_save_stock_day,QA_SU_save_etf_min, 28 | QA_SU_save_stock_list, QA_SU_save_stock_xdxr, 29 | QA_util_log_info) 30 | 31 | print('SAVE/UPDATE {}'.format(datetime.datetime.now())) 32 | 33 | QA_SU_save_stock_day('tdx') 34 | QA_SU_save_stock_xdxr('tdx') 35 | QA_SU_save_etf_day('tdx') 36 | QA_SU_save_index_day('tdx') 37 | QA_SU_save_stock_list('tdx') 38 | QA_SU_save_stock_block('tdx') 39 | -------------------------------------------------------------------------------- /config/update_x.py: -------------------------------------------------------------------------------- 1 | #coding :utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | """对应于save x 27 | """ 28 | from QUANTAXIS.QASU.main import (QA_SU_save_etf_day, QA_SU_save_etf_min, 29 | QA_SU_save_financialfiles, 30 | QA_SU_save_index_day, QA_SU_save_index_min, 31 | QA_SU_save_stock_block, QA_SU_save_stock_day, 32 | QA_SU_save_stock_info, 33 | QA_SU_save_stock_info_tushare, 34 | QA_SU_save_stock_list, QA_SU_save_stock_min, 35 | QA_SU_save_stock_xdxr) 36 | from QUANTAXIS.QASU.save_binance import (QA_SU_save_binance, 37 | QA_SU_save_binance_1day, 38 | QA_SU_save_binance_1hour, 39 | QA_SU_save_binance_1min, 40 | QA_SU_save_binance_symbol) 41 | 42 | 43 | QA_SU_save_stock_day('tdx') 44 | QA_SU_save_stock_xdxr('tdx') 45 | QA_SU_save_stock_min('tdx') 46 | QA_SU_save_index_day('tdx') 47 | QA_SU_save_index_min('tdx') 48 | QA_SU_save_etf_day('tdx') 49 | QA_SU_save_etf_min('tdx') 50 | QA_SU_save_stock_list('tdx') 51 | QA_SU_save_stock_block('tdx') 52 | QA_SU_save_stock_info('tdx') -------------------------------------------------------------------------------- /config/windows_autojob_updatedata.md: -------------------------------------------------------------------------------- 1 | # WINDOWS开启自动脚本 2 | 3 | 4 | 5 | - [WINDOWS开启自动脚本](#windows开启自动脚本) 6 | - [打开控制面板-系统和安全-管理工具](#打开控制面板-系统和安全-管理工具) 7 | - [打开计划任务程序](#打开计划任务程序) 8 | - [在计划任务程序中,新建任务](#在计划任务程序中新建任务) 9 | - [创建QUANTAXIS_Update任务](#创建quantaxis_update任务) 10 | - [选择运行时间/频率](#选择运行时间频率) 11 | - [选择执行的命令](#选择执行的命令) 12 | - [配置完毕](#配置完毕) 13 | 14 | 15 | 16 | 我们使用计划任务来开启自动更新任务: 17 | 18 | 19 | ## 打开控制面板-系统和安全-管理工具 20 | ![](http://pic.yutiansut.com/management.png) 21 | 22 | ## 打开计划任务程序 23 | ![](http://pic.yutiansut.com/management2.png) 24 | 25 | ## 在计划任务程序中,新建任务 26 | ![](http://pic.yutiansut.com/task1.png) 27 | 28 | ## 创建QUANTAXIS_Update任务 29 | ![](http://pic.yutiansut.com/task2.png) 30 | 31 | ## 选择运行时间/频率 32 | ![](http://pic.yutiansut.com/task3.png) 33 | 34 | ## 选择执行的命令 35 | ![](http://pic.yutiansut.com/task4.png) 36 | 37 | ## 配置完毕 38 | ![](http://pic.yutiansut.com/task5.png) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # QUANTAXIS DEMO 2 | 3 | quantaxis的一些使用示例 4 | 5 | 6 | ## 使用方法: 7 | 8 | 先将此项目 ```FORK```到你自己的账户中 9 | 10 | 11 | ```bash 12 | git clone https://github.com/[你的github账号]/qademo 13 | ``` 14 | 15 | ## 后台运行脚本 16 | 17 | ``` 18 | sudo chmod -R 777 ./qademo 19 | cd qademo 20 | sudo nohup ./startjupyter.sh & 21 | ``` 22 | 23 | ## 更新代码 24 | 25 | 通过从 yutiansut/qademo 向你的项目推```pull request```来对项目进行更新 26 | 27 | ## 贡献代码 28 | 29 | 通过从 你的项目 向 yutiansut/qademo 推 ```pull request``` 来贡献你的代码 -------------------------------------------------------------------------------- /research/RNN_EXAMPLE/RNN-example_using_keras.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # In[3]: 5 | 6 | 7 | import keras 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | import pandas as pd 11 | from pandas import datetime 12 | import math 13 | import time 14 | import itertools 15 | from sklearn import preprocessing 16 | import datetime 17 | from operator import itemgetter 18 | from sklearn.metrics import mean_squared_error 19 | from math import sqrt 20 | from keras.models import Sequential 21 | from keras.layers.core import Dense, Dropout, Activation 22 | from keras.layers.recurrent import LSTM 23 | import QUANTAXIS as QA 24 | 25 | 26 | # In[23]: 27 | 28 | 29 | # load data function 30 | def load_data(stock, seq_len): 31 | # stock 是一个input的dataframe 32 | amount_of_features = len(stock.columns) 33 | data = stock.as_matrix() # pd.DataFrame(stock) 34 | sequence_length = seq_len + 1 35 | result = [] 36 | for index in range(len(data) - sequence_length): 37 | result.append(data[index: index + sequence_length]) 38 | 39 | result = np.array(result) 40 | row = round(0.9 * result.shape[0]) 41 | train = result[:int(row), :] 42 | x_train = train[:, :-1] 43 | y_train = train[:, -1][:, -1] 44 | x_test = result[int(row):, :-1] 45 | y_test = result[int(row):, -1][:, -1] 46 | 47 | x_train = np.reshape( 48 | x_train, (x_train.shape[0], x_train.shape[1], amount_of_features)) 49 | x_test = np.reshape( 50 | x_test, (x_test.shape[0], x_test.shape[1], amount_of_features)) 51 | 52 | return [x_train, y_train, x_test, y_test] 53 | 54 | 55 | def build_model(layers): 56 | model = Sequential() 57 | 58 | model.add(LSTM( 59 | input_dim=layers[0], 60 | output_dim=layers[1], 61 | return_sequences=True)) 62 | model.add(Dropout(0.2)) 63 | 64 | model.add(LSTM( 65 | layers[2], 66 | return_sequences=False)) 67 | model.add(Dropout(0.2)) 68 | 69 | model.add(Dense( 70 | output_dim=layers[2])) 71 | model.add(Activation("linear")) 72 | 73 | start = time.time() 74 | model.compile(loss="mse", optimizer="rmsprop", metrics=['accuracy']) 75 | print("Compilation Time : ", time.time() - start) 76 | return model 77 | 78 | 79 | def build_model2(layers): 80 | d = 0.2 81 | model = Sequential() 82 | model.add(LSTM(128, input_shape=( 83 | layers[1], layers[0]), return_sequences=True)) 84 | model.add(Dropout(d)) 85 | model.add(LSTM(64, input_shape=( 86 | layers[1], layers[0]), return_sequences=False)) 87 | model.add(Dropout(d)) 88 | model.add(Dense(16, init='uniform', activation='relu')) 89 | model.add(Dense(1, init='uniform', activation='relu')) 90 | model.compile(loss='mse', optimizer='adam', metrics=['accuracy']) 91 | return model 92 | 93 | 94 | # In[10]: 95 | 96 | 97 | data = QA.QA_fetch_stock_day_adv('000001', '2000-01-01', '2018-01-31').to_qfq() 98 | 99 | 100 | # In[14]: 101 | 102 | 103 | data.plot() 104 | 105 | 106 | # In[21]: 107 | 108 | 109 | used_data = pd.concat([data.open, data.high, data.close], axis=1) 110 | 111 | 112 | # In[25]: 113 | 114 | 115 | window = 5 116 | X_train, y_train, X_test, y_test = load_data(used_data[::-1], window) 117 | 118 | 119 | # In[27]: 120 | 121 | 122 | X_train 123 | 124 | 125 | # In[28]: 126 | 127 | 128 | model = build_model2([3, window, 1]) 129 | 130 | 131 | # In[29]: 132 | 133 | 134 | model.fit( 135 | X_train, 136 | y_train, 137 | batch_size=512, 138 | nb_epoch=500, 139 | validation_split=0.1, 140 | verbose=0) 141 | 142 | 143 | # In[30]: 144 | 145 | 146 | # print(X_test[-1]) 147 | diff = [] 148 | ratio = [] 149 | p = model.predict(X_test) 150 | for u in range(len(y_test)): 151 | pr = p[u][0] 152 | ratio.append((y_test[u]/pr)-1) 153 | diff.append(abs(y_test[u] - pr)) 154 | #print(u, y_test[u], pr, (y_test[u]/pr)-1, abs(y_test[u]- pr)) 155 | 156 | 157 | # In[31]: 158 | 159 | 160 | import matplotlib.pyplot as plt2 161 | 162 | plt2.plot(p, color='red', label='prediction') 163 | plt2.plot(y_test, color='blue', label='y_test') 164 | plt2.legend(loc='upper left') 165 | plt2.show() 166 | -------------------------------------------------------------------------------- /research/马科维茨有效前沿实现/output_19_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QADemoOLD/ed8cc09fc373fe665459e0e8e3d362d5d48894f3/research/马科维茨有效前沿实现/output_19_1.png -------------------------------------------------------------------------------- /research/马科维茨有效前沿实现/output_34_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QADemoOLD/ed8cc09fc373fe665459e0e8e3d362d5d48894f3/research/马科维茨有效前沿实现/output_34_1.png -------------------------------------------------------------------------------- /research/马科维茨有效前沿实现/output_6_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QADemoOLD/ed8cc09fc373fe665459e0e8e3d362d5d48894f3/research/马科维茨有效前沿实现/output_6_1.png -------------------------------------------------------------------------------- /research/马科维茨有效前沿实现/output_9_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QADemoOLD/ed8cc09fc373fe665459e0e8e3d362d5d48894f3/research/马科维茨有效前沿实现/output_9_1.png -------------------------------------------------------------------------------- /research/马科维茨有效前沿实现/马科维茨的QUANTAXIS实现.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```python 4 | import pandas as pd 5 | import numpy as np 6 | import statsmodels.api as sm 7 | import scipy.stats as scs 8 | import matplotlib.pyplot as plt 9 | import QUANTAXIS as QA 10 | ``` 11 | 12 | QUANTAXIS>> start QUANTAXIS 13 | QUANTAXIS>> Welcome to QUANTAXIS, the Version is 1.0.66 14 | QUANTAXIS>> 15 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 16 | ``########`````##````````##``````````##`````````####````````##```##########````````#``````##``````###```##`````######`` 17 | `##``````## ```##````````##`````````####````````##`##```````##```````##```````````###``````##````##`````##```##`````##` 18 | ##````````##```##````````##````````##`##````````##``##``````##```````##``````````####```````#```##``````##```##``````## 19 | ##````````##```##````````##```````##```##```````##```##`````##```````##`````````##`##```````##`##```````##````##``````` 20 | ##````````##```##````````##``````##`````##``````##````##````##```````##````````##``###```````###````````##`````##`````` 21 | ##````````##```##````````##``````##``````##`````##`````##```##```````##```````##````##```````###````````##``````###```` 22 | ##````````##```##````````##`````##````````##````##``````##``##```````##``````##``````##`````##`##```````##````````##``` 23 | ##````````##```##````````##````#############````##```````##`##```````##`````###########`````##``##``````##`````````##`` 24 | ###```````##```##````````##```##```````````##```##```````##`##```````##````##`````````##```##```##``````##```##`````##` 25 | `##``````###````##``````###``##`````````````##``##````````####```````##```##``````````##``###````##`````##````##`````## 26 | ``#########``````########```##``````````````###`##``````````##```````##``##````````````##`##``````##````##`````###``### 27 | ````````#####`````````````````````````````````````````````````````````````````````````````````````````````````````##`` 28 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 29 | ``````````````````````````Copyright``yutiansut``2018``````QUANTITATIVE FINANCIAL FRAMEWORK````````````````````````````` 30 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 31 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 32 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 33 | 34 | 35 | 36 | # 1. 获取股票, 并选取close 进行初步分析 37 | 38 | 39 | ```python 40 | # 获取上证50中的四根票 41 | code=QA.QA_fetch_stock_block_adv().get_block('上证50').code[0:4] 42 | ``` 43 | 44 | 45 | ```python 46 | data=QA.QA_fetch_stock_day_adv(code,'2018-01-01','2018-07-16').to_qfq() 47 | ``` 48 | 49 | 50 | ```python 51 | 52 | # 选择close序列, 进行pivot成表 53 | close=data.pivot('close') 54 | 55 | close.head() 56 | ``` 57 | 58 | 59 | 60 | 61 |
62 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
code600000600016600019600028
date
2018-01-0212.5870857.0060298.5212626.008582
2018-01-0312.5277127.0553688.4927316.102908
2018-01-0412.5277127.0224758.5022426.508511
2018-01-0512.5573987.0718148.4356696.659433
2018-01-0812.5475037.1704908.8351036.650000
130 |
131 | 132 | 133 | 134 | ## 使用基准价格比较股票 135 | 136 | 137 | ```python 138 | (close/close.iloc[0]*100).plot(figsize = (18,16)) 139 | ``` 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | ![png](output_6_1.png) 150 | 151 | 152 | ## 计算收益率 153 | 154 | 155 | ```python 156 | log_returns=np.log(close/close.shift(1)) 157 | log_returns.head() 158 | ``` 159 | 160 | 161 | 162 | 163 |
164 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 |
code600000600016600019600028
date
2018-01-02NaNNaNNaNNaN
2018-01-03-0.0047280.007018-0.0033540.015577
2018-01-040.000000-0.0046730.0011190.064345
2018-01-050.0023670.007001-0.0078610.022924
2018-01-08-0.0007880.0138570.046264-0.001417
232 |
233 | 234 | 235 | 236 | 237 | ```python 238 | log_returns.hist(bins = 50, figsize = (19,16)) 239 | ``` 240 | 241 | 242 | 243 | 244 | array([[, 245 | ], 246 | [, 247 | ]], 248 | dtype=object) 249 | 250 | 251 | 252 | 253 | ![png](output_9_1.png) 254 | 255 | 256 | 257 | ```python 258 | log_returns.cov()*252 259 | ``` 260 | 261 | 262 | 263 | 264 |
265 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 |
code600000600016600019600028
code
6000000.0462010.0301600.0379570.028727
6000160.0301600.0406330.0366710.032252
6000190.0379570.0366710.1359020.046658
6000280.0287270.0322520.0466580.096903
326 |
327 | 328 | 329 | 330 | 331 | ```python 332 | noa=len(code) 333 | ``` 334 | 335 | ## 给不同股票随意分配权重 336 | 337 | 338 | ```python 339 | weights = np.random.random(noa) 340 | weights /= np.sum(weights) 341 | weights 342 | ``` 343 | 344 | 345 | 346 | 347 | array([0.21942895, 0.14466788, 0.17803594, 0.45786723]) 348 | 349 | 350 | 351 | ## 计算预期组合年化收益、组合方差和组合标准差 352 | 353 | 354 | ```python 355 | np.sum(log_returns.mean()*weights)*252 356 | ``` 357 | 358 | 359 | 360 | 361 | -0.16519203884200712 362 | 363 | 364 | 365 | 366 | ```python 367 | np.dot(weights.T, np.dot(log_returns.cov()*252,weights)) 368 | ``` 369 | 370 | 371 | 372 | 373 | 0.05211897463039171 374 | 375 | 376 | 377 | 378 | ```python 379 | np.sqrt(np.dot(weights.T, np.dot(log_returns.cov()* 252,weights))) 380 | ``` 381 | 382 | 383 | 384 | 385 | 0.2282958051090552 386 | 387 | 388 | 389 | ## 用蒙特卡洛模拟产生大量随机组合 390 | 391 | 进行到此,我们最想知道的是给定的一个股票池(证券组合)如何找到风险和收益平衡的位置。 392 | 393 | 下面通过一次蒙特卡洛模拟,产生大量随机的权重向量,并记录随机组合的预期收益和方差。 394 | 395 | 396 | ```python 397 | port_returns = [] 398 | port_variance = [] 399 | for p in range(4000): 400 | weights = np.random.random(noa) 401 | weights /=np.sum(weights) 402 | port_returns.append(np.sum(log_returns.mean()*252*weights)) 403 | port_variance.append(np.sqrt(np.dot(weights.T, np.dot(log_returns.cov()*252, weights)))) 404 | 405 | port_returns = np.array(port_returns) 406 | port_variance = np.array(port_variance) 407 | 408 | #无风险利率设定为4% 409 | risk_free = 0.04 410 | plt.figure(figsize = (8,4)) 411 | plt.scatter(port_variance, port_returns, c=(port_returns-risk_free)/port_variance, marker = 'o') 412 | plt.grid(True) 413 | plt.xlabel('excepted volatility') 414 | plt.ylabel('expected return') 415 | plt.colorbar(label = 'Sharpe ratio') 416 | ``` 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | ![png](output_19_1.png) 427 | 428 | 429 | # 投资组合优化1——sharpe最大 430 | 431 | 建立statistics函数来记录重要的投资组合统计数据(收益,方差和夏普比) 432 | 433 | 通过对约束最优问题的求解,得到最优解。其中约束是权重总和为1。 434 | 435 | 436 | ```python 437 | def statistics(weights): 438 | weights = np.array(weights) 439 | port_returns = np.sum(log_returns.mean()*weights)*252 440 | port_variance = np.sqrt(np.dot(weights.T, np.dot(log_returns.cov()*252,weights))) 441 | return np.array([port_returns, port_variance, port_returns/port_variance]) 442 | 443 | #最优化投资组合的推导是一个约束最优化问题 444 | import scipy.optimize as sco 445 | 446 | #最小化夏普指数的负值 447 | def min_sharpe(weights): 448 | return -statistics(weights)[2] 449 | 450 | #约束是所有参数(权重)的总和为1。这可以用minimize函数的约定表达如下 451 | cons = ({'type':'eq', 'fun':lambda x: np.sum(x)-1}) 452 | 453 | #我们还将参数值(权重)限制在0和1之间。这些值以多个元组组成的一个元组形式提供给最小化函数 454 | bnds = tuple((0,1) for x in range(noa)) 455 | 456 | #优化函数调用中忽略的唯一输入是起始参数列表(对权重的初始猜测)。我们简单的使用平均分布。 457 | opts = sco.minimize(min_sharpe, noa*[1./noa,], method = 'SLSQP', bounds = bnds, constraints = cons) 458 | opts 459 | ``` 460 | 461 | 462 | 463 | 464 | fun: -0.3395589843140905 465 | jac: array([1.88688774, 1.29688912, 0.85391124, 0. ]) 466 | message: 'Optimization terminated successfully.' 467 | nfev: 12 468 | nit: 2 469 | njev: 2 470 | status: 0 471 | success: True 472 | x: array([7.21644966e-16, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]) 473 | 474 | 475 | 476 | 477 | 得到的最优组合权重向量为: 478 | 479 | 480 | ```python 481 | opts['x'].round(3) 482 | ``` 483 | 484 | 485 | 486 | 487 | array([0., 0., 0., 1.]) 488 | 489 | 490 | 491 | sharpe最大的组合3个统计数据分别为: 492 | 493 | 494 | ```python 495 | #预期收益率、预期波动率、最优夏普指数 496 | statistics(opts['x']).round(3) 497 | ``` 498 | 499 | 500 | 501 | 502 | array([0.106, 0.311, 0.34 ]) 503 | 504 | 505 | 506 | ## 投资组合优化2——方差最小 507 | 接下来,我们通过方差最小来选出最优投资组合。 508 | 509 | 510 | ```python 511 | #但是我们定义一个函数对 方差进行最小化 512 | def min_variance(weights): 513 | return statistics(weights)[1] 514 | 515 | optv = sco.minimize(min_variance, noa*[1./noa,],method = 'SLSQP', bounds = bnds, constraints = cons) 516 | optv 517 | ``` 518 | 519 | 520 | 521 | 522 | fun: 0.18986885342564985 523 | jac: array([0.18988797, 0.18988497, 0.19980709, 0.18966556]) 524 | message: 'Optimization terminated successfully.' 525 | nfev: 48 526 | nit: 8 527 | njev: 8 528 | status: 0 529 | success: True 530 | x: array([0.37442787, 0.54700915, 0. , 0.07856297]) 531 | 532 | 533 | 534 | 方差最小的最优组合权重向量及组合的统计数据分别为: 535 | 536 | 537 | ```python 538 | optv['x'].round(3) 539 | ``` 540 | 541 | 542 | 543 | 544 | array([0.374, 0.547, 0. , 0.079]) 545 | 546 | 547 | 548 | 549 | ```python 550 | #得到的预期收益率、波动率和夏普指数 551 | statistics(optv['x']).round(3) 552 | ``` 553 | 554 | 555 | 556 | 557 | array([-0.401, 0.19 , -2.115]) 558 | 559 | 560 | 561 | ## 组合的有效前沿 562 | 有效前沿有既定的目标收益率下方差最小的投资组合构成。 563 | 564 | 在最优化时采用两个约束,1.给定目标收益率,2.投资组合权重和为1。 565 | 566 | 567 | ```python 568 | 569 | def min_variancemin_varia (weights): 570 | return statistics(weights)[1] 571 | 572 | #在不同目标收益率水平(target_returns)循环时,最小化的一个约束条件会变化。 573 | target_returns = np.linspace(0.0,0.5,50) 574 | target_variance = [] 575 | for tar in target_returns: 576 | cons = ({'type':'eq','fun':lambda x:statistics(x)[0]-tar},{'type':'eq','fun':lambda x:np.sum(x)-1}) 577 | res = sco.minimize(min_variance, noa*[1./noa,],method = 'SLSQP', bounds = bnds, constraints = cons) 578 | target_variance.append(res['fun']) 579 | 580 | target_variance = np.array(target_variance) 581 | ``` 582 | 583 | 下面是最优化结果的展示。 584 | 585 | 叉号:构成的曲线是有效前沿(目标收益率下最优的投资组合) 586 | 587 | 红星:sharpe最大的投资组合 588 | 589 | 黄星:方差最小的投资组合 590 | 591 | 592 | ```python 593 | plt.figure(figsize = (8,4)) 594 | #圆圈:蒙特卡洛随机产生的组合分布 595 | plt.scatter(port_variance, port_returns, c = port_returns/port_variance,marker = 'o') 596 | #叉号:有效前沿 597 | plt.scatter(target_variance,target_returns, c = target_returns/target_variance, marker = 'x') 598 | #红星:标记最高sharpe组合 599 | plt.plot(statistics(opts['x'])[1], statistics(opts['x'])[0], 'r*', markersize = 15.0) 600 | #黄星:标记最小方差组合 601 | plt.plot(statistics(optv['x'])[1], statistics(optv['x'])[0], 'y*', markersize = 15.0) 602 | plt.grid(True) 603 | plt.xlabel('expected volatility') 604 | plt.ylabel('expected return') 605 | plt.colorbar(label = 'Sharpe ratio') 606 | ``` 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | ![png](output_34_1.png) 617 | 618 | -------------------------------------------------------------------------------- /startjupyter.bat: -------------------------------------------------------------------------------- 1 | jupyter notebook -------------------------------------------------------------------------------- /startjupyter.sh: -------------------------------------------------------------------------------- 1 | echo 'start jupter notebook' 2 | 3 | jupyter notebook --ip=0.0.0.0 --allow-root -y -------------------------------------------------------------------------------- /test_backtest/FUTURE/TEST 期货的多空下单.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import QUANTAXIS as QA" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 2, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "acc=QA.QA_Account(allow_sellopen=True,init_cash=10000,allow_t0=True,account_cookie='future_test',market_type=QA.MARKET_TYPE.FUTURE_CN,frequence=QA.FREQUENCE.FIFTEEN_MIN)" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 3, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "order=acc.send_order(code='RB1901', amount=1, time='2018-12-28 09:30:00', towards=QA.ORDER_DIRECTION.BUY_OPEN, price=3420, money=None, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT)" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 4, 33 | "metadata": {}, 34 | "outputs": [ 35 | { 36 | "data": { 37 | "text/plain": [ 38 | "6579.1449999999995" 39 | ] 40 | }, 41 | "execution_count": 4, 42 | "metadata": {}, 43 | "output_type": "execute_result" 44 | } 45 | ], 46 | "source": [ 47 | "acc.cash_available" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 5, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "data": { 57 | "text/plain": [ 58 | "[10000]" 59 | ] 60 | }, 61 | "execution_count": 5, 62 | "metadata": {}, 63 | "output_type": "execute_result" 64 | } 65 | ], 66 | "source": [ 67 | "acc.cash" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 6, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "order2=acc.send_order(code='RB1901', amount=1, time='2018-12-28 09:30:00', towards=QA.ORDER_DIRECTION.SELL_OPEN, price=3420, money=None, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 7, 82 | "metadata": {}, 83 | "outputs": [ 84 | { 85 | "data": { 86 | "text/plain": [ 87 | "6579.1449999999995" 88 | ] 89 | }, 90 | "execution_count": 7, 91 | "metadata": {}, 92 | "output_type": "execute_result" 93 | } 94 | ], 95 | "source": [ 96 | "acc.cash_available" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 8, 102 | "metadata": {}, 103 | "outputs": [ 104 | { 105 | "data": { 106 | "text/plain": [ 107 | "[10000]" 108 | ] 109 | }, 110 | "execution_count": 8, 111 | "metadata": {}, 112 | "output_type": "execute_result" 113 | } 114 | ], 115 | "source": [ 116 | "acc.cash" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 9, 122 | "metadata": {}, 123 | "outputs": [ 124 | { 125 | "data": { 126 | "text/plain": [ 127 | "3" 128 | ] 129 | }, 130 | "execution_count": 9, 131 | "metadata": {}, 132 | "output_type": "execute_result" 133 | } 134 | ], 135 | "source": [ 136 | "QA.ORDER_DIRECTION.BUY_CLOSE" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": 10, 142 | "metadata": {}, 143 | "outputs": [ 144 | { 145 | "name": "stdout", 146 | "output_type": "stream", 147 | "text": [ 148 | "0\n", 149 | "ERROR : CODE RB1901 TIME 2018-12-28 09:30:00 AMOUNT 1 TOWARDS 3\n", 150 | "空单仓位不足\n" 151 | ] 152 | } 153 | ], 154 | "source": [ 155 | "order3=acc.send_order(code='RB1901', amount=1, time='2018-12-28 09:30:00', towards=QA.ORDER_DIRECTION.BUY_CLOSE, price=3420, money=None, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT)" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 11, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "data": { 165 | "text/plain": [ 166 | "6579.1449999999995" 167 | ] 168 | }, 169 | "execution_count": 11, 170 | "metadata": {}, 171 | "output_type": "execute_result" 172 | } 173 | ], 174 | "source": [ 175 | "acc.cash_available" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 12, 181 | "metadata": {}, 182 | "outputs": [ 183 | { 184 | "data": { 185 | "text/plain": [ 186 | "Series([], Name: amount, dtype: float64)" 187 | ] 188 | }, 189 | "execution_count": 12, 190 | "metadata": {}, 191 | "output_type": "execute_result" 192 | } 193 | ], 194 | "source": [ 195 | "acc.hold_available" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 13, 201 | "metadata": {}, 202 | "outputs": [ 203 | { 204 | "name": "stdout", 205 | "output_type": "stream", 206 | "text": [ 207 | "ERROR : CODE RB1901 TIME 2018-12-28 09:30:00 AMOUNT 1 TOWARDS -3\n", 208 | "卖出仓位不足\n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "order4=acc.send_order(code='RB1901', amount=1, time='2018-12-28 09:30:00', towards=QA.ORDER_DIRECTION.SELL_CLOSE, price=3420, money=None, order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT)" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": null, 219 | "metadata": {}, 220 | "outputs": [], 221 | "source": [] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": null, 226 | "metadata": {}, 227 | "outputs": [], 228 | "source": [] 229 | } 230 | ], 231 | "metadata": { 232 | "kernelspec": { 233 | "display_name": "Python 3", 234 | "language": "python", 235 | "name": "python3" 236 | }, 237 | "language_info": { 238 | "codemirror_mode": { 239 | "name": "ipython", 240 | "version": 3 241 | }, 242 | "file_extension": ".py", 243 | "mimetype": "text/x-python", 244 | "name": "python", 245 | "nbconvert_exporter": "python", 246 | "pygments_lexer": "ipython3", 247 | "version": "3.6.7" 248 | } 249 | }, 250 | "nbformat": 4, 251 | "nbformat_minor": 2 252 | } 253 | -------------------------------------------------------------------------------- /test_backtest/PERFORMANCE.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # In[2]: 5 | 6 | 7 | import QUANTAXIS as QA 8 | 9 | 10 | # In[4]: 11 | 12 | 13 | AC=QA.QA_Account().from_message(QA.QA_fetch_account()[-1]) 14 | 15 | 16 | # In[6]: 17 | 18 | 19 | pr=QA.QA_Performance(AC) 20 | 21 | 22 | # In[8]: 23 | 24 | 25 | pr.pnl_fifo 26 | 27 | 28 | # In[11]: 29 | 30 | 31 | pr.plot_pnlmoney(pr.pnl_fifo) 32 | 33 | 34 | # In[12]: 35 | 36 | 37 | pr.plot_pnlratio(pr.pnl_fifo) 38 | 39 | -------------------------------------------------------------------------------- /test_backtest/QAMARKET_SyncOrderExample.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # In[1]: 5 | 6 | 7 | import QUANTAXIS as QA 8 | from QUANTAXIS.QAMarket import QA_Market 9 | from QUANTAXIS.QAMarket.QAShipaneBroker import QA_SPEBroker 10 | from QUANTAXIS.QAMarket.QABacktestBroker import QA_BacktestBroker 11 | from concurrent import futures 12 | import threading 13 | import asyncio 14 | 15 | import datetime 16 | import pandas as pd 17 | 18 | 19 | # In[3]: 20 | 21 | 22 | market = QA_Market(if_start_orderthreading=True) 23 | 24 | 25 | # In[4]: 26 | 27 | 28 | market.start() 29 | 30 | 31 | # In[5]: 32 | 33 | 34 | 35 | market.connect(QA.BROKER_TYPE.SHIPANE) 36 | 37 | 38 | # In[6]: 39 | 40 | 41 | market.login(QA.BROKER_TYPE.SHIPANE,'account:1391') 42 | 43 | 44 | # In[7]: 45 | 46 | 47 | market.login(QA.BROKER_TYPE.SHIPANE,'account:141') 48 | 49 | 50 | # In[8]: 51 | 52 | 53 | market.login(QA.BROKER_TYPE.SHIPANE,'account:813') 54 | 55 | 56 | # In[9]: 57 | 58 | 59 | market.get_account_cookie() 60 | 61 | 62 | # In[10]: 63 | 64 | 65 | #data 66 | market._sync_orders() 67 | 68 | 69 | # In[12]: 70 | 71 | 72 | market.order_handler.order_status 73 | 74 | 75 | # In[13]: 76 | 77 | 78 | market.order_handler.deal_status 79 | 80 | -------------------------------------------------------------------------------- /test_backtest/T0backtest.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "QUANTAXIS>> start QUANTAXIS\n", 13 | "QUANTAXIS>> Welcome to QUANTAXIS, the Version is 1.1.0\n", 14 | "QUANTAXIS>> \n", 15 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 16 | " ``########`````##````````##``````````##`````````####````````##```##########````````#``````##``````###```##`````######`` \n", 17 | " `##``````## ```##````````##`````````####````````##`##```````##```````##```````````###``````##````##`````##```##`````##` \n", 18 | " ##````````##```##````````##````````##`##````````##``##``````##```````##``````````####```````#```##``````##```##``````## \n", 19 | " ##````````##```##````````##```````##```##```````##```##`````##```````##`````````##`##```````##`##```````##````##``````` \n", 20 | " ##````````##```##````````##``````##`````##``````##````##````##```````##````````##``###```````###````````##`````##`````` \n", 21 | " ##````````##```##````````##``````##``````##`````##`````##```##```````##```````##````##```````###````````##``````###```` \n", 22 | " ##````````##```##````````##`````##````````##````##``````##``##```````##``````##``````##`````##`##```````##````````##``` \n", 23 | " ##````````##```##````````##````#############````##```````##`##```````##`````###########`````##``##``````##`````````##`` \n", 24 | " ###```````##```##````````##```##```````````##```##```````##`##```````##````##`````````##```##```##``````##```##`````##` \n", 25 | " `##``````###````##``````###``##`````````````##``##````````####```````##```##``````````##``###````##`````##````##`````## \n", 26 | " ``#########``````########```##``````````````###`##``````````##```````##``##````````````##`##``````##````##`````###``### \n", 27 | " ````````#####`````````````````````````````````````````````````````````````````````````````````````````````````````##`` \n", 28 | " ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 29 | " ``````````````````````````Copyright``yutiansut``2018``````QUANTITATIVE FINANCIAL FRAMEWORK````````````````````````````` \n", 30 | " ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 31 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 32 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 33 | " \n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "from QUANTAXIS.QAARP.QAStrategy import QA_Strategy\n", 39 | "from QUANTAXIS.QAARP.QAAccount import QA_Account\n", 40 | "from QUANTAXIS.QAUtil.QAParameter import (AMOUNT_MODEL, MARKET_TYPE,\n", 41 | " FREQUENCE, ORDER_DIRECTION,\n", 42 | " ORDER_MODEL,RUNNING_ENVIRONMENT)\n", 43 | "import QUANTAXIS as QA\n", 44 | "\n", 45 | "import random\n" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 2, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "class MAMINT0Strategy(QA_Account):\n", 55 | " def __init__(self,init_hold={'000001':10000,'000002':20000,'000004':40000}):\n", 56 | " super().__init__(init_hold=init_hold)\n", 57 | " self.running_environment=RUNNING_ENVIRONMENT.TZERO\n", 58 | " self.frequence = FREQUENCE.FIFTEEN_MIN\n", 59 | " self.market_type = MARKET_TYPE.STOCK_CN\n", 60 | " self.account_cookie ='LCW_T0'\n", 61 | "\n", 62 | " def on_bar(self, event):\n", 63 | " try:\n", 64 | " for item in event.market_data.code:\n", 65 | "\n", 66 | " print(self.current_time)\n", 67 | " print(self.datetime)\n", 68 | " print('=====SELL_AVAILABLE======')\n", 69 | " print(self.sell_available)\n", 70 | " print('=====HOLD_AVAILABLE======')\n", 71 | " print(self.hold_available)\n", 72 | " print('=====BUY_AVAILABLE=======')\n", 73 | " print(self.buy_available)\n", 74 | " if self.sell_available.get(item, 0) > 0:\n", 75 | " event.send_order(account_cookie=self.account_cookie,\n", 76 | " amount=int(self.sell_available[item]*random.random()/100)*100, amount_model=AMOUNT_MODEL.BY_AMOUNT,\n", 77 | " time=self.current_time, code=item, price=0,\n", 78 | " order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.SELL,\n", 79 | " market_type=self.market_type, frequence=self.frequence,\n", 80 | " broker_name=self.broker\n", 81 | " )\n", 82 | " if random.random()>0.5:\n", 83 | " event.send_order(account_cookie=self.account_cookie,\n", 84 | " amount=random.randint(1,50)*100, amount_model=AMOUNT_MODEL.BY_AMOUNT,\n", 85 | " time=self.current_time, code=item, price=0,\n", 86 | " order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.BUY,\n", 87 | " market_type=self.market_type, frequence=self.frequence,\n", 88 | " broker_name=self.broker)\n", 89 | " except:\n", 90 | " pass" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 3, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "class MAMINT0Strategy1(QA_Account):\n", 100 | " def __init__(self,init_hold={'000001':10000,'000004':20000,'000008':40000}):\n", 101 | " super().__init__(init_hold=init_hold)\n", 102 | " self.running_environment=RUNNING_ENVIRONMENT.TZERO\n", 103 | " self.frequence = FREQUENCE.FIFTEEN_MIN\n", 104 | " self.market_type = MARKET_TYPE.STOCK_CN\n", 105 | " self.account_cookie ='LCW_T01'\n", 106 | "\n", 107 | " def on_bar(self, event):\n", 108 | " try:\n", 109 | " for item in event.market_data.code:\n", 110 | "\n", 111 | " print(self.current_time)\n", 112 | " print(self.datetime)\n", 113 | " print('=====SELL_AVAILABLE======')\n", 114 | " print(self.sell_available)\n", 115 | " print('=====HOLD_AVAILABLE======')\n", 116 | " print(self.hold_available)\n", 117 | " print('=====BUY_AVAILABLE=======')\n", 118 | " print(self.buy_available)\n", 119 | " if self.sell_available.get(item, 0) > 0:\n", 120 | " event.send_order(account_cookie=self.account_cookie,\n", 121 | " amount=int(self.sell_available[item]*random.random()/100)*100, amount_model=AMOUNT_MODEL.BY_AMOUNT,\n", 122 | " time=self.current_time, code=item, price=0,\n", 123 | " order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.SELL,\n", 124 | " market_type=self.market_type, frequence=self.frequence,\n", 125 | " broker_name=self.broker\n", 126 | " )\n", 127 | " if random.random()>0.5:\n", 128 | " event.send_order(account_cookie=self.account_cookie,\n", 129 | " amount=random.randint(1,50)*100, amount_model=AMOUNT_MODEL.BY_AMOUNT,\n", 130 | " time=self.current_time, code=item, price=0,\n", 131 | " order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.BUY,\n", 132 | " market_type=self.market_type, frequence=self.frequence,\n", 133 | " broker_name=self.broker)\n", 134 | " except:\n", 135 | " pass" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 4, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "account1=MAMINT0Strategy()" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 5, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "account2=MAMINT0Strategy1()" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 6, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | "user=QA.QA_User(user_cookie='LCW')" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 7, 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "data": { 172 | "text/plain": [ 173 | "< QA_Account LCW_T01>" 174 | ] 175 | }, 176 | "execution_count": 7, 177 | "metadata": {}, 178 | "output_type": "execute_result" 179 | } 180 | ], 181 | "source": [ 182 | "account2" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "metadata": {}, 189 | "outputs": [], 190 | "source": [] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": 8, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "port=user.new_portfolio(portfolio_cookie='LCW_t0')" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": 9, 204 | "metadata": {}, 205 | "outputs": [], 206 | "source": [ 207 | "port.add_account(account1)" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 10, 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "port.add_account(account2)" 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": 11, 222 | "metadata": {}, 223 | "outputs": [], 224 | "source": [ 225 | "import pandas as pd" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 12, 231 | "metadata": {}, 232 | "outputs": [ 233 | { 234 | "data": { 235 | "text/html": [ 236 | "
\n", 237 | "\n", 250 | "\n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | "
amount
codeaccount_cookie
000001LCW_T010000
000002LCW_T020000
000004LCW_T040000
000001LCW_T0110000
000004LCW_T0120000
000008LCW_T0140000
\n", 296 | "
" 297 | ], 298 | "text/plain": [ 299 | " amount\n", 300 | "code account_cookie \n", 301 | "000001 LCW_T0 10000\n", 302 | "000002 LCW_T0 20000\n", 303 | "000004 LCW_T0 40000\n", 304 | "000001 LCW_T01 10000\n", 305 | "000004 LCW_T01 20000\n", 306 | "000008 LCW_T01 40000" 307 | ] 308 | }, 309 | "execution_count": 12, 310 | "metadata": {}, 311 | "output_type": "execute_result" 312 | } 313 | ], 314 | "source": [ 315 | "port.init_hold_table" 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": 13, 321 | "metadata": {}, 322 | "outputs": [], 323 | "source": [ 324 | "#pd.concat([account.init_hold_with_account for account in list(port.accounts.values())]).groupby('code').sum()" 325 | ] 326 | }, 327 | { 328 | "cell_type": "code", 329 | "execution_count": 14, 330 | "metadata": {}, 331 | "outputs": [], 332 | "source": [ 333 | "\n", 334 | "from QUANTAXIS.QAARP.QARisk import QA_Risk\n", 335 | "from QUANTAXIS.QAARP.QAUser import QA_User\n", 336 | "from QUANTAXIS.QAApplication.QABacktest import QA_Backtest\n", 337 | "from QUANTAXIS.QAUtil.QALogs import QA_util_log_info\n", 338 | "from QUANTAXIS.QAUtil.QAParameter import FREQUENCE, MARKET_TYPE\n", 339 | "\n", 340 | "\n", 341 | "class Backtest(QA_Backtest):\n", 342 | " '''\n", 343 | " 多线程模式回测示例\n", 344 | "\n", 345 | " '''\n", 346 | "\n", 347 | " def __init__(self, market_type, frequence, start, end, code_list, commission_fee):\n", 348 | " super().__init__(market_type, frequence, start, end, code_list, commission_fee)\n", 349 | " self.user = QA_User()\n", 350 | " t0strategy=MAMINT0Strategy()\n", 351 | " # maminstrategy.reset_assets(1000)\n", 352 | " # self.portfolio, self.account = self.user.register_account(mastrategy)\n", 353 | " self.user = QA_User(user_cookie='user_admin')\n", 354 | " self.portfolio = self.user.new_portfolio('folio_admin')\n", 355 | " self.portfolio, self.account = self.user.register_account(t0strategy)\n", 356 | "\n", 357 | " def after_success(self):\n", 358 | " QA_util_log_info(self.account.history_table)\n", 359 | " risk = QA_Risk(self.account, benchmark_code='000300',\n", 360 | " benchmark_type=MARKET_TYPE.INDEX_CN)\n", 361 | "\n", 362 | " print(risk().T)\n", 363 | "\n", 364 | " self.account.save()\n", 365 | " risk.save()" 366 | ] 367 | }, 368 | { 369 | "cell_type": "code", 370 | "execution_count": null, 371 | "metadata": {}, 372 | "outputs": [], 373 | "source": [] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "execution_count": null, 378 | "metadata": {}, 379 | "outputs": [], 380 | "source": [ 381 | "\n", 382 | "backtest = Backtest(market_type=MARKET_TYPE.STOCK_CN,\n", 383 | " frequence=FREQUENCE.FIFTEEN_MIN,\n", 384 | " start='2018-08-01',\n", 385 | " end='2018-08-05',\n", 386 | " code_list=['000001','000002','000004'],\n", 387 | " commission_fee=0.00015)\n", 388 | "backtest.start_market()\n", 389 | "\n", 390 | "backtest.run()\n", 391 | "backtest.stop()\n" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": null, 397 | "metadata": {}, 398 | "outputs": [], 399 | "source": [ 400 | "backtest.account.hold_available" 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": null, 406 | "metadata": {}, 407 | "outputs": [], 408 | "source": [ 409 | "backtest.account.orders.queue_df" 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": null, 415 | "metadata": {}, 416 | "outputs": [], 417 | "source": [ 418 | "risk=QA.QA_Risk(backtest.account)" 419 | ] 420 | }, 421 | { 422 | "cell_type": "code", 423 | "execution_count": null, 424 | "metadata": {}, 425 | "outputs": [], 426 | "source": [ 427 | "risk.profit_construct" 428 | ] 429 | }, 430 | { 431 | "cell_type": "code", 432 | "execution_count": null, 433 | "metadata": {}, 434 | "outputs": [], 435 | "source": [ 436 | "backtest.account.init_assets" 437 | ] 438 | }, 439 | { 440 | "cell_type": "code", 441 | "execution_count": null, 442 | "metadata": {}, 443 | "outputs": [], 444 | "source": [ 445 | "backtest.account.daily_hold" 446 | ] 447 | }, 448 | { 449 | "cell_type": "code", 450 | "execution_count": null, 451 | "metadata": {}, 452 | "outputs": [], 453 | "source": [] 454 | }, 455 | { 456 | "cell_type": "code", 457 | "execution_count": null, 458 | "metadata": {}, 459 | "outputs": [], 460 | "source": [ 461 | "risk.plot_assets_curve()" 462 | ] 463 | } 464 | ], 465 | "metadata": { 466 | "kernelspec": { 467 | "display_name": "Python 3", 468 | "language": "python", 469 | "name": "python3" 470 | }, 471 | "language_info": { 472 | "codemirror_mode": { 473 | "name": "ipython", 474 | "version": 3 475 | }, 476 | "file_extension": ".py", 477 | "mimetype": "text/x-python", 478 | "name": "python", 479 | "nbconvert_exporter": "python", 480 | "pygments_lexer": "ipython3", 481 | "version": "3.6.6" 482 | } 483 | }, 484 | "nbformat": 4, 485 | "nbformat_minor": 2 486 | } 487 | -------------------------------------------------------------------------------- /test_backtest/T0backtest.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # In[1]: 5 | 6 | 7 | from QUANTAXIS.QAARP.QAStrategy import QA_Strategy 8 | from QUANTAXIS.QAARP.QAAccount import QA_Account 9 | from QUANTAXIS.QAUtil.QAParameter import (AMOUNT_MODEL, MARKET_TYPE, 10 | FREQUENCE, ORDER_DIRECTION, 11 | ORDER_MODEL, RUNNING_ENVIRONMENT) 12 | 13 | 14 | import random 15 | 16 | 17 | # In[2]: 18 | 19 | 20 | class MAMINT0Strategy(QA_Account): 21 | def __init__(self, user_cookie='default', portfolio_cookie='default', init_hold={'000001': 10000}): 22 | super().__init__(user_cookie, portfolio_cookie, init_hold=init_hold) 23 | self.account_cookie = 'T0BACKTEST' 24 | self.running_environment = RUNNING_ENVIRONMENT.TZERO 25 | self.frequence = FREQUENCE.ONE_MIN 26 | self.market_type = MARKET_TYPE.STOCK_CN 27 | 28 | self.result = {} 29 | 30 | def on_bar(self, event): 31 | 32 | # min5= self.market_data.min5 33 | # min15= self.market_data.min15 34 | 35 | # min5macd=QA.QA_indicator_MACD(min5) 36 | # min15macd=QA.QA_indicator_MACD(min15) 37 | # self.result['min5macd']=min5macd 38 | 39 | # self.cash_available # 当前剩余现金 40 | # self.sell_available # 当前可卖股票 41 | # self.history_table # 当前的历史交易 42 | # self.hold_time # 当前的持仓时间 43 | # self.hold_price # 当前持仓的成本价格 44 | # self.get_orders # 获取历史订单 45 | # self.allow_sellopen # 账户是否允许卖空 46 | # self.allow_t0 # 账户是否允许t0 47 | # self.commission_coeff # 账户的手续费(可自行调整) 48 | 49 | try: 50 | for item in event.market_data.code: 51 | 52 | print('================') 53 | print(self.sell_available) 54 | print('================') 55 | print(self.hold_available) 56 | if self.sell_available.get(item, 0) > 0: 57 | event.send_order(account_cookie=self.account_cookie, 58 | amount=self.sell_available[item], amount_model=AMOUNT_MODEL.BY_AMOUNT, 59 | time=self.current_time, code=item, price=0, 60 | order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.SELL, 61 | market_type=self.market_type, frequence=self.frequence, 62 | broker_name=self.broker 63 | ) 64 | else: 65 | event.send_order(account_cookie=self.account_cookie, 66 | amount=100, amount_model=AMOUNT_MODEL.BY_AMOUNT, 67 | time=self.current_time, code=item, price=0, 68 | order_model=ORDER_MODEL.MARKET, towards=ORDER_DIRECTION.BUY, 69 | market_type=self.market_type, frequence=self.frequence, 70 | broker_name=self.broker) 71 | except: 72 | pass 73 | 74 | 75 | # In[3]: 76 | 77 | 78 | from QUANTAXIS.QAARP.QARisk import QA_Risk 79 | from QUANTAXIS.QAARP.QAUser import QA_User 80 | from QUANTAXIS.QAApplication.QABacktest import QA_Backtest 81 | from QUANTAXIS.QAUtil.QALogs import QA_util_log_info 82 | from QUANTAXIS.QAUtil.QAParameter import FREQUENCE, MARKET_TYPE 83 | 84 | 85 | class Backtest(QA_Backtest): 86 | ''' 87 | 多线程模式回测示例 88 | 89 | ''' 90 | 91 | def __init__(self, market_type, frequence, start, end, code_list, commission_fee): 92 | super().__init__(market_type, frequence, start, end, code_list, commission_fee) 93 | self.account = self.portfolio.add_account( MAMINT0Strategy(user_cookie=self.user.user_cookie, portfolio_cookie= self.portfolio.portfolio_cookie)) 94 | 95 | def after_success(self): 96 | QA_util_log_info(self.account.history_table) 97 | risk = QA_Risk(self.account, benchmark_code='000300', 98 | benchmark_type=MARKET_TYPE.INDEX_CN) 99 | 100 | print(risk().T) 101 | self.account.save() 102 | risk.save() 103 | risk.plot_assets_curve() 104 | print(risk.profit_construct) 105 | 106 | 107 | # In[4]: 108 | 109 | 110 | import QUANTAXIS as QA 111 | backtest = Backtest(market_type=MARKET_TYPE.STOCK_CN, 112 | frequence=FREQUENCE.FIFTEEN_MIN, 113 | start='2018-11-01', 114 | end='2018-12-10', 115 | code_list=['000001'], 116 | commission_fee=0.00015) 117 | backtest.start_market() 118 | 119 | backtest.run() 120 | backtest.stop() 121 | 122 | 123 | # In[5]: 124 | 125 | 126 | print(backtest.account.history_table) 127 | -------------------------------------------------------------------------------- /test_backtest/TEST_MARKET_SETTLE.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "QUANTAXIS>> start QUANTAXIS\n", 13 | "QUANTAXIS>> Welcome to QUANTAXIS, the Version is 1.1.0\n", 14 | "QUANTAXIS>> \n", 15 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 16 | " ``########`````##````````##``````````##`````````####````````##```##########````````#``````##``````###```##`````######`` \n", 17 | " `##``````## ```##````````##`````````####````````##`##```````##```````##```````````###``````##````##`````##```##`````##` \n", 18 | " ##````````##```##````````##````````##`##````````##``##``````##```````##``````````####```````#```##``````##```##``````## \n", 19 | " ##````````##```##````````##```````##```##```````##```##`````##```````##`````````##`##```````##`##```````##````##``````` \n", 20 | " ##````````##```##````````##``````##`````##``````##````##````##```````##````````##``###```````###````````##`````##`````` \n", 21 | " ##````````##```##````````##``````##``````##`````##`````##```##```````##```````##````##```````###````````##``````###```` \n", 22 | " ##````````##```##````````##`````##````````##````##``````##``##```````##``````##``````##`````##`##```````##````````##``` \n", 23 | " ##````````##```##````````##````#############````##```````##`##```````##`````###########`````##``##``````##`````````##`` \n", 24 | " ###```````##```##````````##```##```````````##```##```````##`##```````##````##`````````##```##```##``````##```##`````##` \n", 25 | " `##``````###````##``````###``##`````````````##``##````````####```````##```##``````````##``###````##`````##````##`````## \n", 26 | " ``#########``````########```##``````````````###`##``````````##```````##``##````````````##`##``````##````##`````###``### \n", 27 | " ````````#####`````````````````````````````````````````````````````````````````````````````````````````````````````##`` \n", 28 | " ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 29 | " ``````````````````````````Copyright``yutiansut``2018``````QUANTITATIVE FINANCIAL FRAMEWORK````````````````````````````` \n", 30 | " ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 31 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 32 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 33 | " \n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "import QUANTAXIS as QA\n", 39 | "\n", 40 | "import threading\n", 41 | "import pandas as pd\n", 42 | "\n", 43 | "import time" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 2, 49 | "metadata": {}, 50 | "outputs": [ 51 | { 52 | "name": "stdout", 53 | "output_type": "stream", 54 | "text": [ 55 | "sub\n", 56 | "subscribe\n", 57 | "[<_MainThread(MainThread, started 21604)>, , , , , , , , , , ]\n" 58 | ] 59 | } 60 | ], 61 | "source": [ 62 | "# utf-8\n", 63 | "import QUANTAXIS as QA\n", 64 | "\n", 65 | "market = QA.QA_Market(if_start_orderthreading=True)\n", 66 | "portfolio= QA.QA_Portfolio()\n", 67 | "# 创建两个account\n", 68 | "# 这里是创建一个资产组合,然后在组合里面创建两个account 你可以想象成股票里面的两个策略账户\n", 69 | "# 然后返回的是这个账户的id\n", 70 | "a_1 = portfolio.new_account()\n", 71 | "a_1.reset_assets(100000000)\n", 72 | "a_1.frequence = QA.FREQUENCE.ONE_MIN\n", 73 | "market.start()\n", 74 | "market._sync_orders()\n", 75 | "market.connect(QA.BROKER_TYPE.BACKETEST)\n", 76 | "market.login(QA.BROKER_TYPE.BACKETEST, a_1.account_cookie, a_1)\n", 77 | "\n", 78 | "market.order_handler.monitor\n", 79 | "print(threading.enumerate())" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 3, 85 | "metadata": {}, 86 | "outputs": [ 87 | { 88 | "name": "stderr", 89 | "output_type": "stream", 90 | "text": [ 91 | "QUANTAXIS>> MARKET WARING: SOMEING WRONG WITH ORDER \n", 92 | " \n", 93 | "QUANTAXIS>> code 000001 date 2018-08-14 14:58:00 price 0 order_model MARKET amount_model by_amount\n", 94 | "QUANTAXIS>> MARKET WARING: SOMEING WRONG WITH ORDER \n", 95 | " \n", 96 | "QUANTAXIS>> code 000004 date 2018-08-14 14:58:00 price 0 order_model MARKET amount_model by_amount\n" 97 | ] 98 | } 99 | ], 100 | "source": [ 101 | "for code in ['000001', '000002', '000004', '600010', '000007','600000']:\n", 102 | " market.insert_order(a_1.account_cookie,code=code,\n", 103 | " price=0,\n", 104 | " amount=1000,\n", 105 | " time='2018-08-14 14:58:00',\n", 106 | " towards=QA.ORDER_DIRECTION.BUY,\n", 107 | " order_model=QA.ORDER_MODEL.MARKET,\n", 108 | " amount_model=QA.AMOUNT_MODEL.BY_AMOUNT,\n", 109 | " market_type=QA.MARKET_TYPE.STOCK_CN,\n", 110 | " frequence=QA.FREQUENCE.ONE_MIN,\n", 111 | " broker_name=QA.BROKER_TYPE.BACKETEST,\n", 112 | " )\n", 113 | "while True:\n", 114 | " if len(market.order_handler.order_queue.untrade)==0:\n", 115 | " break\n" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 4, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [ 124 | "market.settle_order()" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 5, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "name": "stdout", 134 | "output_type": "stream", 135 | "text": [ 136 | "['Acc_HgDIe1qk', '2018-08-14 14:58:00', '2018-08-14 14:58:00', '000002', None, 1, 22.33, 22.33, 'trade_success', 1000, 1000, 22335.5825, 0, 'Order_LYjbzuBt', 'Trade_92iCzWUE']\n", 137 | "on_insert_order\n", 138 | "< QA_Order realorder_id Order_LYjbzuBt datetime:2018-08-14 14:58:00 code:000002 amount:1000 price:22.33 towards:1 btype:stock_cn order_id:Order_LYjbzuBt account:Acc_HgDIe1qk status:queued >\n", 139 | "queued\n", 140 | "['Acc_HgDIe1qk', '2018-08-14 14:58:00', '2018-08-14 14:58:00', '600010', None, 1, 1.63, 1.63, 'trade_success', 1000, 1000, 1635.0, 0, 'Order_FLyq7JBN', 'Trade_USTZ08F1']\n", 141 | "on_insert_order\n", 142 | "< QA_Order realorder_id Order_FLyq7JBN datetime:2018-08-14 14:58:00 code:600010 amount:1000 price:1.63 towards:1 btype:stock_cn order_id:Order_FLyq7JBN account:Acc_HgDIe1qk status:queued >\n", 143 | "queued\n", 144 | "['Acc_HgDIe1qk', '2018-08-14 14:58:00', '2018-08-14 14:58:00', '000007', None, 1, 0.0, 13.23, 'trade_price_limit', 1000, 0, 5, 0, 'Order_OIuxT70K', 'Trade_jn5GlHwK']\n", 145 | "on_insert_order\n", 146 | "< QA_Order realorder_id Order_OIuxT70K datetime:2018-08-14 14:58:00 code:000007 amount:1000 price:13.23 towards:1 btype:stock_cn order_id:Order_OIuxT70K account:Acc_HgDIe1qk status:queued >\n", 147 | "queued\n", 148 | "['Acc_HgDIe1qk', '2018-08-14 14:58:00', '2018-08-14 14:58:00', '600000', None, 1, 10.07, 10.065000000000001, 'trade_success', 1000, 1000, 10070.000000000002, 0, 'Order_JkyYMKu3', 'Trade_JNOqDLPG']\n", 149 | "on_insert_order\n", 150 | "< QA_Order realorder_id Order_JkyYMKu3 datetime:2018-08-14 14:58:00 code:600000 amount:1000 price:10.065000000000001 towards:1 btype:stock_cn order_id:Order_JkyYMKu3 account:Acc_HgDIe1qk status:queued >\n", 151 | "queued\n", 152 | "SETTLE ORDERHANDLER\n", 153 | "11468\n", 154 | "receive deal\n", 155 | "11468\n", 156 | "receive deal\n", 157 | "11468\n", 158 | "11468\n", 159 | "receive deal\n", 160 | "True\n", 161 | "[]\n", 162 | "settled\n" 163 | ] 164 | } 165 | ], 166 | "source": [ 167 | "market.trade_engine.join()" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 7, 173 | "metadata": {}, 174 | "outputs": [ 175 | { 176 | "data": { 177 | "text/html": [ 178 | "
\n", 179 | "\n", 192 | "\n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | "
datetimecodepriceamountcashorder_idrealorder_idtrade_idaccount_cookiecommissiontax
02018-08-14 14:58:0000000222.3310009.997763e+07Order_LYjbzuBtOrder_LYjbzuBtTrade_lQ7NMwHuAcc_HgDIe1qk5.582533.495
12018-08-14 14:58:006000101.6310009.997600e+07Order_FLyq7JBNOrder_FLyq7JBNTrade_7MW4lamQAcc_HgDIe1qk0.40752.445
22018-08-14 14:58:0060000010.0710009.996591e+07Order_JkyYMKu3Order_JkyYMKu3Trade_ZzMWFyilAcc_HgDIe1qk2.517515.105
\n", 254 | "
" 255 | ], 256 | "text/plain": [ 257 | " datetime code price amount cash order_id \\\n", 258 | "0 2018-08-14 14:58:00 000002 22.33 1000 9.997763e+07 Order_LYjbzuBt \n", 259 | "1 2018-08-14 14:58:00 600010 1.63 1000 9.997600e+07 Order_FLyq7JBN \n", 260 | "2 2018-08-14 14:58:00 600000 10.07 1000 9.996591e+07 Order_JkyYMKu3 \n", 261 | "\n", 262 | " realorder_id trade_id account_cookie commission tax \n", 263 | "0 Order_LYjbzuBt Trade_lQ7NMwHu Acc_HgDIe1qk 5.5825 33.495 \n", 264 | "1 Order_FLyq7JBN Trade_7MW4lamQ Acc_HgDIe1qk 0.4075 2.445 \n", 265 | "2 Order_JkyYMKu3 Trade_ZzMWFyil Acc_HgDIe1qk 2.5175 15.105 " 266 | ] 267 | }, 268 | "execution_count": 7, 269 | "metadata": {}, 270 | "output_type": "execute_result" 271 | } 272 | ], 273 | "source": [ 274 | "a_1.history_table" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 8, 280 | "metadata": {}, 281 | "outputs": [ 282 | { 283 | "data": { 284 | "text/plain": [ 285 | "True" 286 | ] 287 | }, 288 | "execution_count": 8, 289 | "metadata": {}, 290 | "output_type": "execute_result" 291 | } 292 | ], 293 | "source": [ 294 | "market.order_handler.if_start_orderquery" 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": null, 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [] 303 | }, 304 | { 305 | "cell_type": "code", 306 | "execution_count": null, 307 | "metadata": {}, 308 | "outputs": [], 309 | "source": [] 310 | }, 311 | { 312 | "cell_type": "code", 313 | "execution_count": null, 314 | "metadata": {}, 315 | "outputs": [], 316 | "source": [] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": null, 321 | "metadata": {}, 322 | "outputs": [], 323 | "source": [] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": null, 328 | "metadata": {}, 329 | "outputs": [], 330 | "source": [] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": null, 335 | "metadata": {}, 336 | "outputs": [], 337 | "source": [] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": null, 342 | "metadata": {}, 343 | "outputs": [], 344 | "source": [] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "execution_count": null, 349 | "metadata": {}, 350 | "outputs": [], 351 | "source": [] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": null, 356 | "metadata": {}, 357 | "outputs": [], 358 | "source": [] 359 | }, 360 | { 361 | "cell_type": "code", 362 | "execution_count": null, 363 | "metadata": {}, 364 | "outputs": [], 365 | "source": [] 366 | } 367 | ], 368 | "metadata": { 369 | "kernelspec": { 370 | "display_name": "Python 3", 371 | "language": "python", 372 | "name": "python3" 373 | }, 374 | "language_info": { 375 | "codemirror_mode": { 376 | "name": "ipython", 377 | "version": 3 378 | }, 379 | "file_extension": ".py", 380 | "mimetype": "text/x-python", 381 | "name": "python", 382 | "nbconvert_exporter": "python", 383 | "pygments_lexer": "ipython3", 384 | "version": "3.6.6" 385 | } 386 | }, 387 | "nbformat": 4, 388 | "nbformat_minor": 2 389 | } 390 | -------------------------------------------------------------------------------- /test_backtest/TEST_MARKET_SETTLE.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # In[1]: 5 | 6 | 7 | import QUANTAXIS as QA 8 | 9 | import threading 10 | import pandas as pd 11 | 12 | import time 13 | 14 | 15 | # In[2]: 16 | 17 | 18 | # utf-8 19 | import QUANTAXIS as QA 20 | 21 | market = QA.QA_Market(if_start_orderthreading=True) 22 | portfolio = QA.QA_Portfolio() 23 | # 创建两个account 24 | # 这里是创建一个资产组合,然后在组合里面创建两个account 你可以想象成股票里面的两个策略账户 25 | # 然后返回的是这个账户的id 26 | a_1 = portfolio.new_account() 27 | a_1.reset_assets(100000000) 28 | a_1.frequence = QA.FREQUENCE.ONE_MIN 29 | market.start() 30 | market._sync_orders() 31 | market.connect(QA.BROKER_TYPE.BACKETEST) 32 | market.login(QA.BROKER_TYPE.BACKETEST, a_1.account_cookie, a_1) 33 | 34 | market.order_handler.monitor 35 | 36 | 37 | # In[3]: 38 | 39 | 40 | for code in ['000001', '000002', '000004', '600010', '000007', '600000']: 41 | market.insert_order(a_1.account_cookie, code=code, 42 | price=0, 43 | amount=1000, 44 | time='2018-08-14 14:58:00', 45 | towards=QA.ORDER_DIRECTION.BUY, 46 | order_model=QA.ORDER_MODEL.MARKET, 47 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT, 48 | market_type=QA.MARKET_TYPE.STOCK_CN, 49 | frequence=QA.FREQUENCE.ONE_MIN, 50 | broker_name=QA.BROKER_TYPE.BACKETEST, 51 | ) 52 | 53 | 54 | # In[4]: 55 | 56 | 57 | print(market.trade_engine.queue.qsize()) 58 | 59 | 60 | # In[5]: 61 | 62 | 63 | print(market.trade_engine.kernels_dict['ORDER'].queue.qsize()) 64 | 65 | 66 | # In[6]: 67 | 68 | 69 | print(market.trade_engine.kernels_dict[QA.BROKER_TYPE.BACKETEST].queue.qsize()) 70 | 71 | 72 | # In[7]: 73 | 74 | 75 | # ma 76 | 77 | 78 | # In[8]: 79 | 80 | 81 | # In[ ]: 82 | 83 | 84 | # market.trade_engine.kernels_dict['ORDER'].queue.task_done() 85 | 86 | market.settle_order() 87 | 88 | 89 | # In[ ]: 90 | 91 | market.trade_engine.join() 92 | # market.trade_engine.kernels_dict['ORDER'].queue.join() 93 | 94 | print(a_1.history_table) 95 | # In[ ]: 96 | 97 | 98 | # market.trade_engine.join() 99 | 100 | 101 | # In[ ]: 102 | -------------------------------------------------------------------------------- /test_backtest/backtest_debug.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | from QUANTAXIS.QAARP.QARisk import QA_Risk 27 | from QUANTAXIS.QAARP.QAUser import QA_User 28 | from QUANTAXIS.QAApplication.QABacktest import QA_Backtest 29 | from QUANTAXIS.QAUtil.QALogs import QA_util_log_info 30 | from QUANTAXIS.QAUtil.QAParameter import FREQUENCE, MARKET_TYPE 31 | from test_backtest.minstrategy import MAMINStrategy 32 | from test_backtest.strategy import MAStrategy 33 | 34 | 35 | class Backtest(QA_Backtest): 36 | ''' 37 | 多线程模式回测示例 38 | 39 | ''' 40 | 41 | def __init__(self, market_type, frequence, start, end, code_list, commission_fee): 42 | super().__init__(market_type, frequence, start, end, code_list, commission_fee) 43 | self.user = QA_User() 44 | mastrategy = MAStrategy() 45 | maminstrategy = MAMINStrategy() 46 | # maminstrategy.reset_assets(1000) 47 | # self.portfolio, self.account = self.user.register_account(mastrategy) 48 | self.user = QA_User(user_cookie='user_admin') 49 | self.portfolio = self.user.new_portfolio('folio_admin') 50 | self.portfolio, self.account = self.user.register_account(mastrategy) 51 | 52 | print(self.user) 53 | print(self.portfolio) 54 | print(self.account) 55 | print(self.account.message) 56 | 57 | def after_success(self): 58 | QA_util_log_info(self.account.history_table) 59 | risk = QA_Risk(self.account, benchmark_code='000300', 60 | benchmark_type=MARKET_TYPE.INDEX_CN) 61 | 62 | print(risk().T) 63 | fig=risk.plot_assets_curve() 64 | fig.show() 65 | fig=risk.plot_dailyhold() 66 | fig.show() 67 | fig=risk.plot_signal() 68 | fig.show() 69 | self.account.save() 70 | risk.save() 71 | 72 | 73 | def run_daybacktest(): 74 | import QUANTAXIS as QA 75 | backtest = Backtest(market_type=MARKET_TYPE.STOCK_CN, 76 | frequence=FREQUENCE.DAY, 77 | start='2017-01-01', 78 | end='2017-02-10', 79 | code_list=QA.QA_fetch_stock_block_adv().code[0:5], 80 | commission_fee=0.00015) 81 | backtest.start_market() 82 | 83 | backtest.run() 84 | backtest.stop() 85 | 86 | 87 | def run_minbacktest(): 88 | import QUANTAXIS as QA 89 | backtest = Backtest(market_type=MARKET_TYPE.STOCK_CN, 90 | frequence=FREQUENCE.FIFTEEN_MIN, 91 | start='2017-11-01', 92 | end='2017-11-10', 93 | code_list=QA.QA_fetch_stock_block_adv().code[0:5], 94 | commission_fee=0.00015) 95 | backtest.start_market() 96 | 97 | backtest.run() 98 | backtest.stop() 99 | 100 | 101 | if __name__ == '__main__': 102 | run_daybacktest() 103 | #run_minbacktest() 104 | 105 | -------------------------------------------------------------------------------- /test_backtest/example/indicator/macd.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import QUANTAXIS as QA 3 | import pandas as pd 4 | 5 | def MACD_JCSC(dataframe, SHORT=12, LONG=26, M=9): 6 | """ 7 | 1.DIF向上突破DEA,买入信号参考。 8 | 2.DIF向下跌破DEA,卖出信号参考。 9 | """ 10 | CLOSE = dataframe.close 11 | DIFF = QA.EMA(CLOSE, SHORT) - QA.EMA(CLOSE, LONG) 12 | DEA = QA.EMA(DIFF, M) 13 | MACD = 2*(DIFF-DEA) 14 | 15 | CROSS_JC = QA.CROSS(DIFF, DEA) 16 | CROSS_SC = QA.CROSS(DEA, DIFF) 17 | ZERO = 0 18 | return pd.DataFrame({'DIFF': DIFF, 'DEA': DEA, 'MACD': MACD, 'CROSS_JC': CROSS_JC, 'CROSS_SC': CROSS_SC, 'ZERO': ZERO}) 19 | -------------------------------------------------------------------------------- /test_backtest/example/simple_backtest_day.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: zhongjy 3 | # @Date: 2018-08-27 00:21:02 4 | # @Last Modified by: Jingyao.Zhong 5 | # @Last Modified time: 2018-08-27 10:19:26 6 | import math 7 | import QUANTAXIS as QA 8 | 9 | from indicator.macd import MACD_JCSC 10 | 11 | try: 12 | if QA.__version__>'1.1.0': 13 | pass 14 | else: 15 | print('quantaxis version < 1.1.0; please upgrade quantaxis.\npip install quantaxis==1.1.0') 16 | exit() 17 | except Exception as e: 18 | print('quantaxis version < 1.1.0; please upgrade quantaxis.\npip install quantaxis==1.1.0') 19 | exit() 20 | 21 | def simple_backtest(AC:QA.QA_Account, code, start:str, end:str): 22 | ''' 23 | 24 | :param AC: QA_Account 25 | :param code: 股票代码 26 | :type list or str 27 | :param start: 回测开始时间 28 | :param end: 回测结束时间 29 | :return: 30 | ''' 31 | # 取数并前复权 32 | DATA = QA.QA_fetch_stock_day_adv(code, start, end).to_qfq() 33 | # todo 计算信号 34 | stock_signal = DATA.add_func(MACD_JCSC, 12, 26, 9) 35 | 36 | 37 | for peroid_item in DATA.panel_gen: 38 | # 一天过去了 39 | 40 | for stock_item in peroid_item.security_gen: 41 | # 当天的某个股票 42 | 43 | cur_stock_code = stock_item.code[0] 44 | cur_stock_date = stock_item.date[0] 45 | # 可卖数量 46 | cur_account_sotck_code_sell_available_amount = AC.sell_available.get(cur_stock_code, 0) 47 | 48 | cur_sotck_operation_towards = None 49 | # todo 提取对应的信号 50 | cur_stock_signal = stock_signal.loc[cur_stock_date, cur_stock_code]['DIFF'] 51 | # 剔除无效信号 52 | if cur_stock_signal is None or math.isnan(cur_stock_signal): 53 | continue 54 | 55 | if cur_stock_signal > 0 and cur_account_sotck_code_sell_available_amount == 0: 56 | # 买入信号, 持仓为0, 方向: 买入 57 | # 买入方式, QA.ORDER_DIRECTION.BUY, QA.ORDER_DIRECTION.BUY_CLOSE, QA.ORDER_DIRECTION.BUY_OPEN 58 | cur_sotck_operation_towards = QA.ORDER_DIRECTION.BUY 59 | 60 | elif cur_stock_signal > 0 and cur_account_sotck_code_sell_available_amount > 0: 61 | # 买入信号, 持仓不为0, 方向: 持有 62 | cur_sotck_operation_towards = None 63 | pass 64 | elif cur_stock_signal < 0 and cur_account_sotck_code_sell_available_amount == 0: 65 | # 卖出信号, 持仓为0, 忽略 66 | cur_sotck_operation_towards =None 67 | pass 68 | elif cur_stock_signal < 0 and cur_account_sotck_code_sell_available_amount > 0: 69 | # 买入信号, 持仓不为0, 方向: 卖出 70 | cur_sotck_operation_towards = QA.ORDER_DIRECTION.SELL 71 | 72 | if cur_sotck_operation_towards is None: 73 | continue 74 | 75 | order = None 76 | if cur_sotck_operation_towards == QA.ORDER_DIRECTION.BUY: 77 | # 97 % 仓 买入 78 | maxMoney = 0.97 * AC.cash_available 79 | # closePrice = stock_item.close[0] 80 | highPrice = stock_item.high[0] 81 | lowPrice = stock_item.low[0] 82 | avgPrice = (highPrice + lowPrice) / 2 83 | 84 | if round(avgPrice, 2) < avgPrice: 85 | avgPrice = round(avgPrice, 2) + 0.01 86 | 87 | maxBuyAmount = int(maxMoney / (avgPrice * (1 + commission_coeff) * 100)) * 100 88 | 89 | print('cash_available {}'.format(AC.cash_available)) 90 | print("可用资金: %s, 预计买入 %s , %s, %s, %s,股" % (maxMoney, cur_stock_code, cur_stock_date, avgPrice, maxBuyAmount)) 91 | order = AC.send_order( 92 | code=cur_stock_code, time=cur_stock_date, towards=cur_sotck_operation_towards, 93 | order_model=QA.ORDER_MODEL.MARKET, 94 | amount_model=QA.AMOUNT_MODEL.BY_MONEY, 95 | money=maxMoney, 96 | price=avgPrice, 97 | ) 98 | elif cur_sotck_operation_towards == QA.ORDER_DIRECTION.SELL: 99 | # 市价 全仓卖出 100 | order = AC.send_order( 101 | code=cur_stock_code, time=cur_stock_date, towards=cur_sotck_operation_towards, 102 | order_model=QA.ORDER_MODEL.MARKET, amount_model=QA.AMOUNT_MODEL.BY_AMOUNT, 103 | amount=cur_account_sotck_code_sell_available_amount, price=0, 104 | 105 | ) 106 | 107 | if order is not None and order: 108 | Broker.receive_order(QA.QA_Event(order=order, market_data=stock_item)) 109 | trade_mes = Broker.query_orders(AC.account_cookie, 'filled') 110 | res = trade_mes.loc[order.account_cookie, order.realorder_id] 111 | order.trade(res.trade_id, res.trade_price, 112 | res.trade_amount, res.trade_time) 113 | # 当天结算 114 | AC.settle() 115 | 116 | 117 | if __name__ == '__main__': 118 | # 策略名称 119 | strategy_name = 'MACD_JCSC' 120 | # 用户cookie 121 | user_cookie = 'user1' 122 | # 组合cookie 123 | portfolio_cookie = 'win300' 124 | # 账户cookie 125 | account_cookie = 'bba' 126 | benchmark_code = '000300' 127 | initial_cash = 200000 128 | initial_hold = {} 129 | # 交易佣金 130 | commission_coeff = 0.00025 131 | # 印花税 132 | tax_coeff = 0.0015 133 | 134 | # backtest_code_list = QA.QA_fetch_stock_block_adv().code[0:10] 135 | backtest_code_list = '000001' 136 | backtest_start_date = '2018-01-01' 137 | backtest_end_date = '2018-08-25' 138 | 139 | Broker = QA.QA_BacktestBroker() 140 | AC = QA.QA_Account( 141 | strategy_name=strategy_name, 142 | user_cookie=user_cookie, 143 | portfolio_cookie=portfolio_cookie, 144 | account_cookie=account_cookie, 145 | init_hold=initial_hold, 146 | init_cash=initial_cash, 147 | commission_coeff=commission_coeff, 148 | tax_coeff=tax_coeff, 149 | market_type=QA.MARKET_TYPE.STOCK_CN, 150 | frequence=QA.FREQUENCE.DAY 151 | ) 152 | # 设置初始资金 153 | # AC.reset_assets(20000000) 154 | 155 | # 回测 156 | simple_backtest(AC, backtest_code_list, backtest_start_date, backtest_end_date) 157 | 158 | AC.save() 159 | 160 | # 结果 161 | print(AC.message) 162 | print(AC.history_table) 163 | 164 | 165 | 166 | # 分析 167 | risk = QA.QA_Risk(account=AC, benchmark_code=benchmark_code, benchmark_type=QA.MARKET_TYPE.INDEX_CN, if_fq=False) 168 | risk.save() 169 | 170 | print(risk.message) 171 | fig=risk.plot_assets_curve() 172 | 173 | fig.plot() -------------------------------------------------------------------------------- /test_backtest/make_order.md: -------------------------------------------------------------------------------- 1 | # 下单说明: 2 | 3 | ## 全仓买入测试 4 | 5 | ```python 6 | # 初始化一个account 7 | Account=QA.QA_Account() 8 | 9 | # 全仓买入'000001' 10 | 11 | Order=Account.send_order(code='000001', 12 | price=11, 13 | money=Account.cash_available, 14 | time='2018-05-09', 15 | towards=QA.ORDER_DIRECTION.BUY, 16 | order_model=QA.ORDER_MODEL.MARKET, 17 | amount_model=QA.AMOUNT_MODEL.BY_MONEY 18 | ) 19 | 20 | 21 | # 打印剩余资金 22 | Account.cash_available 23 | Out[5]: 950.2999999999302 24 | 25 | ## 打印order的占用资金 26 | (Order.amount*Order.price)*(1+Account.commission_coeff) 27 | Out[6]: 999049.7000000001 28 | 29 | ## order占用的资金和account的资金相加等于总和 30 | 999049.7000000001+950.2999999999302 31 | Out[7]: 1000000.0 32 | ``` -------------------------------------------------------------------------------- /test_backtest/strategy_qsdd.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Name: QSDD strategy 3 | 4 | import QUANTAXIS as QA 5 | import numpy as np 6 | import pandas as pd 7 | import talib 8 | import matplotlib as mpl 9 | import matplotlib.pyplot as plt 10 | import seaborn as sns 11 | 12 | # code_list = ['000001', '000002', '000004', '600000', 13 | # '600536', '000936', '002023', '600332', 14 | # '600398', '300498', '603609', '300673'] 15 | code_list = QA.QA_fetch_stock_block_adv().code[0:50] 16 | start_date = '2017-01-01' 17 | end_date = '2018-05-23' 18 | 19 | ''' 20 | QSDD 21 | 趋势顶底(QSDD)指标介绍 22 | 23 | ''' 24 | 25 | # define the QSDD strategy 26 | 27 | 28 | def QSDD(dataframe, SHORT=12, LONG=26, M=9): 29 | """ 30 | 1.line_mid向上突破line_long,买入信号参考。 31 | 2.line_mid向下跌破line_long,卖出信号参考。 32 | """ 33 | OPEN = dataframe.open 34 | HIGH = dataframe.high 35 | LOW = dataframe.low 36 | CLOSE = dataframe.close 37 | 38 | # QSDD策略 39 | # A = talib.MA(-100 * (talib.MAX(HIGH, 34) - CLOSE) / (talib.MAX(HIGH, 34) - talib.MIN(LOW, 34)), 19) 40 | # B = -100 * (talib.MAX(HIGH, 14) - CLOSE) / (talib.MAX(HIGH, 14) - talib.MIN(LOW, 14)) 41 | # D = talib.EMA(-100 * (talib.MAX(HIGH, 34) - CLOSE) / (talib.MAX(HIGH, 34) - talib.MIN(LOW, 34)), 4) 42 | A = QA.MA(-100 * (QA.HHV(HIGH, 34) - CLOSE) / 43 | (QA.HHV(HIGH, 34) - QA.LLV(LOW, 34)), 19) 44 | B = -100 * (QA.HHV(HIGH, 14) - CLOSE) / \ 45 | (QA.HHV(HIGH, 14) - QA.LLV(LOW, 14)) 46 | D = QA.EMA(-100 * (QA.HHV(HIGH, 34) - CLOSE) / 47 | (QA.HHV(HIGH, 34) - QA.LLV(LOW, 34)), 4) 48 | 49 | line_long = A + 100 50 | line_short = B + 100 51 | line_mid = D + 100 # 信号线 52 | 53 | CROSS_JC = QA.CROSS(line_mid, line_long) 54 | CROSS_SC = QA.CROSS(line_long, line_mid) 55 | return pd.DataFrame({'line_mid': line_mid, 'line_long': line_long, 'CROSS_JC': CROSS_JC, 'CROSS_SC': CROSS_SC}) 56 | 57 | 58 | # create account 59 | Account = QA.QA_Account() 60 | Broker = QA.QA_BacktestBroker() 61 | 62 | Account.reset_assets(1000000) 63 | Account.account_cookie = 'user_admin_qsdd' 64 | 65 | # get data from mongodb 66 | data = QA.QA_fetch_stock_day_adv(code_list, start_date, end_date) 67 | data = data.to_qfq() 68 | 69 | # add indicator 70 | ind = data.add_func(QSDD) 71 | # ind.xs('000001',level=1)['2018-01'].plot() 72 | 73 | # data_forbacktest=data.select_time('2018-01-01','2018-05-20') 74 | data_forbacktest = data 75 | 76 | for items in data_forbacktest.panel_gen: 77 | for item in items.security_gen: 78 | daily_ind = ind.loc[item.index] 79 | if daily_ind.CROSS_JC.iloc[0] > 0: 80 | order = Account.send_order( 81 | code=item.code[0], 82 | time=item.date[0], 83 | amount=1000, 84 | towards=QA.ORDER_DIRECTION.BUY, 85 | price=0, 86 | order_model=QA.ORDER_MODEL.CLOSE, 87 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 88 | ) 89 | Broker.receive_order(QA.QA_Event(order=order, market_data=item)) 90 | trade_mes = Broker.query_orders(Account.account_cookie, 'filled') 91 | res = trade_mes.loc[order.account_cookie, order.realorder_id] 92 | order.trade(res.trade_id, res.trade_price, 93 | res.trade_amount, res.trade_time) 94 | elif daily_ind.CROSS_SC.iloc[0] > 0: 95 | if Account.sell_available.get(item.code[0], 0) > 0: 96 | order = Account.send_order( 97 | code=item.code[0], 98 | time=item.date[0], 99 | amount=Account.sell_available.get(item.code[0], 0), 100 | towards=QA.ORDER_DIRECTION.SELL, 101 | price=0, 102 | order_model=QA.ORDER_MODEL.MARKET, 103 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT 104 | ) 105 | Broker.receive_order(QA.QA_Event( 106 | order=order, market_data=item)) 107 | trade_mes = Broker.query_orders( 108 | Account.account_cookie, 'filled') 109 | res = trade_mes.loc[order.account_cookie, order.realorder_id] 110 | order.trade(res.trade_id, res.trade_price, 111 | res.trade_amount, res.trade_time) 112 | Account.settle() 113 | 114 | print(Account.history) 115 | print(Account.history_table) 116 | print(Account.daily_hold) 117 | 118 | # create Risk analysis 119 | Risk = QA.QA_Risk(Account) 120 | print(Risk.message) 121 | print(Risk.assets) 122 | 123 | # Risk.assets.plot() 124 | # Risk.benchmark_assets.plot() 125 | fig = Risk.plot_assets_curve() 126 | fig.plot() 127 | fig = Risk.plot_dailyhold() 128 | fig.plot() 129 | fig = Risk.plot_signal() 130 | fig.plot() 131 | 132 | # plt.style.use('ggplot') 133 | # f, ax = plt.subplots(figsize=(20, 8)) 134 | # ax.set_title('SIGNAL TABLE --ACCOUNT: {}'.format(Account.account_cookie)) 135 | # ax.set_xlabel('Code') 136 | # ax.set_ylabel('DATETIME', rotation=90) 137 | # import matplotlib.patches as mpatches 138 | # # x2 = Risk.benchmark_assets.x 139 | # 140 | # patch_assert = mpatches.Patch(color='red', label='assert') 141 | # patch_benchmark = mpatches.Patch(label='benchmark') 142 | # plt.legend(handles=[patch_assert, patch_benchmark], loc=0) 143 | # plt.title('Assert and Benchmark') 144 | # 145 | # 146 | # cmap = sns.cubehelix_palette(start=1, rot=3, gamma=0.8, as_cmap=True) 147 | # ht = sns.heatmap(Account.trade.head(55), cmap=cmap, linewidths=0.05, ax=ax) 148 | # # sns.heatmap(Account.trade.head(55), cmap="YlGnBu",linewidths = 0.05, ax = ax) 149 | # # ht.set_xticklabels(rotation=90) 150 | # # ht.set_yticklabels(rotation=90) 151 | # plt.show() 152 | 153 | # # save result 154 | # Account.save() 155 | # Risk.save() 156 | # 157 | # account_info=QA.QA_fetch_account({'account_cookie':'user_admin_macd'}) 158 | # account=QA.QA_Account().from_message(account_info[0]) 159 | # print(account) 160 | -------------------------------------------------------------------------------- /test_backtest/test_insert_orderspeed.py: -------------------------------------------------------------------------------- 1 | # utf-8 2 | import QUANTAXIS as QA 3 | import time 4 | market = QA.QA_Market(if_start_orderthreading=True) 5 | user = QA.QA_Portfolio() 6 | # 创建两个account 7 | # 这里是创建一个资产组合,然后在组合里面创建两个account 你可以想象成股票里面的两个策略账户 8 | # 然后返回的是这个账户的id 9 | a_1 = user.new_account() 10 | a_1.reset_assets(100000000) 11 | a_1.frequence = QA.FREQUENCE.ONE_MIN 12 | market.start() 13 | 14 | market.connect(QA.BROKER_TYPE.BACKETEST) 15 | 16 | # 打印market 17 | print(market) 18 | 19 | """ 20 | 登陆到这个交易前置上 把你刚才的两个账户 21 | """ 22 | # 登陆交易 23 | 24 | market.login(QA.BROKER_TYPE.BACKETEST, a_1.account_cookie, a_1) 25 | market._sync_orders() 26 | for code in ['000001', '000002', '000004', '600010', '000007', '600000']: 27 | market.insert_order(a_1.account_cookie, code=code, 28 | price=0, 29 | amount=1000, 30 | time='2018-08-14 14:58:00', 31 | towards=QA.ORDER_DIRECTION.BUY, 32 | order_model=QA.ORDER_MODEL.MARKET, 33 | amount_model=QA.AMOUNT_MODEL.BY_AMOUNT, 34 | market_type=QA.MARKET_TYPE.STOCK_CN, 35 | frequence=QA.FREQUENCE.ONE_MIN, 36 | broker_name=QA.BROKER_TYPE.BACKETEST, 37 | ) 38 | # market.trade_engine.join() 39 | # market._settle(QA.BROKER_TYPE.BACKETEST) 40 | time.sleep(10) 41 | print(a_1.history) 42 | print(a_1.cash) 43 | print(a_1.cash_available) 44 | print(a_1.history_table) 45 | print(a_1.hold) 46 | 47 | # market.trade_engine.stop_all() 48 | # market.trade_engine.stop() 49 | -------------------------------------------------------------------------------- /test_backtest/关于1.1.0的quantaxis的账户,市场,实盘模拟盘回测.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 前言 : \n", 8 | "\n", 9 | "1.1.0 是对于QA_Market的一个小规模重构,区别以往的订单,成交模式, 故更新一个小版本\n", 10 | "\n", 11 | "本次的更新主要有:\n", 12 | "\n", 13 | "\n", 14 | "[QAData]\n", 15 | "\n", 16 | "1. 修改了采样函数的写法\n", 17 | "2. 修复了tick采样成60min的bug\n", 18 | "3. 修复了因为multiindex导致的QA_DataStruct.to_json方法缺失 datetime/code 字段的问题\n", 19 | "\n", 20 | "[QAMARKET]\n", 21 | "\n", 22 | "\n", 23 | "1. 增加对于实盘易的支持\n", 24 | "2. 将一些基础解析字段挪至基类QABroker中\n", 25 | "3. 基于QAMarket创建的broker/order线程全部变成后台线程\n", 26 | "4. QA_OrderHandler 增加持久化 订单/成交单部分\n", 27 | "5. 修改QAOrder 变成有限状态机, 通过状态机的动作自动改变Order的状态\n", 28 | "6. 修改QABacktest_Broker 适配新的order类\n", 29 | "7. 优化QABroker的状态显示\n", 30 | "8. 将撮合缓存字典重构进QADealer, dealer加入 deal_message(dict) 和deal_df(dataframe),并增加dealer的settle函数\n", 31 | "9. 大量更新QABacktest_Broker方法,使之适配新版本回测\n", 32 | "10. 适配实盘,增加字段解析 trade_towards_cn_en, order_status_cn_en\n", 33 | "11. 修改order的撮合机制, 使用创建order时的callback回调来更新账户\n", 34 | "\n", 35 | "\n", 36 | "[QAEngine]\n", 37 | "\n", 38 | "1. QAThread 初始化增加 daemon选项, 用于创建守护线程\n", 39 | "\n", 40 | "[QAARP]\n", 41 | "\n", 42 | "1. QA_Account 增加 cancel_order方法 撤单操作\n", 43 | "2. 重写QA_Account的receive_deal方法, 适配新版本更新账户\n", 44 | "3. 优化和修改QA_Portfolio 增加对于history/history_table的支持\n", 45 | "\n", 46 | "\n", 47 | "[QASU]\n", 48 | "\n", 49 | "1. save_orderhandler.py 增加 QA_SU_save_order/ QA_SU_save_deal 方法\n", 50 | "2. 增加对于运行时出错的容错处理\n", 51 | "\n", 52 | "[QAUtil]\n", 53 | "\n", 54 | "1. QADate_Trade 增加QA_util_get_order_datetime() 用于获取委托的真实日期 QA_util_get_trade_datetime() 用于获取成交的真实日期\n", 55 | "2. QA_Parameter 修改订单状态\n", 56 | "\n", 57 | "[QAWEB]\n", 58 | "\n", 59 | "1. QAWEB 增加查询股票名称的接口 http://ip:port/marketdata/stock/code?code=xxxxx" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 1, 65 | "metadata": {}, 66 | "outputs": [ 67 | { 68 | "name": "stderr", 69 | "output_type": "stream", 70 | "text": [ 71 | "QUANTAXIS>> start QUANTAXIS\n", 72 | "QUANTAXIS>> Welcome to QUANTAXIS, the Version is 1.1.0\n", 73 | "QUANTAXIS>> \n", 74 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 75 | " ``########`````##````````##``````````##`````````####````````##```##########````````#``````##``````###```##`````######`` \n", 76 | " `##``````## ```##````````##`````````####````````##`##```````##```````##```````````###``````##````##`````##```##`````##` \n", 77 | " ##````````##```##````````##````````##`##````````##``##``````##```````##``````````####```````#```##``````##```##``````## \n", 78 | " ##````````##```##````````##```````##```##```````##```##`````##```````##`````````##`##```````##`##```````##````##``````` \n", 79 | " ##````````##```##````````##``````##`````##``````##````##````##```````##````````##``###```````###````````##`````##`````` \n", 80 | " ##````````##```##````````##``````##``````##`````##`````##```##```````##```````##````##```````###````````##``````###```` \n", 81 | " ##````````##```##````````##`````##````````##````##``````##``##```````##``````##``````##`````##`##```````##````````##``` \n", 82 | " ##````````##```##````````##````#############````##```````##`##```````##`````###########`````##``##``````##`````````##`` \n", 83 | " ###```````##```##````````##```##```````````##```##```````##`##```````##````##`````````##```##```##``````##```##`````##` \n", 84 | " `##``````###````##``````###``##`````````````##``##````````####```````##```##``````````##``###````##`````##````##`````## \n", 85 | " ``#########``````########```##``````````````###`##``````````##```````##``##````````````##`##``````##````##`````###``### \n", 86 | " ````````#####`````````````````````````````````````````````````````````````````````````````````````````````````````##`` \n", 87 | " ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 88 | " ``````````````````````````Copyright``yutiansut``2018``````QUANTITATIVE FINANCIAL FRAMEWORK````````````````````````````` \n", 89 | " ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 90 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 91 | " ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n", 92 | " \n" 93 | ] 94 | } 95 | ], 96 | "source": [ 97 | "import QUANTAXIS as QA\n", 98 | "import pandas as pd\n", 99 | "import threading\n", 100 | "import time\n", 101 | "import datetime\n", 102 | "import numpy as np" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 2, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "if QA.__version__<'1.1.0':\n", 112 | " print('请升级quantaxis后再运行此教程')" 113 | ] 114 | }, 115 | { 116 | "cell_type": "markdown", 117 | "metadata": {}, 118 | "source": [ 119 | "# 首先我们介绍QA_MARKET:\n", 120 | "\n", 121 | "1. 如何理解QA_MARKET:\n", 122 | " QA_MARKET 是一个交易前置, 从使用的角度看,你可以把他理解成一个交易终端(比如同花顺/通达信)\n", 123 | " \n", 124 | " 在去年准备对于MARKET类重构的时候,QA_MARKET的作用图如下:\n", 125 | " \n", 126 | " ![pic](http://pic.yutiansut.com/%E9%87%8D%E6%9E%84%E6%96%87%E6%A1%A3-%E5%B8%82%E5%9C%BA.png)\n", 127 | " \n", 128 | " \n", 129 | " 交易前置主要起的作用是:\n", 130 | " \n", 131 | " 1. 向上接入不同的Broker\n", 132 | " 2. 向下接入不同的账户\n", 133 | " \n", 134 | " broker可以利用不同的接口, 接入不同的市场(股票/期货/港股/美股/模拟盘/回测)\n", 135 | "\n", 136 | "2. QA_MARKET的类构成:\n", 137 | "\n", 138 | " QA_Market继承于 QA_Trade, QA_Trade 是一个交易前置基类, 其中包含了 QA_Engine(用于开启多线程的管理引擎), 以及各种基类方法\n", 139 | "\n", 140 | "3. QA_Market的主要方法:\n", 141 | "\n", 142 | " - start() 启动交易前置\n", 143 | " \n", 144 | " - connect(broker) 连接broker (等同于在同花顺里面选择不同的券商)\n", 145 | " \n", 146 | " - register(broker_name,broker) 注册一个broker(如果不是官方支持的broker)\n", 147 | " \n", 148 | " - login(account_cookie,account) 登陆账户\n", 149 | " \n", 150 | " - login_out(account_cookie,account) 登出\n", 151 | " \n", 152 | " - get_account(account_cookie) 获得账户句柄\n", 153 | " \n", 154 | " - insert_order(account_cookie, amount, amount_model, time, code, price, order_model, towards, market_type, frequence, broker_name, money=None) 插入订单\n", 155 | " \n", 156 | " - cancel_order(broker_name,account_cookie,order_id) 撤单\n", 157 | " \n", 158 | " - cancel_all(broker_name,account_cookie) 某一个账户订单全撤\n", 159 | " \n", 160 | " - query_assets(account_cookie) 查询某个账户的资产\n", 161 | " \n", 162 | " - query_position(account_cookie) 查询某个账户的持仓\n", 163 | " \n", 164 | " - query_cash(account_cookie) 查询某个账户的现金\n", 165 | " \n", 166 | " - query_data(broker_name, frequence, market_type, code, start, end=None) 查询历史行情数据\n", 167 | " \n", 168 | " - query_currentbar(broker_name, market_type, code) 查询当前行情\n", 169 | " \n", 170 | " - get_trading_day() 查询当前交易日期\n", 171 | " \n", 172 | " \n", 173 | "4. QA_Market的非阻塞事件\n", 174 | "\n", 175 | " QA_Market的非阻塞事件由 QA_Engine, Engine 中管理着各个QA_Thread, 通过submit(QA_Task) 和submit_nowait(QA_Task)的方法将事件推送到处理队列中\n", 176 | " \n", 177 | " - upcoming_data(broker, data) 行情推送进交易前置, 分发至market下的所有账户中\n", 178 | " \n", 179 | " - settle(broker) 每日交易结算\n", 180 | " \n", 181 | " - insert_order 插入订单 可以在on_insert_order中写异步处理(需要继承)\n", 182 | " \n", 183 | " 关于submit函数和QA_Task\n", 184 | " \n", 185 | " ![pic](http://pic.yutiansut.com/QUANTAXISEvent.png)\n", 186 | " \n", 187 | " 你可以在QA_Task的QA_Event中自行写入回调来异步调用你的函数\n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | "\n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " " 198 | ] 199 | } 200 | ], 201 | "metadata": { 202 | "kernelspec": { 203 | "display_name": "Python 3", 204 | "language": "python", 205 | "name": "python3" 206 | }, 207 | "language_info": { 208 | "codemirror_mode": { 209 | "name": "ipython", 210 | "version": 3 211 | }, 212 | "file_extension": ".py", 213 | "mimetype": "text/x-python", 214 | "name": "python", 215 | "nbconvert_exporter": "python", 216 | "pygments_lexer": "ipython3", 217 | "version": "3.6.6" 218 | } 219 | }, 220 | "nbformat": 4, 221 | "nbformat_minor": 2 222 | } 223 | --------------------------------------------------------------------------------