增加交易策略、交易指标、量化库代码等文件夹
This commit is contained in:
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/3.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/3.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/3_更新.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/3_更新.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/5.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/5.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/6.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/6.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/7.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/7.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/8.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/8.zip
Normal file
Binary file not shown.
23116
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[Demo] Backtesting.ipynb
Normal file
23116
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[Demo] Backtesting.ipynb
Normal file
File diff suppressed because one or more lines are too long
636
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[Lession3] Download Data.ipynb
Normal file
636
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[Lession3] Download Data.ipynb
Normal file
@@ -0,0 +1,636 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#88\n",
|
||||
"# 888\n",
|
||||
"# 889\n",
|
||||
"# 99, IF99"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Download data "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from datetime import datetime\n",
|
||||
"from typing import List, Dict, Tuple\n",
|
||||
"\n",
|
||||
"from vnpy.trader.engine import BaseEngine, MainEngine, EventEngine\n",
|
||||
"from vnpy.trader.constant import Interval, Exchange\n",
|
||||
"from vnpy.trader.object import BarData, HistoryRequest\n",
|
||||
"from vnpy.trader.database import database_manager\n",
|
||||
"from vnpy.trader.rqdata import rqdata_client"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"rqdata_client.init()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def download_data(symbol, exchange):\n",
|
||||
" start = datetime(2006,1,1)\n",
|
||||
" req = HistoryRequest(\n",
|
||||
" symbol=symbol,\n",
|
||||
" exchange=exchange,\n",
|
||||
" interval=Interval.DAILY,\n",
|
||||
" start=start,\n",
|
||||
" end=datetime.now()\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" data = rqdata_client.query_history(req)\n",
|
||||
" database_manager.save_bar_data(data)\n",
|
||||
" \n",
|
||||
" print(\"finish! symbol=\",symbol, \"count=\", len(data))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"download_data(\"IC99\", Exchange.CFFEX)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"database_manager.save_bar_data(data)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# GET ALL instuments"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>order_book_id</th>\n",
|
||||
" <th>underlying_symbol</th>\n",
|
||||
" <th>market_tplus</th>\n",
|
||||
" <th>symbol</th>\n",
|
||||
" <th>margin_rate</th>\n",
|
||||
" <th>maturity_date</th>\n",
|
||||
" <th>type</th>\n",
|
||||
" <th>trading_code</th>\n",
|
||||
" <th>exchange</th>\n",
|
||||
" <th>product</th>\n",
|
||||
" <th>contract_multiplier</th>\n",
|
||||
" <th>round_lot</th>\n",
|
||||
" <th>trading_hours</th>\n",
|
||||
" <th>listed_date</th>\n",
|
||||
" <th>industry_name</th>\n",
|
||||
" <th>de_listed_date</th>\n",
|
||||
" <th>underlying_order_book_id</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>A0303</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0303</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-03-14</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0303</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-03-15</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-03-14</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>A0305</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0305</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-05-23</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0305</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-03-15</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-05-23</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>A0307</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0307</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-07-14</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0307</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-03-15</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-07-14</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>A0309</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0309</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-09-12</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0309</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-05-22</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-09-12</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>A0311</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0311</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-11-14</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0311</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-05-22</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-11-14</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>...</th>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6609</th>\n",
|
||||
" <td>PB2201</td>\n",
|
||||
" <td>PB</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>铅2201</td>\n",
|
||||
" <td>0.08</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>pb2201</td>\n",
|
||||
" <td>SHFE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>5.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-01:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>有色</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6610</th>\n",
|
||||
" <td>BC2201</td>\n",
|
||||
" <td>BC</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>国际铜2201</td>\n",
|
||||
" <td>0.08</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>bc2201</td>\n",
|
||||
" <td>INE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>5.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-01:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>未知</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6611</th>\n",
|
||||
" <td>BB2201</td>\n",
|
||||
" <td>BB</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>细木工板2201</td>\n",
|
||||
" <td>0.40</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>bb2201</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>500.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>建材</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6612</th>\n",
|
||||
" <td>SR2201</td>\n",
|
||||
" <td>SR</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>白砂糖2201</td>\n",
|
||||
" <td>0.07</td>\n",
|
||||
" <td>2022-01-14</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>SR201</td>\n",
|
||||
" <td>CZCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>软商品</td>\n",
|
||||
" <td>2022-01-14</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6613</th>\n",
|
||||
" <td>WR2201</td>\n",
|
||||
" <td>WR</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>线材2201</td>\n",
|
||||
" <td>0.07</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>wr2201</td>\n",
|
||||
" <td>SHFE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>焦煤钢矿</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"<p>6614 rows × 17 columns</p>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" order_book_id underlying_symbol market_tplus symbol margin_rate \\\n",
|
||||
"0 A0303 A 0.0 豆一0303 0.05 \n",
|
||||
"1 A0305 A 0.0 豆一0305 0.05 \n",
|
||||
"2 A0307 A 0.0 豆一0307 0.05 \n",
|
||||
"3 A0309 A 0.0 豆一0309 0.05 \n",
|
||||
"4 A0311 A 0.0 豆一0311 0.05 \n",
|
||||
"... ... ... ... ... ... \n",
|
||||
"6609 PB2201 PB 0.0 铅2201 0.08 \n",
|
||||
"6610 BC2201 BC 0.0 国际铜2201 0.08 \n",
|
||||
"6611 BB2201 BB 0.0 细木工板2201 0.40 \n",
|
||||
"6612 SR2201 SR 0.0 白砂糖2201 0.07 \n",
|
||||
"6613 WR2201 WR 0.0 线材2201 0.07 \n",
|
||||
"\n",
|
||||
" maturity_date type trading_code exchange product \\\n",
|
||||
"0 2003-03-14 Future a0303 DCE Commodity \n",
|
||||
"1 2003-05-23 Future a0305 DCE Commodity \n",
|
||||
"2 2003-07-14 Future a0307 DCE Commodity \n",
|
||||
"3 2003-09-12 Future a0309 DCE Commodity \n",
|
||||
"4 2003-11-14 Future a0311 DCE Commodity \n",
|
||||
"... ... ... ... ... ... \n",
|
||||
"6609 2022-01-17 Future pb2201 SHFE Commodity \n",
|
||||
"6610 2022-01-17 Future bc2201 INE Commodity \n",
|
||||
"6611 2022-01-17 Future bb2201 DCE Commodity \n",
|
||||
"6612 2022-01-14 Future SR201 CZCE Commodity \n",
|
||||
"6613 2022-01-17 Future wr2201 SHFE Commodity \n",
|
||||
"\n",
|
||||
" contract_multiplier round_lot \\\n",
|
||||
"0 10.0 1.0 \n",
|
||||
"1 10.0 1.0 \n",
|
||||
"2 10.0 1.0 \n",
|
||||
"3 10.0 1.0 \n",
|
||||
"4 10.0 1.0 \n",
|
||||
"... ... ... \n",
|
||||
"6609 5.0 1.0 \n",
|
||||
"6610 5.0 1.0 \n",
|
||||
"6611 500.0 1.0 \n",
|
||||
"6612 10.0 1.0 \n",
|
||||
"6613 10.0 1.0 \n",
|
||||
"\n",
|
||||
" trading_hours listed_date \\\n",
|
||||
"0 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-03-15 \n",
|
||||
"1 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-03-15 \n",
|
||||
"2 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-03-15 \n",
|
||||
"3 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-05-22 \n",
|
||||
"4 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-05-22 \n",
|
||||
"... ... ... \n",
|
||||
"6609 21:01-01:00,09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"6610 21:01-01:00,09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"6611 09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"6612 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"6613 09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"\n",
|
||||
" industry_name de_listed_date underlying_order_book_id \n",
|
||||
"0 油脂 2003-03-14 null \n",
|
||||
"1 油脂 2003-05-23 null \n",
|
||||
"2 油脂 2003-07-14 null \n",
|
||||
"3 油脂 2003-09-12 null \n",
|
||||
"4 油脂 2003-11-14 null \n",
|
||||
"... ... ... ... \n",
|
||||
"6609 有色 2022-01-17 null \n",
|
||||
"6610 未知 2022-01-17 null \n",
|
||||
"6611 建材 2022-01-17 null \n",
|
||||
"6612 软商品 2022-01-14 null \n",
|
||||
"6613 焦煤钢矿 2022-01-17 null \n",
|
||||
"\n",
|
||||
"[6614 rows x 17 columns]"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df=rqdata_client.get_all_futures()\n",
|
||||
"df\n",
|
||||
"# underlying_symbol\n",
|
||||
"# exchange\n",
|
||||
"# listed_date"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"data_dict = df.transpose().to_dict()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'order_book_id': 'A0303',\n",
|
||||
" 'underlying_symbol': 'A',\n",
|
||||
" 'market_tplus': 0.0,\n",
|
||||
" 'symbol': '豆一0303',\n",
|
||||
" 'margin_rate': 0.05,\n",
|
||||
" 'maturity_date': '2003-03-14',\n",
|
||||
" 'type': 'Future',\n",
|
||||
" 'trading_code': 'a0303',\n",
|
||||
" 'exchange': 'DCE',\n",
|
||||
" 'product': 'Commodity',\n",
|
||||
" 'contract_multiplier': 10.0,\n",
|
||||
" 'round_lot': 1.0,\n",
|
||||
" 'trading_hours': '21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00',\n",
|
||||
" 'listed_date': '2002-03-15',\n",
|
||||
" 'industry_name': '油脂',\n",
|
||||
" 'de_listed_date': '2003-03-14',\n",
|
||||
" 'underlying_order_book_id': 'null'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data_dict[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"underlying_symbols = []\n",
|
||||
"vt_symbols = [] # IF99.CFFEX\n",
|
||||
"for data in data_dict.values():\n",
|
||||
" # 1) Filter underlying symbol \n",
|
||||
" underlying = data['underlying_symbol']\n",
|
||||
" if underlying not in underlying_symbols:\n",
|
||||
" underlying_symbols.append(underlying)\n",
|
||||
" \n",
|
||||
" # 2) Filter listed date\n",
|
||||
" dt_str = data[\"listed_date\"]\n",
|
||||
" dt = datetime.strptime(dt_str, \"%Y-%m-%d\")\n",
|
||||
" \n",
|
||||
" if dt <= datetime(2016,1,1):\n",
|
||||
" \n",
|
||||
" vt_symbol = underlying + \"99\" + \".\" + data[\"exchange\"]\n",
|
||||
" \n",
|
||||
" vt_symbols.append(vt_symbol)\n",
|
||||
" \n",
|
||||
" \n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"finish! symbol= A99 count= 3661\n",
|
||||
"finish! symbol= AG99 count= 2121\n",
|
||||
"finish! symbol= AL99 count= 3661\n",
|
||||
"finish! symbol= AU99 count= 3173\n",
|
||||
"finish! symbol= B99 count= 3661\n",
|
||||
"finish! symbol= BB99 count= 1739\n",
|
||||
"finish! symbol= BU99 count= 1781\n",
|
||||
"finish! symbol= C99 count= 3661\n",
|
||||
"finish! symbol= CF99 count= 3661\n",
|
||||
"finish! symbol= CS99 count= 1485\n",
|
||||
"finish! symbol= CU99 count= 3661\n",
|
||||
"finish! symbol= ER99 count= 994\n",
|
||||
"finish! symbol= FB99 count= 1739\n",
|
||||
"finish! symbol= FG99 count= 1980\n",
|
||||
"finish! symbol= FU99 count= 3650\n",
|
||||
"finish! symbol= HC99 count= 1670\n",
|
||||
"finish! symbol= I99 count= 1774\n",
|
||||
"finish! symbol= IC99 count= 1409\n",
|
||||
"finish! symbol= IF99 count= 2620\n",
|
||||
"finish! symbol= IH99 count= 1409\n",
|
||||
"finish! symbol= J99 count= 2380\n",
|
||||
"finish! symbol= JD99 count= 1759\n",
|
||||
"finish! symbol= JM99 count= 1909\n",
|
||||
"finish! symbol= JR99 count= 1753\n",
|
||||
"finish! symbol= L99 count= 3282\n",
|
||||
"finish! symbol= LR99 count= 1597\n",
|
||||
"finish! symbol= M99 count= 3661\n",
|
||||
"finish! symbol= MA99 count= 1612\n",
|
||||
"finish! symbol= ME99 count= 860\n",
|
||||
"finish! symbol= NI99 count= 1422\n",
|
||||
"finish! symbol= OI99 count= 2075\n",
|
||||
"finish! symbol= P99 count= 3223\n",
|
||||
"finish! symbol= PB99 count= 2394\n",
|
||||
"finish! symbol= PM99 count= 2193\n",
|
||||
"finish! symbol= PP99 count= 1685\n",
|
||||
"finish! symbol= RB99 count= 2878\n",
|
||||
"finish! symbol= RI99 count= 2069\n",
|
||||
"finish! symbol= RM99 count= 1961\n",
|
||||
"finish! symbol= RO99 count= 1444\n",
|
||||
"finish! symbol= RS99 count= 1961\n",
|
||||
"finish! symbol= RU99 count= 3661\n",
|
||||
"finish! symbol= S99 count= 0\n",
|
||||
"finish! symbol= SF99 count= 1574\n",
|
||||
"finish! symbol= SM99 count= 1574\n",
|
||||
"finish! symbol= SN99 count= 1422\n",
|
||||
"finish! symbol= SR99 count= 3659\n",
|
||||
"finish! symbol= T99 count= 1427\n",
|
||||
"finish! symbol= TA99 count= 3430\n",
|
||||
"finish! symbol= TC99 count= 617\n",
|
||||
"finish! symbol= TF99 count= 1797\n",
|
||||
"finish! symbol= V99 count= 2839\n",
|
||||
"finish! symbol= WH99 count= 2069\n",
|
||||
"finish! symbol= WR99 count= 2853\n",
|
||||
"finish! symbol= WS99 count= 1792\n",
|
||||
"finish! symbol= WT99 count= 1675\n",
|
||||
"finish! symbol= Y99 count= 3658\n",
|
||||
"finish! symbol= ZC99 count= 1388\n",
|
||||
"finish! symbol= ZN99 count= 3368\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for vt_symbol in vt_symbols:\n",
|
||||
" symbol, exchange =tuple(vt_symbol.split(\".\"))\n",
|
||||
" download_data(symbol, Exchange(exchange))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
22920
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[Lession7] show capital.ipynb
Normal file
22920
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[Lession7] show capital.ipynb
Normal file
File diff suppressed because one or more lines are too long
169
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[Lession7]return10_strategy.py
Normal file
169
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[Lession7]return10_strategy.py
Normal file
@@ -0,0 +1,169 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from vnpy.trader.constant import Interval
|
||||
|
||||
|
||||
class Return10Strategy(StrategyTemplate):
|
||||
""""""
|
||||
|
||||
author = "KeKe"
|
||||
|
||||
price_add_percent = 0.05 # 超价5%下单
|
||||
fixed_pos_value = 3000000 # 每个合约做10万
|
||||
return_period = 10
|
||||
holding_period = 10
|
||||
shift_period = 0
|
||||
|
||||
signal_ts = {}
|
||||
signal_total = {}
|
||||
last_tick_time: datetime = None
|
||||
trade_day = 0
|
||||
targets_pos = {}
|
||||
show_pos = {}
|
||||
symbol_cap = {}
|
||||
today = None
|
||||
|
||||
parameters = [
|
||||
"price_add_percent", "fixed_pos_value",
|
||||
"return_period", "holding_period", "shift_period"
|
||||
]
|
||||
variables = [
|
||||
"signal_ts", "signal_total",
|
||||
"trade_day", "targets_pos"
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
|
||||
self.bgs[vt_symbol] = BarGenerator(on_bar)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(days=20, interval=Interval.DAILY)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
# 1) 全撤
|
||||
self.cancel_all()
|
||||
|
||||
# 2.3)初始化am &计算时间序列
|
||||
for vt_symbol, bar in bars.items():
|
||||
self.today = bar.datetime.date()
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
|
||||
# 信号 过去10天的收益率
|
||||
return10 = am.rocp(self.return_period)
|
||||
|
||||
# 信号>0,时序信号+1,信号<0,时序信号-1
|
||||
if return10 > 0:
|
||||
self.signal_ts[vt_symbol] = 1
|
||||
elif return10 < 0:
|
||||
self.signal_ts[vt_symbol] = -1
|
||||
else:
|
||||
self.signal_ts[vt_symbol] = 0
|
||||
|
||||
today = self.today
|
||||
|
||||
# 4)信号汇总,总信号=时序信号汇总 + 横截面信号汇总
|
||||
# 基于总体信号,得到目标持仓
|
||||
|
||||
for vt_symbol, bar in bars.items():
|
||||
self.signal_total[vt_symbol] = self.signal_ts[vt_symbol]
|
||||
self.targets_pos[vt_symbol] = int(
|
||||
self.fixed_pos_value / bar.close_price
|
||||
) * self.signal_total[vt_symbol]
|
||||
|
||||
# 3)交易执行(每隔10个交易日检查并且调仓)
|
||||
if self.trade_day == 0 or not (self.trade_day + self.shift_period) % self.holding_period:
|
||||
pos = {}
|
||||
capital = {}
|
||||
|
||||
for vt_symbol, bar in bars.items():
|
||||
bar = bars.get(vt_symbol)
|
||||
if not bar:
|
||||
continue
|
||||
|
||||
target_pos = self.targets_pos[vt_symbol]
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
pos[vt_symbol] = current_pos
|
||||
capital[vt_symbol] = abs(bar.close_price * current_pos)
|
||||
|
||||
# 计算仓位差异,当产生差异时候,才进行调整
|
||||
pos_diff = target_pos - current_pos
|
||||
|
||||
if pos_diff > 0:
|
||||
price = bar.close_price * (1 + self.price_add_percent)
|
||||
if current_pos < 0:
|
||||
self.cover(vt_symbol, price, pos_diff)
|
||||
else:
|
||||
self.buy(vt_symbol, price, pos_diff)
|
||||
|
||||
elif pos_diff < 0:
|
||||
price = bar.close_price * (1 - self.price_add_percent)
|
||||
if current_pos > 0:
|
||||
self.sell(vt_symbol, price, - pos_diff)
|
||||
else:
|
||||
self.short(vt_symbol, price, - pos_diff)
|
||||
|
||||
self.show_pos[today] = pos
|
||||
self.symbol_cap[today] = capital
|
||||
|
||||
self.trade_day += 1
|
||||
self.put_event()
|
||||
22396
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[作业1] MACD横截面策略.ipynb
Normal file
22396
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[作业1] MACD横截面策略.ipynb
Normal file
File diff suppressed because one or more lines are too long
154
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[作业1}macd10_strategy.py
Normal file
154
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[作业1}macd10_strategy.py
Normal file
@@ -0,0 +1,154 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
from operator import itemgetter
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
from vnpy.trader.constant import Interval
|
||||
|
||||
|
||||
class Macd10Strategy(StrategyTemplate):
|
||||
""""""
|
||||
author = "KeKe"
|
||||
|
||||
price_add_percent = 0.05 # 超价5%下单
|
||||
fixed_pos_value = 100000 # 每个合约做100万
|
||||
trade_day = 0
|
||||
targets_pos = {}
|
||||
macd_data = {}
|
||||
target_cs = {}
|
||||
target_total = {}
|
||||
|
||||
parameters = [
|
||||
"price_add_percent",
|
||||
"fixed_size",
|
||||
]
|
||||
variables = [
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
self.last_tick_time: datetime = None
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
|
||||
self.bgs[vt_symbol] = BarGenerator(on_bar)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(10, interval=Interval.DAILY)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
# MACD指标计算
|
||||
for vt_symbol, bar in bars.items():
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
|
||||
x, y, macd = am.macd(10, 20, 5)
|
||||
self.macd_data[vt_symbol] = macd
|
||||
|
||||
# 按照MACD从小到大排序
|
||||
sorted_l = sorted(self.macd_data.items(), key=itemgetter(1))
|
||||
len_symbol = len(sorted_l) # 10
|
||||
|
||||
choose = int(0.25 * len_symbol) # int(2.5) =2
|
||||
|
||||
short_part = dict(sorted_l[:choose])
|
||||
long_part = dict(sorted_l[-choose:])
|
||||
not_trade_part = dict(sorted_l[choose: -choose])
|
||||
|
||||
for k in short_part:
|
||||
self.target_cs[k] = -1
|
||||
for k in long_part:
|
||||
self.target_cs[k] = 1
|
||||
for k in not_trade_part:
|
||||
self.target_cs[k] = 0
|
||||
|
||||
# 信号汇总
|
||||
for vt_symbol, bar in bars.items():
|
||||
self.target_total[vt_symbol] = self.target_cs[vt_symbol]
|
||||
self.targets_pos[vt_symbol] = int(
|
||||
self.fixed_pos_value / bar.close_price
|
||||
) * self.target_total[vt_symbol]
|
||||
|
||||
# 交易执行
|
||||
if self.trade_day == 0 or not (self.trade_day + 0) % 10:
|
||||
|
||||
for vt_symbol in self.vt_symbols:
|
||||
bar = bars.get(vt_symbol)
|
||||
if not bar:
|
||||
continue
|
||||
|
||||
target_pos = self.targets_pos[vt_symbol]
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
|
||||
pos_diff = target_pos - current_pos
|
||||
|
||||
if pos_diff > 0:
|
||||
price = bar.close_price * (1 + self.price_add_percent)
|
||||
if current_pos < 0:
|
||||
self.cover(vt_symbol, price, pos_diff)
|
||||
else:
|
||||
self.buy(vt_symbol, price, pos_diff)
|
||||
|
||||
elif pos_diff < 0:
|
||||
price = bar.close_price * (1 - self.price_add_percent)
|
||||
if current_pos > 0:
|
||||
self.sell(vt_symbol, price, - pos_diff)
|
||||
else:
|
||||
self.short(vt_symbol, price, - pos_diff)
|
||||
|
||||
self.trade_day += 1
|
||||
self.put_event()
|
||||
2093
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[作业2] 多周期合成.ipynb
Normal file
2093
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[作业2] 多周期合成.ipynb
Normal file
File diff suppressed because one or more lines are too long
224
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[作业2]demo_strategy.py
Normal file
224
5.课程代码/1.投资组合策略7天入门/使用代码/archive/[作业2]demo_strategy.py
Normal file
@@ -0,0 +1,224 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from vnpy.trader.constant import Interval
|
||||
|
||||
|
||||
class DemoStrategy(StrategyTemplate):
|
||||
""""""
|
||||
|
||||
author = "KeKe"
|
||||
|
||||
price_add_percent = 0.05 # 超价5%下单
|
||||
fixed_pos_value = 1000000 # 每个合约做10万
|
||||
atr_window = 22
|
||||
atr_ma_window = 10
|
||||
rsi_window = 5
|
||||
rsi_entry = 16
|
||||
trailing_percent = 0.8
|
||||
fixed_size = 1
|
||||
price_add = 5
|
||||
|
||||
rsi_buy = 0
|
||||
rsi_sell = 0
|
||||
|
||||
signal_ts = {}
|
||||
signal_total = {}
|
||||
last_tick_time: datetime = None
|
||||
last_bar_time: datetime = None
|
||||
trade_day = 0
|
||||
targets_pos = {}
|
||||
show_pos = {}
|
||||
symbol_cap = {}
|
||||
window_bars = {}
|
||||
today = None
|
||||
|
||||
parameters = [
|
||||
"price_add_percent", "fixed_pos_value",
|
||||
"return_period", "holding_period", "shift_period"
|
||||
]
|
||||
variables = [
|
||||
"signal_ts", "signal_total",
|
||||
"trade_day", "targets_pos"
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
self.rsi_data: Dict[str, float] = {}
|
||||
self.atr_data: Dict[str, float] = {}
|
||||
self.atr_ma: Dict[str, float] = {}
|
||||
self.intra_trade_high: Dict[str, float] = {}
|
||||
self.intra_trade_low: Dict[str, float] = {}
|
||||
|
||||
self.targets: Dict[str, int] = {}
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
self.bgs[vt_symbol] = BarGenerator(
|
||||
self.on_bar,
|
||||
5,
|
||||
self.on_window_bar
|
||||
)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(days=20, interval=Interval.MINUTE)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
|
||||
def on_window_bar(self, bar):
|
||||
dt = bar.datetime.strftime("%Y%d%m, %H:%M")
|
||||
|
||||
if (
|
||||
self.last_bar_time
|
||||
and self.last_bar_time.minute != bar.datetime.minute
|
||||
):
|
||||
self.on_window_bars(self.window_bars)
|
||||
|
||||
self.window_bars = {}
|
||||
self.window_bars[bar.vt_symbol] = bar
|
||||
# print("@", dt, bar.vt_symbol, bar.close_price)
|
||||
else:
|
||||
# print("@@", dt, bar.vt_symbol, bar.close_price)
|
||||
self.window_bars[bar.vt_symbol] = bar
|
||||
|
||||
self.last_bar_time = bar.datetime
|
||||
|
||||
def on_window_bars(self, bars):
|
||||
# test
|
||||
# dts = {}
|
||||
# for vt_symbol, bar in bars.items():
|
||||
# dt = bar.datetime.strftime("%H:%M")
|
||||
# dts[bar.vt_symbol] = dt
|
||||
# print("**", dts)
|
||||
|
||||
# return
|
||||
# test
|
||||
self.cancel_all()
|
||||
|
||||
# 更新K线计算RSI数值
|
||||
for vt_symbol, bar in bars.items():
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
if not am.inited:
|
||||
return
|
||||
atr_array = am.atr(self.atr_window, array=True)
|
||||
self.atr_data[vt_symbol] = atr_array[-1]
|
||||
self.atr_ma[vt_symbol] = atr_array[-self.atr_ma_window:].mean()
|
||||
self.rsi_data[vt_symbol] = am.rsi(self.rsi_window)
|
||||
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
if current_pos == 0:
|
||||
self.intra_trade_high[vt_symbol] = bar.high_price
|
||||
self.intra_trade_low[vt_symbol] = bar.low_price
|
||||
|
||||
if self.atr_data[vt_symbol] > self.atr_ma[vt_symbol]:
|
||||
if self.rsi_data[vt_symbol] > self.rsi_buy:
|
||||
self.targets[vt_symbol] = self.fixed_size
|
||||
elif self.rsi_data[vt_symbol] < self.rsi_sell:
|
||||
self.targets[vt_symbol] = -self.fixed_size
|
||||
else:
|
||||
self.targets[vt_symbol] = 0
|
||||
|
||||
elif current_pos > 0:
|
||||
self.intra_trade_high[vt_symbol] = max(self.intra_trade_high[vt_symbol], bar.high_price)
|
||||
self.intra_trade_low[vt_symbol] = bar.low_price
|
||||
|
||||
long_stop = self.intra_trade_high[vt_symbol] * (1 - self.trailing_percent / 100)
|
||||
|
||||
if bar.close_price <= long_stop:
|
||||
self.targets[vt_symbol] = 0
|
||||
|
||||
elif current_pos < 0:
|
||||
self.intra_trade_low[vt_symbol] = min(self.intra_trade_low[vt_symbol], bar.low_price)
|
||||
self.intra_trade_high[vt_symbol] = bar.high_price
|
||||
|
||||
short_stop = self.intra_trade_low[vt_symbol] * (1 + self.trailing_percent / 100)
|
||||
|
||||
if bar.close_price >= short_stop:
|
||||
self.targets[vt_symbol] = 0
|
||||
|
||||
for vt_symbol in self.vt_symbols:
|
||||
target_pos = self.targets.get(vt_symbol, None)
|
||||
if not target_pos:
|
||||
continue
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
|
||||
pos_diff = target_pos - current_pos
|
||||
volume = abs(pos_diff)
|
||||
bar = bars[vt_symbol]
|
||||
|
||||
if pos_diff > 0:
|
||||
price = bar.close_price + self.price_add
|
||||
|
||||
if current_pos < 0:
|
||||
self.cover(vt_symbol, price, volume)
|
||||
else:
|
||||
self.buy(vt_symbol, price, volume)
|
||||
elif pos_diff < 0:
|
||||
price = bar.close_price - self.price_add
|
||||
|
||||
if current_pos > 0:
|
||||
self.sell(vt_symbol, price, volume)
|
||||
else:
|
||||
self.short(vt_symbol, price, volume)
|
||||
|
||||
self.put_event()
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bar = bars[vt_symbol]
|
||||
bg.update_bar(bar)
|
||||
141
5.课程代码/1.投资组合策略7天入门/使用代码/archive/double_ma_strategy.py
Normal file
141
5.课程代码/1.投资组合策略7天入门/使用代码/archive/double_ma_strategy.py
Normal file
@@ -0,0 +1,141 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
|
||||
class DoubleMaStrategy(StrategyTemplate):
|
||||
""""""
|
||||
|
||||
author = "KeKe"
|
||||
|
||||
fast_window = 8
|
||||
slow_window = 24
|
||||
price_add = 5
|
||||
|
||||
today = ""
|
||||
daily_pos = {}
|
||||
daily_close = {}
|
||||
|
||||
parameters = [
|
||||
"fast_window",
|
||||
"slow_window",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
self.last_tick_time: datetime = None
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
self.bgs[vt_symbol] = BarGenerator(on_bar)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(100)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
|
||||
# 更新K线计算
|
||||
for vt_symbol, bar in bars.items():
|
||||
dt_str = bar.datetime.strftime("%Y-%m-%d")
|
||||
self.today = dt_str
|
||||
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
if not am.inited:
|
||||
continue
|
||||
|
||||
fast_ma = am.sma(self.fast_window, array=True)
|
||||
fast_ma0 = fast_ma[-1]
|
||||
fast_ma1 = fast_ma[-2]
|
||||
|
||||
slow_ma = am.sma(self.slow_window, array=True)
|
||||
slow_ma0 = slow_ma[-1]
|
||||
slow_ma1 = slow_ma[-2]
|
||||
|
||||
cross_over = fast_ma0 > slow_ma0 and fast_ma1 < slow_ma1
|
||||
cross_below = fast_ma0 < slow_ma0 and fast_ma1 > slow_ma1
|
||||
|
||||
pos = self.get_pos(vt_symbol)
|
||||
if cross_over:
|
||||
if pos == 0:
|
||||
self.buy(vt_symbol, bar.close_price, 1)
|
||||
elif pos < 0:
|
||||
self.cover(vt_symbol, bar.close_price, 1)
|
||||
self.buy(vt_symbol, bar.close_price, 1)
|
||||
elif cross_below:
|
||||
if pos == 0:
|
||||
self.short(vt_symbol, bar.close_price, 1)
|
||||
elif pos > 0:
|
||||
self.sell(vt_symbol, bar.close_price, 1)
|
||||
self.short(vt_symbol, bar.close_price, 1)
|
||||
|
||||
self.record_current_pos(bars)
|
||||
|
||||
self.put_event()
|
||||
|
||||
def record_current_pos(self, bars):
|
||||
current_pos = {}
|
||||
current_close = {}
|
||||
for bar in bars.values():
|
||||
pos = self.get_pos(bar.vt_symbol)
|
||||
current_pos[bar.vt_symbol] = pos
|
||||
current_close[bar.vt_symbol] = bar.close_price
|
||||
|
||||
today = self.today
|
||||
|
||||
self.daily_pos[today] = str(current_pos)
|
||||
self.daily_close[today] = current_close
|
||||
154
5.课程代码/1.投资组合策略7天入门/使用代码/archive/return10_strategy.py
Normal file
154
5.课程代码/1.投资组合策略7天入门/使用代码/archive/return10_strategy.py
Normal file
@@ -0,0 +1,154 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from vnpy.trader.constant import Interval
|
||||
|
||||
|
||||
class Return10Strategy(StrategyTemplate):
|
||||
""""""
|
||||
|
||||
author = "KeKe"
|
||||
|
||||
price_add_percent = 0.05 # 超价5%下单
|
||||
fixed_pos_value = 1000000 # 每个合约做100万
|
||||
signal_ts = {}
|
||||
signal_total = {}
|
||||
last_tick_time: datetime = None
|
||||
trade_day = 0
|
||||
targets_pos = {}
|
||||
|
||||
parameters = [
|
||||
"price_add_percent",
|
||||
"fixed_size",
|
||||
]
|
||||
variables = [
|
||||
"signal_ts", "signal_total",
|
||||
"trade_day", "targets_pos"
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
|
||||
self.bgs[vt_symbol] = BarGenerator(on_bar)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(days=20, interval=Interval.DAILY)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
# 1) 全撤
|
||||
self.cancel_all()
|
||||
|
||||
# 2.3)初始化am &计算时间序列
|
||||
for vt_symbol, bar in bars.items():
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
|
||||
# if not am.inited:
|
||||
# return
|
||||
|
||||
# 信号 过去10天的收益率
|
||||
return10 = am.rocp(10)
|
||||
|
||||
# 信号>0,时序信号+1,信号<0,时序信号-1
|
||||
if return10 > 0:
|
||||
self.signal_ts[vt_symbol] = 1
|
||||
elif return10 < - 0:
|
||||
self.signal_ts[vt_symbol] = -1
|
||||
else:
|
||||
self.signal_ts[vt_symbol] = 0
|
||||
|
||||
# 3)信号汇总,总信号=时序信号汇总 + 横截面信号汇总
|
||||
# 基于总体信号,得到目标持仓
|
||||
for vt_symbol, bar in bars.items():
|
||||
self.signal_total[vt_symbol] = self.signal_ts[vt_symbol]
|
||||
self.targets_pos[vt_symbol] = int(
|
||||
self.fixed_pos_value / bar.close_price
|
||||
) * self.signal_total[vt_symbol]
|
||||
|
||||
# 3)交易执行(每隔10个交易日检查并且调仓)
|
||||
if self.trade_day == 0 or not self.trade_day % 10:
|
||||
|
||||
for vt_symbol in self.vt_symbols:
|
||||
bar = bars.get(vt_symbol)
|
||||
if not bar:
|
||||
continue
|
||||
|
||||
target_pos = self.targets_pos[vt_symbol]
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
|
||||
# 计算仓位差异,当产生差异时候,才进行调整
|
||||
pos_diff = target_pos - current_pos
|
||||
|
||||
if pos_diff > 0:
|
||||
price = bar.close_price * (1 + self.price_add_percent)
|
||||
if current_pos < 0:
|
||||
self.cover(vt_symbol, price, pos_diff)
|
||||
else:
|
||||
self.buy(vt_symbol, price, pos_diff)
|
||||
|
||||
elif pos_diff < 0:
|
||||
price = bar.close_price * (1 - self.price_add_percent)
|
||||
if current_pos > 0:
|
||||
self.sell(vt_symbol, price, - pos_diff)
|
||||
else:
|
||||
self.short(vt_symbol, price, - pos_diff)
|
||||
|
||||
self.trade_day += 1
|
||||
self.put_event()
|
||||
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/archive/第2课_认识Portfolio Strategy模块.emmx
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/archive/第2课_认识Portfolio Strategy模块.emmx
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/archive/第4课_认识策略模板.emmx
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/使用代码/archive/第4课_认识策略模板.emmx
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/3.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/3.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/3_更新.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/3_更新.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/5.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/5.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/6.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/6.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/7.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/7.zip
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/8.zip
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/8.zip
Normal file
Binary file not shown.
23116
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[Demo] Backtesting.ipynb
Normal file
23116
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[Demo] Backtesting.ipynb
Normal file
File diff suppressed because one or more lines are too long
636
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[Lession3] Download Data.ipynb
Normal file
636
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[Lession3] Download Data.ipynb
Normal file
@@ -0,0 +1,636 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#88\n",
|
||||
"# 888\n",
|
||||
"# 889\n",
|
||||
"# 99, IF99"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Download data "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from datetime import datetime\n",
|
||||
"from typing import List, Dict, Tuple\n",
|
||||
"\n",
|
||||
"from vnpy.trader.engine import BaseEngine, MainEngine, EventEngine\n",
|
||||
"from vnpy.trader.constant import Interval, Exchange\n",
|
||||
"from vnpy.trader.object import BarData, HistoryRequest\n",
|
||||
"from vnpy.trader.database import database_manager\n",
|
||||
"from vnpy.trader.rqdata import rqdata_client"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"rqdata_client.init()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def download_data(symbol, exchange):\n",
|
||||
" start = datetime(2006,1,1)\n",
|
||||
" req = HistoryRequest(\n",
|
||||
" symbol=symbol,\n",
|
||||
" exchange=exchange,\n",
|
||||
" interval=Interval.DAILY,\n",
|
||||
" start=start,\n",
|
||||
" end=datetime.now()\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" data = rqdata_client.query_history(req)\n",
|
||||
" database_manager.save_bar_data(data)\n",
|
||||
" \n",
|
||||
" print(\"finish! symbol=\",symbol, \"count=\", len(data))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"download_data(\"IC99\", Exchange.CFFEX)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"database_manager.save_bar_data(data)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# GET ALL instuments"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>order_book_id</th>\n",
|
||||
" <th>underlying_symbol</th>\n",
|
||||
" <th>market_tplus</th>\n",
|
||||
" <th>symbol</th>\n",
|
||||
" <th>margin_rate</th>\n",
|
||||
" <th>maturity_date</th>\n",
|
||||
" <th>type</th>\n",
|
||||
" <th>trading_code</th>\n",
|
||||
" <th>exchange</th>\n",
|
||||
" <th>product</th>\n",
|
||||
" <th>contract_multiplier</th>\n",
|
||||
" <th>round_lot</th>\n",
|
||||
" <th>trading_hours</th>\n",
|
||||
" <th>listed_date</th>\n",
|
||||
" <th>industry_name</th>\n",
|
||||
" <th>de_listed_date</th>\n",
|
||||
" <th>underlying_order_book_id</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>A0303</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0303</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-03-14</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0303</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-03-15</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-03-14</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>A0305</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0305</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-05-23</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0305</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-03-15</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-05-23</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>A0307</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0307</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-07-14</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0307</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-03-15</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-07-14</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>A0309</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0309</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-09-12</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0309</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-05-22</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-09-12</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>A0311</td>\n",
|
||||
" <td>A</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>豆一0311</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>2003-11-14</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>a0311</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2002-05-22</td>\n",
|
||||
" <td>油脂</td>\n",
|
||||
" <td>2003-11-14</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>...</th>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6609</th>\n",
|
||||
" <td>PB2201</td>\n",
|
||||
" <td>PB</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>铅2201</td>\n",
|
||||
" <td>0.08</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>pb2201</td>\n",
|
||||
" <td>SHFE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>5.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-01:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>有色</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6610</th>\n",
|
||||
" <td>BC2201</td>\n",
|
||||
" <td>BC</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>国际铜2201</td>\n",
|
||||
" <td>0.08</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>bc2201</td>\n",
|
||||
" <td>INE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>5.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-01:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>未知</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6611</th>\n",
|
||||
" <td>BB2201</td>\n",
|
||||
" <td>BB</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>细木工板2201</td>\n",
|
||||
" <td>0.40</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>bb2201</td>\n",
|
||||
" <td>DCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>500.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>建材</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6612</th>\n",
|
||||
" <td>SR2201</td>\n",
|
||||
" <td>SR</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>白砂糖2201</td>\n",
|
||||
" <td>0.07</td>\n",
|
||||
" <td>2022-01-14</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>SR201</td>\n",
|
||||
" <td>CZCE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>软商品</td>\n",
|
||||
" <td>2022-01-14</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6613</th>\n",
|
||||
" <td>WR2201</td>\n",
|
||||
" <td>WR</td>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>线材2201</td>\n",
|
||||
" <td>0.07</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>Future</td>\n",
|
||||
" <td>wr2201</td>\n",
|
||||
" <td>SHFE</td>\n",
|
||||
" <td>Commodity</td>\n",
|
||||
" <td>10.0</td>\n",
|
||||
" <td>1.0</td>\n",
|
||||
" <td>09:01-10:15,10:31-11:30,13:31-15:00</td>\n",
|
||||
" <td>2021-01-18</td>\n",
|
||||
" <td>焦煤钢矿</td>\n",
|
||||
" <td>2022-01-17</td>\n",
|
||||
" <td>null</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"<p>6614 rows × 17 columns</p>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" order_book_id underlying_symbol market_tplus symbol margin_rate \\\n",
|
||||
"0 A0303 A 0.0 豆一0303 0.05 \n",
|
||||
"1 A0305 A 0.0 豆一0305 0.05 \n",
|
||||
"2 A0307 A 0.0 豆一0307 0.05 \n",
|
||||
"3 A0309 A 0.0 豆一0309 0.05 \n",
|
||||
"4 A0311 A 0.0 豆一0311 0.05 \n",
|
||||
"... ... ... ... ... ... \n",
|
||||
"6609 PB2201 PB 0.0 铅2201 0.08 \n",
|
||||
"6610 BC2201 BC 0.0 国际铜2201 0.08 \n",
|
||||
"6611 BB2201 BB 0.0 细木工板2201 0.40 \n",
|
||||
"6612 SR2201 SR 0.0 白砂糖2201 0.07 \n",
|
||||
"6613 WR2201 WR 0.0 线材2201 0.07 \n",
|
||||
"\n",
|
||||
" maturity_date type trading_code exchange product \\\n",
|
||||
"0 2003-03-14 Future a0303 DCE Commodity \n",
|
||||
"1 2003-05-23 Future a0305 DCE Commodity \n",
|
||||
"2 2003-07-14 Future a0307 DCE Commodity \n",
|
||||
"3 2003-09-12 Future a0309 DCE Commodity \n",
|
||||
"4 2003-11-14 Future a0311 DCE Commodity \n",
|
||||
"... ... ... ... ... ... \n",
|
||||
"6609 2022-01-17 Future pb2201 SHFE Commodity \n",
|
||||
"6610 2022-01-17 Future bc2201 INE Commodity \n",
|
||||
"6611 2022-01-17 Future bb2201 DCE Commodity \n",
|
||||
"6612 2022-01-14 Future SR201 CZCE Commodity \n",
|
||||
"6613 2022-01-17 Future wr2201 SHFE Commodity \n",
|
||||
"\n",
|
||||
" contract_multiplier round_lot \\\n",
|
||||
"0 10.0 1.0 \n",
|
||||
"1 10.0 1.0 \n",
|
||||
"2 10.0 1.0 \n",
|
||||
"3 10.0 1.0 \n",
|
||||
"4 10.0 1.0 \n",
|
||||
"... ... ... \n",
|
||||
"6609 5.0 1.0 \n",
|
||||
"6610 5.0 1.0 \n",
|
||||
"6611 500.0 1.0 \n",
|
||||
"6612 10.0 1.0 \n",
|
||||
"6613 10.0 1.0 \n",
|
||||
"\n",
|
||||
" trading_hours listed_date \\\n",
|
||||
"0 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-03-15 \n",
|
||||
"1 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-03-15 \n",
|
||||
"2 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-03-15 \n",
|
||||
"3 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-05-22 \n",
|
||||
"4 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2002-05-22 \n",
|
||||
"... ... ... \n",
|
||||
"6609 21:01-01:00,09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"6610 21:01-01:00,09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"6611 09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"6612 21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"6613 09:01-10:15,10:31-11:30,13:31-15:00 2021-01-18 \n",
|
||||
"\n",
|
||||
" industry_name de_listed_date underlying_order_book_id \n",
|
||||
"0 油脂 2003-03-14 null \n",
|
||||
"1 油脂 2003-05-23 null \n",
|
||||
"2 油脂 2003-07-14 null \n",
|
||||
"3 油脂 2003-09-12 null \n",
|
||||
"4 油脂 2003-11-14 null \n",
|
||||
"... ... ... ... \n",
|
||||
"6609 有色 2022-01-17 null \n",
|
||||
"6610 未知 2022-01-17 null \n",
|
||||
"6611 建材 2022-01-17 null \n",
|
||||
"6612 软商品 2022-01-14 null \n",
|
||||
"6613 焦煤钢矿 2022-01-17 null \n",
|
||||
"\n",
|
||||
"[6614 rows x 17 columns]"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df=rqdata_client.get_all_futures()\n",
|
||||
"df\n",
|
||||
"# underlying_symbol\n",
|
||||
"# exchange\n",
|
||||
"# listed_date"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"data_dict = df.transpose().to_dict()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'order_book_id': 'A0303',\n",
|
||||
" 'underlying_symbol': 'A',\n",
|
||||
" 'market_tplus': 0.0,\n",
|
||||
" 'symbol': '豆一0303',\n",
|
||||
" 'margin_rate': 0.05,\n",
|
||||
" 'maturity_date': '2003-03-14',\n",
|
||||
" 'type': 'Future',\n",
|
||||
" 'trading_code': 'a0303',\n",
|
||||
" 'exchange': 'DCE',\n",
|
||||
" 'product': 'Commodity',\n",
|
||||
" 'contract_multiplier': 10.0,\n",
|
||||
" 'round_lot': 1.0,\n",
|
||||
" 'trading_hours': '21:01-23:00,09:01-10:15,10:31-11:30,13:31-15:00',\n",
|
||||
" 'listed_date': '2002-03-15',\n",
|
||||
" 'industry_name': '油脂',\n",
|
||||
" 'de_listed_date': '2003-03-14',\n",
|
||||
" 'underlying_order_book_id': 'null'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data_dict[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"underlying_symbols = []\n",
|
||||
"vt_symbols = [] # IF99.CFFEX\n",
|
||||
"for data in data_dict.values():\n",
|
||||
" # 1) Filter underlying symbol \n",
|
||||
" underlying = data['underlying_symbol']\n",
|
||||
" if underlying not in underlying_symbols:\n",
|
||||
" underlying_symbols.append(underlying)\n",
|
||||
" \n",
|
||||
" # 2) Filter listed date\n",
|
||||
" dt_str = data[\"listed_date\"]\n",
|
||||
" dt = datetime.strptime(dt_str, \"%Y-%m-%d\")\n",
|
||||
" \n",
|
||||
" if dt <= datetime(2016,1,1):\n",
|
||||
" \n",
|
||||
" vt_symbol = underlying + \"99\" + \".\" + data[\"exchange\"]\n",
|
||||
" \n",
|
||||
" vt_symbols.append(vt_symbol)\n",
|
||||
" \n",
|
||||
" \n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"finish! symbol= A99 count= 3661\n",
|
||||
"finish! symbol= AG99 count= 2121\n",
|
||||
"finish! symbol= AL99 count= 3661\n",
|
||||
"finish! symbol= AU99 count= 3173\n",
|
||||
"finish! symbol= B99 count= 3661\n",
|
||||
"finish! symbol= BB99 count= 1739\n",
|
||||
"finish! symbol= BU99 count= 1781\n",
|
||||
"finish! symbol= C99 count= 3661\n",
|
||||
"finish! symbol= CF99 count= 3661\n",
|
||||
"finish! symbol= CS99 count= 1485\n",
|
||||
"finish! symbol= CU99 count= 3661\n",
|
||||
"finish! symbol= ER99 count= 994\n",
|
||||
"finish! symbol= FB99 count= 1739\n",
|
||||
"finish! symbol= FG99 count= 1980\n",
|
||||
"finish! symbol= FU99 count= 3650\n",
|
||||
"finish! symbol= HC99 count= 1670\n",
|
||||
"finish! symbol= I99 count= 1774\n",
|
||||
"finish! symbol= IC99 count= 1409\n",
|
||||
"finish! symbol= IF99 count= 2620\n",
|
||||
"finish! symbol= IH99 count= 1409\n",
|
||||
"finish! symbol= J99 count= 2380\n",
|
||||
"finish! symbol= JD99 count= 1759\n",
|
||||
"finish! symbol= JM99 count= 1909\n",
|
||||
"finish! symbol= JR99 count= 1753\n",
|
||||
"finish! symbol= L99 count= 3282\n",
|
||||
"finish! symbol= LR99 count= 1597\n",
|
||||
"finish! symbol= M99 count= 3661\n",
|
||||
"finish! symbol= MA99 count= 1612\n",
|
||||
"finish! symbol= ME99 count= 860\n",
|
||||
"finish! symbol= NI99 count= 1422\n",
|
||||
"finish! symbol= OI99 count= 2075\n",
|
||||
"finish! symbol= P99 count= 3223\n",
|
||||
"finish! symbol= PB99 count= 2394\n",
|
||||
"finish! symbol= PM99 count= 2193\n",
|
||||
"finish! symbol= PP99 count= 1685\n",
|
||||
"finish! symbol= RB99 count= 2878\n",
|
||||
"finish! symbol= RI99 count= 2069\n",
|
||||
"finish! symbol= RM99 count= 1961\n",
|
||||
"finish! symbol= RO99 count= 1444\n",
|
||||
"finish! symbol= RS99 count= 1961\n",
|
||||
"finish! symbol= RU99 count= 3661\n",
|
||||
"finish! symbol= S99 count= 0\n",
|
||||
"finish! symbol= SF99 count= 1574\n",
|
||||
"finish! symbol= SM99 count= 1574\n",
|
||||
"finish! symbol= SN99 count= 1422\n",
|
||||
"finish! symbol= SR99 count= 3659\n",
|
||||
"finish! symbol= T99 count= 1427\n",
|
||||
"finish! symbol= TA99 count= 3430\n",
|
||||
"finish! symbol= TC99 count= 617\n",
|
||||
"finish! symbol= TF99 count= 1797\n",
|
||||
"finish! symbol= V99 count= 2839\n",
|
||||
"finish! symbol= WH99 count= 2069\n",
|
||||
"finish! symbol= WR99 count= 2853\n",
|
||||
"finish! symbol= WS99 count= 1792\n",
|
||||
"finish! symbol= WT99 count= 1675\n",
|
||||
"finish! symbol= Y99 count= 3658\n",
|
||||
"finish! symbol= ZC99 count= 1388\n",
|
||||
"finish! symbol= ZN99 count= 3368\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for vt_symbol in vt_symbols:\n",
|
||||
" symbol, exchange =tuple(vt_symbol.split(\".\"))\n",
|
||||
" download_data(symbol, Exchange(exchange))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
22920
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[Lession7] show capital.ipynb
Normal file
22920
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[Lession7] show capital.ipynb
Normal file
File diff suppressed because one or more lines are too long
169
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[Lession7]return10_strategy.py
Normal file
169
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[Lession7]return10_strategy.py
Normal file
@@ -0,0 +1,169 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from vnpy.trader.constant import Interval
|
||||
|
||||
|
||||
class Return10Strategy(StrategyTemplate):
|
||||
""""""
|
||||
|
||||
author = "KeKe"
|
||||
|
||||
price_add_percent = 0.05 # 超价5%下单
|
||||
fixed_pos_value = 3000000 # 每个合约做10万
|
||||
return_period = 10
|
||||
holding_period = 10
|
||||
shift_period = 0
|
||||
|
||||
signal_ts = {}
|
||||
signal_total = {}
|
||||
last_tick_time: datetime = None
|
||||
trade_day = 0
|
||||
targets_pos = {}
|
||||
show_pos = {}
|
||||
symbol_cap = {}
|
||||
today = None
|
||||
|
||||
parameters = [
|
||||
"price_add_percent", "fixed_pos_value",
|
||||
"return_period", "holding_period", "shift_period"
|
||||
]
|
||||
variables = [
|
||||
"signal_ts", "signal_total",
|
||||
"trade_day", "targets_pos"
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
|
||||
self.bgs[vt_symbol] = BarGenerator(on_bar)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(days=20, interval=Interval.DAILY)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
# 1) 全撤
|
||||
self.cancel_all()
|
||||
|
||||
# 2.3)初始化am &计算时间序列
|
||||
for vt_symbol, bar in bars.items():
|
||||
self.today = bar.datetime.date()
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
|
||||
# 信号 过去10天的收益率
|
||||
return10 = am.rocp(self.return_period)
|
||||
|
||||
# 信号>0,时序信号+1,信号<0,时序信号-1
|
||||
if return10 > 0:
|
||||
self.signal_ts[vt_symbol] = 1
|
||||
elif return10 < 0:
|
||||
self.signal_ts[vt_symbol] = -1
|
||||
else:
|
||||
self.signal_ts[vt_symbol] = 0
|
||||
|
||||
today = self.today
|
||||
|
||||
# 4)信号汇总,总信号=时序信号汇总 + 横截面信号汇总
|
||||
# 基于总体信号,得到目标持仓
|
||||
|
||||
for vt_symbol, bar in bars.items():
|
||||
self.signal_total[vt_symbol] = self.signal_ts[vt_symbol]
|
||||
self.targets_pos[vt_symbol] = int(
|
||||
self.fixed_pos_value / bar.close_price
|
||||
) * self.signal_total[vt_symbol]
|
||||
|
||||
# 3)交易执行(每隔10个交易日检查并且调仓)
|
||||
if self.trade_day == 0 or not (self.trade_day + self.shift_period) % self.holding_period:
|
||||
pos = {}
|
||||
capital = {}
|
||||
|
||||
for vt_symbol, bar in bars.items():
|
||||
bar = bars.get(vt_symbol)
|
||||
if not bar:
|
||||
continue
|
||||
|
||||
target_pos = self.targets_pos[vt_symbol]
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
pos[vt_symbol] = current_pos
|
||||
capital[vt_symbol] = abs(bar.close_price * current_pos)
|
||||
|
||||
# 计算仓位差异,当产生差异时候,才进行调整
|
||||
pos_diff = target_pos - current_pos
|
||||
|
||||
if pos_diff > 0:
|
||||
price = bar.close_price * (1 + self.price_add_percent)
|
||||
if current_pos < 0:
|
||||
self.cover(vt_symbol, price, pos_diff)
|
||||
else:
|
||||
self.buy(vt_symbol, price, pos_diff)
|
||||
|
||||
elif pos_diff < 0:
|
||||
price = bar.close_price * (1 - self.price_add_percent)
|
||||
if current_pos > 0:
|
||||
self.sell(vt_symbol, price, - pos_diff)
|
||||
else:
|
||||
self.short(vt_symbol, price, - pos_diff)
|
||||
|
||||
self.show_pos[today] = pos
|
||||
self.symbol_cap[today] = capital
|
||||
|
||||
self.trade_day += 1
|
||||
self.put_event()
|
||||
22396
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[作业1] MACD横截面策略.ipynb
Normal file
22396
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[作业1] MACD横截面策略.ipynb
Normal file
File diff suppressed because one or more lines are too long
154
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[作业1}macd10_strategy.py
Normal file
154
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[作业1}macd10_strategy.py
Normal file
@@ -0,0 +1,154 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
from operator import itemgetter
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
from vnpy.trader.constant import Interval
|
||||
|
||||
|
||||
class Macd10Strategy(StrategyTemplate):
|
||||
""""""
|
||||
author = "KeKe"
|
||||
|
||||
price_add_percent = 0.05 # 超价5%下单
|
||||
fixed_pos_value = 100000 # 每个合约做100万
|
||||
trade_day = 0
|
||||
targets_pos = {}
|
||||
macd_data = {}
|
||||
target_cs = {}
|
||||
target_total = {}
|
||||
|
||||
parameters = [
|
||||
"price_add_percent",
|
||||
"fixed_size",
|
||||
]
|
||||
variables = [
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
self.last_tick_time: datetime = None
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
|
||||
self.bgs[vt_symbol] = BarGenerator(on_bar)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(10, interval=Interval.DAILY)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
# MACD指标计算
|
||||
for vt_symbol, bar in bars.items():
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
|
||||
x, y, macd = am.macd(10, 20, 5)
|
||||
self.macd_data[vt_symbol] = macd
|
||||
|
||||
# 按照MACD从小到大排序
|
||||
sorted_l = sorted(self.macd_data.items(), key=itemgetter(1))
|
||||
len_symbol = len(sorted_l) # 10
|
||||
|
||||
choose = int(0.25 * len_symbol) # int(2.5) =2
|
||||
|
||||
short_part = dict(sorted_l[:choose])
|
||||
long_part = dict(sorted_l[-choose:])
|
||||
not_trade_part = dict(sorted_l[choose: -choose])
|
||||
|
||||
for k in short_part:
|
||||
self.target_cs[k] = -1
|
||||
for k in long_part:
|
||||
self.target_cs[k] = 1
|
||||
for k in not_trade_part:
|
||||
self.target_cs[k] = 0
|
||||
|
||||
# 信号汇总
|
||||
for vt_symbol, bar in bars.items():
|
||||
self.target_total[vt_symbol] = self.target_cs[vt_symbol]
|
||||
self.targets_pos[vt_symbol] = int(
|
||||
self.fixed_pos_value / bar.close_price
|
||||
) * self.target_total[vt_symbol]
|
||||
|
||||
# 交易执行
|
||||
if self.trade_day == 0 or not (self.trade_day + 0) % 10:
|
||||
|
||||
for vt_symbol in self.vt_symbols:
|
||||
bar = bars.get(vt_symbol)
|
||||
if not bar:
|
||||
continue
|
||||
|
||||
target_pos = self.targets_pos[vt_symbol]
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
|
||||
pos_diff = target_pos - current_pos
|
||||
|
||||
if pos_diff > 0:
|
||||
price = bar.close_price * (1 + self.price_add_percent)
|
||||
if current_pos < 0:
|
||||
self.cover(vt_symbol, price, pos_diff)
|
||||
else:
|
||||
self.buy(vt_symbol, price, pos_diff)
|
||||
|
||||
elif pos_diff < 0:
|
||||
price = bar.close_price * (1 - self.price_add_percent)
|
||||
if current_pos > 0:
|
||||
self.sell(vt_symbol, price, - pos_diff)
|
||||
else:
|
||||
self.short(vt_symbol, price, - pos_diff)
|
||||
|
||||
self.trade_day += 1
|
||||
self.put_event()
|
||||
2093
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[作业2] 多周期合成.ipynb
Normal file
2093
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[作业2] 多周期合成.ipynb
Normal file
File diff suppressed because one or more lines are too long
224
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[作业2]demo_strategy.py
Normal file
224
5.课程代码/1.投资组合策略7天入门/原始代码/archive/[作业2]demo_strategy.py
Normal file
@@ -0,0 +1,224 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from vnpy.trader.constant import Interval
|
||||
|
||||
|
||||
class DemoStrategy(StrategyTemplate):
|
||||
""""""
|
||||
|
||||
author = "KeKe"
|
||||
|
||||
price_add_percent = 0.05 # 超价5%下单
|
||||
fixed_pos_value = 1000000 # 每个合约做10万
|
||||
atr_window = 22
|
||||
atr_ma_window = 10
|
||||
rsi_window = 5
|
||||
rsi_entry = 16
|
||||
trailing_percent = 0.8
|
||||
fixed_size = 1
|
||||
price_add = 5
|
||||
|
||||
rsi_buy = 0
|
||||
rsi_sell = 0
|
||||
|
||||
signal_ts = {}
|
||||
signal_total = {}
|
||||
last_tick_time: datetime = None
|
||||
last_bar_time: datetime = None
|
||||
trade_day = 0
|
||||
targets_pos = {}
|
||||
show_pos = {}
|
||||
symbol_cap = {}
|
||||
window_bars = {}
|
||||
today = None
|
||||
|
||||
parameters = [
|
||||
"price_add_percent", "fixed_pos_value",
|
||||
"return_period", "holding_period", "shift_period"
|
||||
]
|
||||
variables = [
|
||||
"signal_ts", "signal_total",
|
||||
"trade_day", "targets_pos"
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
self.rsi_data: Dict[str, float] = {}
|
||||
self.atr_data: Dict[str, float] = {}
|
||||
self.atr_ma: Dict[str, float] = {}
|
||||
self.intra_trade_high: Dict[str, float] = {}
|
||||
self.intra_trade_low: Dict[str, float] = {}
|
||||
|
||||
self.targets: Dict[str, int] = {}
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
self.bgs[vt_symbol] = BarGenerator(
|
||||
self.on_bar,
|
||||
5,
|
||||
self.on_window_bar
|
||||
)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(days=20, interval=Interval.MINUTE)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
|
||||
def on_window_bar(self, bar):
|
||||
dt = bar.datetime.strftime("%Y%d%m, %H:%M")
|
||||
|
||||
if (
|
||||
self.last_bar_time
|
||||
and self.last_bar_time.minute != bar.datetime.minute
|
||||
):
|
||||
self.on_window_bars(self.window_bars)
|
||||
|
||||
self.window_bars = {}
|
||||
self.window_bars[bar.vt_symbol] = bar
|
||||
# print("@", dt, bar.vt_symbol, bar.close_price)
|
||||
else:
|
||||
# print("@@", dt, bar.vt_symbol, bar.close_price)
|
||||
self.window_bars[bar.vt_symbol] = bar
|
||||
|
||||
self.last_bar_time = bar.datetime
|
||||
|
||||
def on_window_bars(self, bars):
|
||||
# test
|
||||
# dts = {}
|
||||
# for vt_symbol, bar in bars.items():
|
||||
# dt = bar.datetime.strftime("%H:%M")
|
||||
# dts[bar.vt_symbol] = dt
|
||||
# print("**", dts)
|
||||
|
||||
# return
|
||||
# test
|
||||
self.cancel_all()
|
||||
|
||||
# 更新K线计算RSI数值
|
||||
for vt_symbol, bar in bars.items():
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
if not am.inited:
|
||||
return
|
||||
atr_array = am.atr(self.atr_window, array=True)
|
||||
self.atr_data[vt_symbol] = atr_array[-1]
|
||||
self.atr_ma[vt_symbol] = atr_array[-self.atr_ma_window:].mean()
|
||||
self.rsi_data[vt_symbol] = am.rsi(self.rsi_window)
|
||||
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
if current_pos == 0:
|
||||
self.intra_trade_high[vt_symbol] = bar.high_price
|
||||
self.intra_trade_low[vt_symbol] = bar.low_price
|
||||
|
||||
if self.atr_data[vt_symbol] > self.atr_ma[vt_symbol]:
|
||||
if self.rsi_data[vt_symbol] > self.rsi_buy:
|
||||
self.targets[vt_symbol] = self.fixed_size
|
||||
elif self.rsi_data[vt_symbol] < self.rsi_sell:
|
||||
self.targets[vt_symbol] = -self.fixed_size
|
||||
else:
|
||||
self.targets[vt_symbol] = 0
|
||||
|
||||
elif current_pos > 0:
|
||||
self.intra_trade_high[vt_symbol] = max(self.intra_trade_high[vt_symbol], bar.high_price)
|
||||
self.intra_trade_low[vt_symbol] = bar.low_price
|
||||
|
||||
long_stop = self.intra_trade_high[vt_symbol] * (1 - self.trailing_percent / 100)
|
||||
|
||||
if bar.close_price <= long_stop:
|
||||
self.targets[vt_symbol] = 0
|
||||
|
||||
elif current_pos < 0:
|
||||
self.intra_trade_low[vt_symbol] = min(self.intra_trade_low[vt_symbol], bar.low_price)
|
||||
self.intra_trade_high[vt_symbol] = bar.high_price
|
||||
|
||||
short_stop = self.intra_trade_low[vt_symbol] * (1 + self.trailing_percent / 100)
|
||||
|
||||
if bar.close_price >= short_stop:
|
||||
self.targets[vt_symbol] = 0
|
||||
|
||||
for vt_symbol in self.vt_symbols:
|
||||
target_pos = self.targets.get(vt_symbol, None)
|
||||
if not target_pos:
|
||||
continue
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
|
||||
pos_diff = target_pos - current_pos
|
||||
volume = abs(pos_diff)
|
||||
bar = bars[vt_symbol]
|
||||
|
||||
if pos_diff > 0:
|
||||
price = bar.close_price + self.price_add
|
||||
|
||||
if current_pos < 0:
|
||||
self.cover(vt_symbol, price, volume)
|
||||
else:
|
||||
self.buy(vt_symbol, price, volume)
|
||||
elif pos_diff < 0:
|
||||
price = bar.close_price - self.price_add
|
||||
|
||||
if current_pos > 0:
|
||||
self.sell(vt_symbol, price, volume)
|
||||
else:
|
||||
self.short(vt_symbol, price, volume)
|
||||
|
||||
self.put_event()
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bar = bars[vt_symbol]
|
||||
bg.update_bar(bar)
|
||||
141
5.课程代码/1.投资组合策略7天入门/原始代码/archive/double_ma_strategy.py
Normal file
141
5.课程代码/1.投资组合策略7天入门/原始代码/archive/double_ma_strategy.py
Normal file
@@ -0,0 +1,141 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
|
||||
class DoubleMaStrategy(StrategyTemplate):
|
||||
""""""
|
||||
|
||||
author = "KeKe"
|
||||
|
||||
fast_window = 8
|
||||
slow_window = 24
|
||||
price_add = 5
|
||||
|
||||
today = ""
|
||||
daily_pos = {}
|
||||
daily_close = {}
|
||||
|
||||
parameters = [
|
||||
"fast_window",
|
||||
"slow_window",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
self.last_tick_time: datetime = None
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
self.bgs[vt_symbol] = BarGenerator(on_bar)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(100)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
|
||||
# 更新K线计算
|
||||
for vt_symbol, bar in bars.items():
|
||||
dt_str = bar.datetime.strftime("%Y-%m-%d")
|
||||
self.today = dt_str
|
||||
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
if not am.inited:
|
||||
continue
|
||||
|
||||
fast_ma = am.sma(self.fast_window, array=True)
|
||||
fast_ma0 = fast_ma[-1]
|
||||
fast_ma1 = fast_ma[-2]
|
||||
|
||||
slow_ma = am.sma(self.slow_window, array=True)
|
||||
slow_ma0 = slow_ma[-1]
|
||||
slow_ma1 = slow_ma[-2]
|
||||
|
||||
cross_over = fast_ma0 > slow_ma0 and fast_ma1 < slow_ma1
|
||||
cross_below = fast_ma0 < slow_ma0 and fast_ma1 > slow_ma1
|
||||
|
||||
pos = self.get_pos(vt_symbol)
|
||||
if cross_over:
|
||||
if pos == 0:
|
||||
self.buy(vt_symbol, bar.close_price, 1)
|
||||
elif pos < 0:
|
||||
self.cover(vt_symbol, bar.close_price, 1)
|
||||
self.buy(vt_symbol, bar.close_price, 1)
|
||||
elif cross_below:
|
||||
if pos == 0:
|
||||
self.short(vt_symbol, bar.close_price, 1)
|
||||
elif pos > 0:
|
||||
self.sell(vt_symbol, bar.close_price, 1)
|
||||
self.short(vt_symbol, bar.close_price, 1)
|
||||
|
||||
self.record_current_pos(bars)
|
||||
|
||||
self.put_event()
|
||||
|
||||
def record_current_pos(self, bars):
|
||||
current_pos = {}
|
||||
current_close = {}
|
||||
for bar in bars.values():
|
||||
pos = self.get_pos(bar.vt_symbol)
|
||||
current_pos[bar.vt_symbol] = pos
|
||||
current_close[bar.vt_symbol] = bar.close_price
|
||||
|
||||
today = self.today
|
||||
|
||||
self.daily_pos[today] = str(current_pos)
|
||||
self.daily_close[today] = current_close
|
||||
154
5.课程代码/1.投资组合策略7天入门/原始代码/archive/return10_strategy.py
Normal file
154
5.课程代码/1.投资组合策略7天入门/原始代码/archive/return10_strategy.py
Normal file
@@ -0,0 +1,154 @@
|
||||
from typing import List, Dict
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
|
||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from vnpy.trader.constant import Interval
|
||||
|
||||
|
||||
class Return10Strategy(StrategyTemplate):
|
||||
""""""
|
||||
|
||||
author = "KeKe"
|
||||
|
||||
price_add_percent = 0.05 # 超价5%下单
|
||||
fixed_pos_value = 1000000 # 每个合约做100万
|
||||
signal_ts = {}
|
||||
signal_total = {}
|
||||
last_tick_time: datetime = None
|
||||
trade_day = 0
|
||||
targets_pos = {}
|
||||
|
||||
parameters = [
|
||||
"price_add_percent",
|
||||
"fixed_size",
|
||||
]
|
||||
variables = [
|
||||
"signal_ts", "signal_total",
|
||||
"trade_day", "targets_pos"
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy_engine: StrategyEngine,
|
||||
strategy_name: str,
|
||||
vt_symbols: List[str],
|
||||
setting: dict
|
||||
):
|
||||
""""""
|
||||
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
|
||||
|
||||
self.bgs: Dict[str, BarGenerator] = {}
|
||||
self.ams: Dict[str, ArrayManager] = {}
|
||||
|
||||
# Obtain contract info
|
||||
for vt_symbol in self.vt_symbols:
|
||||
def on_bar(bar: BarData):
|
||||
""""""
|
||||
pass
|
||||
|
||||
self.bgs[vt_symbol] = BarGenerator(on_bar)
|
||||
self.ams[vt_symbol] = ArrayManager()
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.load_bars(days=20, interval=Interval.DAILY)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
if (
|
||||
self.last_tick_time
|
||||
and self.last_tick_time.minute != tick.datetime.minute
|
||||
):
|
||||
bars = {}
|
||||
for vt_symbol, bg in self.bgs.items():
|
||||
bars[vt_symbol] = bg.generate()
|
||||
self.on_bars(bars)
|
||||
|
||||
bg: BarGenerator = self.bgs[tick.vt_symbol]
|
||||
bg.update_tick(tick)
|
||||
|
||||
self.last_tick_time = tick.datetime
|
||||
|
||||
def on_bars(self, bars: Dict[str, BarData]):
|
||||
""""""
|
||||
# 1) 全撤
|
||||
self.cancel_all()
|
||||
|
||||
# 2.3)初始化am &计算时间序列
|
||||
for vt_symbol, bar in bars.items():
|
||||
am: ArrayManager = self.ams[vt_symbol]
|
||||
am.update_bar(bar)
|
||||
|
||||
# if not am.inited:
|
||||
# return
|
||||
|
||||
# 信号 过去10天的收益率
|
||||
return10 = am.rocp(10)
|
||||
|
||||
# 信号>0,时序信号+1,信号<0,时序信号-1
|
||||
if return10 > 0:
|
||||
self.signal_ts[vt_symbol] = 1
|
||||
elif return10 < - 0:
|
||||
self.signal_ts[vt_symbol] = -1
|
||||
else:
|
||||
self.signal_ts[vt_symbol] = 0
|
||||
|
||||
# 3)信号汇总,总信号=时序信号汇总 + 横截面信号汇总
|
||||
# 基于总体信号,得到目标持仓
|
||||
for vt_symbol, bar in bars.items():
|
||||
self.signal_total[vt_symbol] = self.signal_ts[vt_symbol]
|
||||
self.targets_pos[vt_symbol] = int(
|
||||
self.fixed_pos_value / bar.close_price
|
||||
) * self.signal_total[vt_symbol]
|
||||
|
||||
# 3)交易执行(每隔10个交易日检查并且调仓)
|
||||
if self.trade_day == 0 or not self.trade_day % 10:
|
||||
|
||||
for vt_symbol in self.vt_symbols:
|
||||
bar = bars.get(vt_symbol)
|
||||
if not bar:
|
||||
continue
|
||||
|
||||
target_pos = self.targets_pos[vt_symbol]
|
||||
current_pos = self.get_pos(vt_symbol)
|
||||
|
||||
# 计算仓位差异,当产生差异时候,才进行调整
|
||||
pos_diff = target_pos - current_pos
|
||||
|
||||
if pos_diff > 0:
|
||||
price = bar.close_price * (1 + self.price_add_percent)
|
||||
if current_pos < 0:
|
||||
self.cover(vt_symbol, price, pos_diff)
|
||||
else:
|
||||
self.buy(vt_symbol, price, pos_diff)
|
||||
|
||||
elif pos_diff < 0:
|
||||
price = bar.close_price * (1 - self.price_add_percent)
|
||||
if current_pos > 0:
|
||||
self.sell(vt_symbol, price, - pos_diff)
|
||||
else:
|
||||
self.short(vt_symbol, price, - pos_diff)
|
||||
|
||||
self.trade_day += 1
|
||||
self.put_event()
|
||||
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/archive/第2课_认识Portfolio Strategy模块.emmx
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/archive/第2课_认识Portfolio Strategy模块.emmx
Normal file
Binary file not shown.
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/archive/第4课_认识策略模板.emmx
Normal file
BIN
5.课程代码/1.投资组合策略7天入门/原始代码/archive/第4课_认识策略模板.emmx
Normal file
Binary file not shown.
2123
5.课程代码/2.Option_spread_strategy/使用文档/10/10_demo.ipynb
Normal file
2123
5.课程代码/2.Option_spread_strategy/使用文档/10/10_demo.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
195
5.课程代码/2.Option_spread_strategy/使用文档/10/black_76.py
Normal file
195
5.课程代码/2.Option_spread_strategy/使用文档/10/black_76.py
Normal file
@@ -0,0 +1,195 @@
|
||||
from scipy import stats
|
||||
from math import log, pow, sqrt, exp
|
||||
from typing import Tuple
|
||||
|
||||
cdf = stats.norm.cdf
|
||||
pdf = stats.norm.pdf
|
||||
|
||||
|
||||
def calculate_d1(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float
|
||||
) -> float:
|
||||
"""Calculate option D1 value"""
|
||||
d1: float = (log(s / k) + (0.5 * pow(v, 2)) * t) / (v * sqrt(t))
|
||||
return d1
|
||||
|
||||
|
||||
def calculate_price(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
cp: int,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option price"""
|
||||
if v <= 0 or not t:
|
||||
return max(0, cp * (s - k))
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
d2: float = d1 - v * sqrt(t)
|
||||
|
||||
price: float = cp * (s * cdf(cp * d1) - k * cdf(cp * d2)) * exp(-r * t)
|
||||
return price
|
||||
|
||||
|
||||
def calculate_delta(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
cp: int,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option delta"""
|
||||
if v <= 0 or not t:
|
||||
return 0
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
|
||||
delta: float = cp * exp(-r * t) * cdf(cp * d1)
|
||||
return delta
|
||||
|
||||
|
||||
def calculate_gamma(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option gamma"""
|
||||
if v <= 0 or not t:
|
||||
return 0
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
|
||||
gamma: float = exp(-r * t) * pdf(d1) / (s * v * sqrt(t))
|
||||
return gamma
|
||||
|
||||
|
||||
def calculate_theta(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
cp: int,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option theta"""
|
||||
if v <= 0 or not t:
|
||||
return 0
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
d2: float = d1 - v * sqrt(t)
|
||||
|
||||
theta: float = -s * exp(-r * t) * pdf(d1) * v / (2 * sqrt(t)) \
|
||||
+ cp * r * s * exp(-r * t) * cdf(cp * d1) \
|
||||
- cp * r * k * exp(-r * t) * cdf(cp * d2)
|
||||
return theta
|
||||
|
||||
|
||||
def calculate_vega(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option vega"""
|
||||
if v <= 0 or not t:
|
||||
return 0
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
|
||||
vega: float = s * exp(-r * t) * pdf(d1) * sqrt(t)
|
||||
return vega
|
||||
|
||||
|
||||
def calculate_greeks(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
cp: int
|
||||
) -> Tuple[float, float, float, float, float]:
|
||||
"""Calculate option price and greeks"""
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
price: float = calculate_price(s, k, r, t, v, cp, d1)
|
||||
delta: float = calculate_delta(s, k, r, t, v, cp, d1)
|
||||
gamma: float = calculate_gamma(s, k, r, t, v, d1)
|
||||
theta: float = calculate_theta(s, k, r, t, v, cp, d1)
|
||||
vega: float = calculate_vega(s, k, r, t, v, d1)
|
||||
return price, delta, gamma, theta, vega
|
||||
|
||||
|
||||
def calculate_impv(
|
||||
price: float,
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
cp: int
|
||||
):
|
||||
"""Calculate option implied volatility"""
|
||||
# Check option price must be positive
|
||||
if price <= 0 or not t:
|
||||
return 0
|
||||
|
||||
# Check if option price meets minimum value (exercise value)
|
||||
meet: bool = False
|
||||
|
||||
if cp == 1 and (price > (s - k) * exp(-r * t)):
|
||||
meet = True
|
||||
elif cp == -1 and (price > k * exp(-r * t) - s):
|
||||
meet = True
|
||||
|
||||
# If minimum value not met, return 0
|
||||
if not meet:
|
||||
return 0
|
||||
|
||||
# Calculate implied volatility with Newton's method
|
||||
v: float = 0.01 # Initial guess of volatility
|
||||
|
||||
for i in range(50):
|
||||
# Caculate option price and vega with current guess
|
||||
p: float = calculate_price(s, k, r, t, v, cp)
|
||||
vega: float = calculate_vega(s, k, r, t, v, cp)
|
||||
|
||||
# Break loop if vega too close to 0
|
||||
if not vega:
|
||||
break
|
||||
|
||||
# Calculate error value
|
||||
dx: float = (price - p) / vega
|
||||
|
||||
# Check if error value meets requirement
|
||||
if abs(dx) < 0.00001:
|
||||
break
|
||||
|
||||
# Calculate guessed implied volatility of next round
|
||||
v += dx
|
||||
|
||||
# Check end result to be non-negative
|
||||
if v <= 0:
|
||||
return 0
|
||||
|
||||
# Round to 4 decimal places
|
||||
v = round(v, 4)
|
||||
|
||||
return v
|
||||
1347
5.课程代码/2.Option_spread_strategy/使用文档/11/11_demo.ipynb
Normal file
1347
5.课程代码/2.Option_spread_strategy/使用文档/11/11_demo.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
195
5.课程代码/2.Option_spread_strategy/使用文档/11/black_76.py
Normal file
195
5.课程代码/2.Option_spread_strategy/使用文档/11/black_76.py
Normal file
@@ -0,0 +1,195 @@
|
||||
from scipy import stats
|
||||
from math import log, pow, sqrt, exp
|
||||
from typing import Tuple
|
||||
|
||||
cdf = stats.norm.cdf
|
||||
pdf = stats.norm.pdf
|
||||
|
||||
|
||||
def calculate_d1(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float
|
||||
) -> float:
|
||||
"""Calculate option D1 value"""
|
||||
d1: float = (log(s / k) + (0.5 * pow(v, 2)) * t) / (v * sqrt(t))
|
||||
return d1
|
||||
|
||||
|
||||
def calculate_price(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
cp: int,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option price"""
|
||||
if v <= 0 or not t:
|
||||
return max(0, cp * (s - k))
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
d2: float = d1 - v * sqrt(t)
|
||||
|
||||
price: float = cp * (s * cdf(cp * d1) - k * cdf(cp * d2)) * exp(-r * t)
|
||||
return price
|
||||
|
||||
|
||||
def calculate_delta(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
cp: int,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option delta"""
|
||||
if v <= 0 or not t:
|
||||
return 0
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
|
||||
delta: float = cp * exp(-r * t) * cdf(cp * d1)
|
||||
return delta
|
||||
|
||||
|
||||
def calculate_gamma(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option gamma"""
|
||||
if v <= 0 or not t:
|
||||
return 0
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
|
||||
gamma: float = exp(-r * t) * pdf(d1) / (s * v * sqrt(t))
|
||||
return gamma
|
||||
|
||||
|
||||
def calculate_theta(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
cp: int,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option theta"""
|
||||
if v <= 0 or not t:
|
||||
return 0
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
d2: float = d1 - v * sqrt(t)
|
||||
|
||||
theta: float = -s * exp(-r * t) * pdf(d1) * v / (2 * sqrt(t)) \
|
||||
+ cp * r * s * exp(-r * t) * cdf(cp * d1) \
|
||||
- cp * r * k * exp(-r * t) * cdf(cp * d2)
|
||||
return theta
|
||||
|
||||
|
||||
def calculate_vega(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
d1: float = 0.0
|
||||
) -> float:
|
||||
"""Calculate option vega"""
|
||||
if v <= 0 or not t:
|
||||
return 0
|
||||
|
||||
if not d1:
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
|
||||
vega: float = s * exp(-r * t) * pdf(d1) * sqrt(t)
|
||||
return vega
|
||||
|
||||
|
||||
def calculate_greeks(
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
v: float,
|
||||
cp: int
|
||||
) -> Tuple[float, float, float, float, float]:
|
||||
"""Calculate option price and greeks"""
|
||||
d1: float = calculate_d1(s, k, r, t, v)
|
||||
price: float = calculate_price(s, k, r, t, v, cp, d1)
|
||||
delta: float = calculate_delta(s, k, r, t, v, cp, d1)
|
||||
gamma: float = calculate_gamma(s, k, r, t, v, d1)
|
||||
theta: float = calculate_theta(s, k, r, t, v, cp, d1)
|
||||
vega: float = calculate_vega(s, k, r, t, v, d1)
|
||||
return price, delta, gamma, theta, vega
|
||||
|
||||
|
||||
def calculate_impv(
|
||||
price: float,
|
||||
s: float,
|
||||
k: float,
|
||||
r: float,
|
||||
t: float,
|
||||
cp: int
|
||||
):
|
||||
"""Calculate option implied volatility"""
|
||||
# Check option price must be positive
|
||||
if price <= 0 or not t:
|
||||
return 0
|
||||
|
||||
# Check if option price meets minimum value (exercise value)
|
||||
meet: bool = False
|
||||
|
||||
if cp == 1 and (price > (s - k) * exp(-r * t)):
|
||||
meet = True
|
||||
elif cp == -1 and (price > k * exp(-r * t) - s):
|
||||
meet = True
|
||||
|
||||
# If minimum value not met, return 0
|
||||
if not meet:
|
||||
return 0
|
||||
|
||||
# Calculate implied volatility with Newton's method
|
||||
v: float = 0.01 # Initial guess of volatility
|
||||
|
||||
for i in range(50):
|
||||
# Caculate option price and vega with current guess
|
||||
p: float = calculate_price(s, k, r, t, v, cp)
|
||||
vega: float = calculate_vega(s, k, r, t, v, cp)
|
||||
|
||||
# Break loop if vega too close to 0
|
||||
if not vega:
|
||||
break
|
||||
|
||||
# Calculate error value
|
||||
dx: float = (price - p) / vega
|
||||
|
||||
# Check if error value meets requirement
|
||||
if abs(dx) < 0.00001:
|
||||
break
|
||||
|
||||
# Calculate guessed implied volatility of next round
|
||||
v += dx
|
||||
|
||||
# Check end result to be non-negative
|
||||
if v <= 0:
|
||||
return 0
|
||||
|
||||
# Round to 4 decimal places
|
||||
v = round(v, 4)
|
||||
|
||||
return v
|
||||
997
5.课程代码/2.Option_spread_strategy/使用文档/15/15_demo.ipynb
Normal file
997
5.课程代码/2.Option_spread_strategy/使用文档/15/15_demo.ipynb
Normal file
@@ -0,0 +1,997 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1fee51d2-8d41-468e-b416-a58bed1ddbb9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"数据字典地址:http://docs.thinktrader.net/pages/7c0936/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "e63c7fc2-2500-4d50-a5af-8af4aaa91c1b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Token连接(若通过客户端连接则无需运行此单元格)\n",
|
||||
"from vnpy.trader.utility import TEMP_DIR\n",
|
||||
"\n",
|
||||
"from xtquant import xtdatacenter as xtdc\n",
|
||||
"\n",
|
||||
"# 设置迅投研令牌\n",
|
||||
"xtdc.set_token(\"4aff6f3b0dcfc990ec9476213ba784e17c34e757\") # 换成自己的Token\n",
|
||||
"\n",
|
||||
"# 设置临时文件目录\n",
|
||||
"xtdc.set_data_home_dir(str(TEMP_DIR) + \"\\\\xt\")\n",
|
||||
"\n",
|
||||
"# 初始化连接\n",
|
||||
"xtdc.init()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "cc8d3d17-28bb-42a9-aea7-95879d9a5994",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from xtquant.xtdata import (\n",
|
||||
" download_history_data,\n",
|
||||
" download_financial_data,\n",
|
||||
" get_local_data,\n",
|
||||
" get_stock_list_in_sector,\n",
|
||||
" get_instrument_detail,\n",
|
||||
" get_financial_data,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "7a04439d-b14f-48a9-9269-420a0c7c2c58",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'90000001.SZO': Empty DataFrame\n",
|
||||
" Columns: [time, open, high, low, close, volume, amount, settelementPrice, openInterest, preClose, suspendFlag]\n",
|
||||
" Index: []}"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 期权数据(1d也支持)\n",
|
||||
"download_history_data(\"90000001.SZO\", \"1m\", \"20200101\", \"20200112\")\n",
|
||||
"data1 = get_local_data([], [\"90000001.SZO\"], \"1m\", \"20200101\", \"20200112\")\n",
|
||||
"data1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "a9347593-3ed2-42a6-93e2-534ffe5fbc09",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>time</th>\n",
|
||||
" <th>open</th>\n",
|
||||
" <th>high</th>\n",
|
||||
" <th>low</th>\n",
|
||||
" <th>close</th>\n",
|
||||
" <th>volume</th>\n",
|
||||
" <th>amount</th>\n",
|
||||
" <th>settelementPrice</th>\n",
|
||||
" <th>openInterest</th>\n",
|
||||
" <th>preClose</th>\n",
|
||||
" <th>suspendFlag</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
"Empty DataFrame\n",
|
||||
"Columns: [time, open, high, low, close, volume, amount, settelementPrice, openInterest, preClose, suspendFlag]\n",
|
||||
"Index: []"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data1[\"90000001.SZO\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "32f8a0db",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'rb2401.SF': time open high low close volume \\\n",
|
||||
" 20231026090100 1698282060000 3665.0 3669.0 3665.0 3667.0 7834 \n",
|
||||
" 20231026090200 1698282120000 3668.0 3668.0 3666.0 3668.0 3807 \n",
|
||||
" 20231026090300 1698282180000 3668.0 3669.0 3665.0 3666.0 4264 \n",
|
||||
" 20231026090400 1698282240000 3666.0 3669.0 3666.0 3668.0 2269 \n",
|
||||
" 20231026090500 1698282300000 3668.0 3668.0 3666.0 3667.0 1518 \n",
|
||||
" ... ... ... ... ... ... ... \n",
|
||||
" 20231030225600 1698677760000 3723.0 3724.0 3722.0 3724.0 2955 \n",
|
||||
" 20231030225700 1698677820000 3723.0 3724.0 3720.0 3721.0 4641 \n",
|
||||
" 20231030225800 1698677880000 3720.0 3723.0 3720.0 3723.0 3093 \n",
|
||||
" 20231030225900 1698677940000 3722.0 3723.0 3721.0 3722.0 2247 \n",
|
||||
" 20231030230000 1698678000000 3721.0 3723.0 3720.0 3722.0 5145 \n",
|
||||
" \n",
|
||||
" amount settelementPrice openInterest preClose \\\n",
|
||||
" 20231026090100 287264340.0 0.0 1762615 3665.0 \n",
|
||||
" 20231026090200 139616890.0 0.0 1762851 3667.0 \n",
|
||||
" 20231026090300 156379480.0 0.0 1763036 3668.0 \n",
|
||||
" 20231026090400 83222740.0 0.0 1763346 3666.0 \n",
|
||||
" 20231026090500 55658560.0 0.0 1763165 3668.0 \n",
|
||||
" ... ... ... ... ... \n",
|
||||
" 20231030225600 110019310.0 0.0 1690326 3722.0 \n",
|
||||
" 20231030225700 172706690.0 0.0 1689474 3724.0 \n",
|
||||
" 20231030225800 115105860.0 0.0 1688648 3721.0 \n",
|
||||
" 20231030225900 83633400.0 0.0 1688086 3723.0 \n",
|
||||
" 20231030230000 191473920.0 0.0 1686985 3722.0 \n",
|
||||
" \n",
|
||||
" suspendFlag \n",
|
||||
" 20231026090100 0 \n",
|
||||
" 20231026090200 0 \n",
|
||||
" 20231026090300 0 \n",
|
||||
" 20231026090400 0 \n",
|
||||
" 20231026090500 0 \n",
|
||||
" ... ... \n",
|
||||
" 20231030225600 0 \n",
|
||||
" 20231030225700 0 \n",
|
||||
" 20231030225800 0 \n",
|
||||
" 20231030225900 0 \n",
|
||||
" 20231030230000 0 \n",
|
||||
" \n",
|
||||
" [1455 rows x 11 columns]}"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 期货数据(1d也支持)\n",
|
||||
"download_history_data(\"rb2401.SF\", \"1m\", \"20230601\", \"20231030\")\n",
|
||||
"data1 = get_local_data([], [\"rb2401.SF\"], \"1m\", \"20231026\", \"20231030\")\n",
|
||||
"data1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "1ade0d1d-1905-4316-b1b4-ebd62cc3834c",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'rb2309.SF': Empty DataFrame\n",
|
||||
" Columns: [time, lastPrice, open, high, low, lastClose, amount, volume, pvolume, stockStatus, openInt, lastSettlementPrice, askPrice, bidPrice, askVol, bidVol, settlementPrice, transactionNum]\n",
|
||||
" Index: []}"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# L1 Tick数据\n",
|
||||
"download_history_data(\"rb2309.SF\", \"tick\", \"20230821\", \"20230822\")\n",
|
||||
"data2 = get_local_data([], [\"rb2309.SF\"], \"tick\", \"20230821\", \"20230822\")\n",
|
||||
"data2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "a6c481e8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 下载历史合约信息\n",
|
||||
"download_history_data(\"\", \"historycontract\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "4aea61d2-aab4-4189-b19f-862ec22d6a34",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"4807\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 期权过期合约查询\n",
|
||||
"l = get_stock_list_in_sector(\"过期中金所\")\n",
|
||||
"# get_stock_list_in_sector(\"过期上证期权\")\n",
|
||||
"# get_stock_list_in_sector(\"过期深证期权\")\n",
|
||||
"print(len(l))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "681ffa29-c6e5-46cb-a519-7461425cc73f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"['00.IF', 'HO2301-C-2325.IF', 'HO2301-C-2350.IF']"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"l[:3]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "1f76b380-9d30-4dde-a2b6-913193b49b60",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'ExchangeID': 'SZO',\n",
|
||||
" 'InstrumentID': '90000001',\n",
|
||||
" 'InstrumentName': '300ETF购1月3700',\n",
|
||||
" 'Abbreviation': '300ETFG1Y3700',\n",
|
||||
" 'ProductID': '300ETF(159919)',\n",
|
||||
" 'ProductName': '',\n",
|
||||
" 'UnderlyingCode': '',\n",
|
||||
" 'ExtendName': '',\n",
|
||||
" 'ExchangeCode': '',\n",
|
||||
" 'RzrkCode': '',\n",
|
||||
" 'UniCode': '',\n",
|
||||
" 'CreateDate': '20191223',\n",
|
||||
" 'OpenDate': '20191223',\n",
|
||||
" 'ExpireDate': '20200122',\n",
|
||||
" 'PreClose': 0.4652,\n",
|
||||
" 'SettlementPrice': 0.4714,\n",
|
||||
" 'UpStopPrice': 0.8885,\n",
|
||||
" 'DownStopPrice': 0.0001,\n",
|
||||
" 'FloatVolume': 0.0,\n",
|
||||
" 'TotalVolume': 0.0,\n",
|
||||
" 'AccumulatedInterest': 1.7976931348623157e+308,\n",
|
||||
" 'LongMarginRatio': 0.0,\n",
|
||||
" 'ShortMarginRatio': 0.0,\n",
|
||||
" 'PriceTick': 0.0001,\n",
|
||||
" 'VolumeMultiple': 10000,\n",
|
||||
" 'MainContract': 0,\n",
|
||||
" 'MaxMarketOrderVolume': 10,\n",
|
||||
" 'MinMarketOrderVolume': 1,\n",
|
||||
" 'MaxLimitOrderVolume': 50,\n",
|
||||
" 'MinLimitOrderVolume': 1,\n",
|
||||
" 'MaxMarginSideAlgorithm': 49,\n",
|
||||
" 'DayCountFromIPO': 2147483647,\n",
|
||||
" 'LastVolume': 239,\n",
|
||||
" 'InstrumentStatus': 0,\n",
|
||||
" 'IsTrading': False,\n",
|
||||
" 'IsRecent': False,\n",
|
||||
" 'IsContinuous': False,\n",
|
||||
" 'bNotProfitable': False,\n",
|
||||
" 'bDualClass': False,\n",
|
||||
" 'ContinueType': 0,\n",
|
||||
" 'secuCategory': 0,\n",
|
||||
" 'secuAttri': 0,\n",
|
||||
" 'MaxMarketSellOrderVolume': 2147483647,\n",
|
||||
" 'MinMarketSellOrderVolume': 0,\n",
|
||||
" 'MaxLimitSellOrderVolume': 2147483647,\n",
|
||||
" 'MinLimitSellOrderVolume': 0,\n",
|
||||
" 'MaxFixedBuyOrderVol': 2147483647,\n",
|
||||
" 'MinFixedBuyOrderVol': 0,\n",
|
||||
" 'MaxFixedSellOrderVol': 2147483647,\n",
|
||||
" 'MinFixedSellOrderVol': 0,\n",
|
||||
" 'HSGTFlag': 0,\n",
|
||||
" 'BondParValue': 1.7976931348623157e+308,\n",
|
||||
" 'QualifiedType': 2147483647,\n",
|
||||
" 'PriceTickType': 2147483647,\n",
|
||||
" 'tradingStatus': '',\n",
|
||||
" 'ExtendInfo': {'OptUnit': 1.7976931348623157e+308,\n",
|
||||
" 'MarginUnit': 9719.2,\n",
|
||||
" 'OptUndlCode': '159919',\n",
|
||||
" 'OptUndlMarket': 'SZ',\n",
|
||||
" 'OptLotSize': 0,\n",
|
||||
" 'OptExercisePrice': 3.7,\n",
|
||||
" 'NeeqExeType': 0,\n",
|
||||
" 'OptExchFixedMargin': 1.7976931348623157e+308,\n",
|
||||
" 'OptExchMiniMargin': 1.7976931348623157e+308,\n",
|
||||
" 'Ccy': '',\n",
|
||||
" 'IbSecType': '',\n",
|
||||
" 'OptUndlRiskFreeRate': 0.0,\n",
|
||||
" 'OptUndlHistoryRate': 0.0,\n",
|
||||
" 'EndDelivDate': '20200122',\n",
|
||||
" 'RegisteredCapital': 2147483647,\n",
|
||||
" 'MaxOrderPriceRange': 1.7976931348623157e+308,\n",
|
||||
" 'MinOrderPriceRange': 1.7976931348623157e+308,\n",
|
||||
" 'VoteRightRatio': 1.0,\n",
|
||||
" 'm_nMinRepurchaseDaysLimit': 2147483647,\n",
|
||||
" 'm_nMaxRepurchaseDaysLimit': 2147483647,\n",
|
||||
" 'DeliveryYear': 0,\n",
|
||||
" 'DeliveryMonth': 0,\n",
|
||||
" 'ContractType': 0,\n",
|
||||
" 'ProductTradeQuota': 0,\n",
|
||||
" 'ContractTradeQuota': 0,\n",
|
||||
" 'ProductOpenInterestQuota': 0,\n",
|
||||
" 'ContractOpenInterestQuota': 0}}"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 获取期权合约信息\n",
|
||||
"get_instrument_detail(\"90000001.SZO\", True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "7269450a-ea0c-4652-9d0d-bd31b572067a",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'600519.SH': {'Balance': m_timetag m_anntime internal_shoule_recv fixed_capital_clearance \\\n",
|
||||
" 0 20010630 20010822 NaN NaN \n",
|
||||
" 1 20011231 20020417 NaN 0.0 \n",
|
||||
" 2 20020331 20020429 NaN 0.0 \n",
|
||||
" 3 20020630 20020814 NaN 0.0 \n",
|
||||
" 4 20020930 20021029 NaN 0.0 \n",
|
||||
" .. ... ... ... ... \n",
|
||||
" 107 20221231 20230803 NaN NaN \n",
|
||||
" 108 20221231 20231021 NaN NaN \n",
|
||||
" 109 20230331 20230426 NaN NaN \n",
|
||||
" 110 20230630 20230803 NaN NaN \n",
|
||||
" 111 20230930 20231021 NaN NaN \n",
|
||||
" \n",
|
||||
" should_pay_money settlement_payment receivable_premium \\\n",
|
||||
" 0 NaN 0.0 NaN \n",
|
||||
" 1 NaN 0.0 NaN \n",
|
||||
" 2 NaN 0.0 NaN \n",
|
||||
" 3 NaN 0.0 NaN \n",
|
||||
" 4 NaN 0.0 NaN \n",
|
||||
" .. ... ... ... \n",
|
||||
" 107 NaN NaN NaN \n",
|
||||
" 108 NaN NaN NaN \n",
|
||||
" 109 NaN NaN NaN \n",
|
||||
" 110 NaN NaN NaN \n",
|
||||
" 111 NaN NaN NaN \n",
|
||||
" \n",
|
||||
" accounts_receivable_reinsurance reinsurance_contract_reserve \\\n",
|
||||
" 0 NaN 0.0 \n",
|
||||
" 1 NaN 0.0 \n",
|
||||
" 2 NaN 0.0 \n",
|
||||
" 3 NaN 0.0 \n",
|
||||
" 4 NaN 0.0 \n",
|
||||
" .. ... ... \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" 110 NaN NaN \n",
|
||||
" 111 NaN NaN \n",
|
||||
" \n",
|
||||
" dividends_payable ... m_guaranteeInvestmentFunds \\\n",
|
||||
" 0 NaN ... NaN \n",
|
||||
" 1 0.0 ... NaN \n",
|
||||
" 2 0.0 ... NaN \n",
|
||||
" 3 0.0 ... NaN \n",
|
||||
" 4 0.0 ... NaN \n",
|
||||
" .. ... ... ... \n",
|
||||
" 107 NaN ... NaN \n",
|
||||
" 108 NaN ... NaN \n",
|
||||
" 109 NaN ... NaN \n",
|
||||
" 110 NaN ... NaN \n",
|
||||
" 111 NaN ... NaN \n",
|
||||
" \n",
|
||||
" m_premiumsReceivedAdvance m_insuranceLiabilities \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" 110 NaN NaN \n",
|
||||
" 111 NaN NaN \n",
|
||||
" \n",
|
||||
" m_liabilitiesIndependentAccounts m_liabilitiesVicariousBusiness \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" 110 NaN NaN \n",
|
||||
" 111 NaN NaN \n",
|
||||
" \n",
|
||||
" m_otherLiablities m_capitalPremium m_petainedProfit \\\n",
|
||||
" 0 NaN NaN NaN \n",
|
||||
" 1 NaN NaN NaN \n",
|
||||
" 2 NaN NaN NaN \n",
|
||||
" 3 NaN NaN NaN \n",
|
||||
" 4 NaN NaN NaN \n",
|
||||
" .. ... ... ... \n",
|
||||
" 107 NaN NaN NaN \n",
|
||||
" 108 NaN NaN NaN \n",
|
||||
" 109 NaN NaN NaN \n",
|
||||
" 110 NaN NaN NaN \n",
|
||||
" 111 NaN NaN NaN \n",
|
||||
" \n",
|
||||
" m_provisionTransactionRisk m_otherReserves \n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" 110 NaN NaN \n",
|
||||
" 111 NaN NaN \n",
|
||||
" \n",
|
||||
" [112 rows x 146 columns],\n",
|
||||
" 'Income': m_timetag m_anntime revenue_inc earned_premium \\\n",
|
||||
" 0 20010630 20010822 8.738635e+08 NaN \n",
|
||||
" 1 20011231 20020417 1.618047e+09 NaN \n",
|
||||
" 2 20020331 20020429 7.180149e+08 NaN \n",
|
||||
" 3 20020630 20020814 9.556542e+08 NaN \n",
|
||||
" 4 20020930 20021029 1.363886e+09 NaN \n",
|
||||
" .. ... ... ... ... \n",
|
||||
" 105 20220930 20221017 8.716023e+10 NaN \n",
|
||||
" 106 20221231 20230331 1.240998e+11 NaN \n",
|
||||
" 107 20230331 20230426 3.875581e+10 NaN \n",
|
||||
" 108 20230630 20230803 6.957602e+10 NaN \n",
|
||||
" 109 20230930 20231021 1.032684e+11 NaN \n",
|
||||
" \n",
|
||||
" real_estate_sales_income total_operating_cost real_estate_sales_cost \\\n",
|
||||
" 0 NaN NaN NaN \n",
|
||||
" 1 NaN 1.009061e+09 NaN \n",
|
||||
" 2 NaN 3.808385e+08 NaN \n",
|
||||
" 3 NaN 5.545605e+08 NaN \n",
|
||||
" 4 NaN 8.382068e+08 NaN \n",
|
||||
" .. ... ... ... \n",
|
||||
" 105 NaN 2.789089e+10 NaN \n",
|
||||
" 106 NaN 3.974831e+10 NaN \n",
|
||||
" 107 NaN 1.071560e+10 NaN \n",
|
||||
" 108 NaN 2.117930e+10 NaN \n",
|
||||
" 109 NaN 3.223569e+10 NaN \n",
|
||||
" \n",
|
||||
" research_expenses surrender_value net_payments ... \\\n",
|
||||
" 0 NaN NaN NaN ... \n",
|
||||
" 1 NaN NaN NaN ... \n",
|
||||
" 2 NaN NaN NaN ... \n",
|
||||
" 3 NaN NaN NaN ... \n",
|
||||
" 4 NaN NaN NaN ... \n",
|
||||
" .. ... ... ... ... \n",
|
||||
" 105 1.149345e+08 NaN NaN ... \n",
|
||||
" 106 1.351857e+08 NaN NaN ... \n",
|
||||
" 107 2.295621e+07 NaN NaN ... \n",
|
||||
" 108 7.277068e+07 NaN NaN ... \n",
|
||||
" 109 1.011260e+08 NaN NaN ... \n",
|
||||
" \n",
|
||||
" m_paymentsInsuranceClaims m_amortizedCompensationExpenses \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 105 NaN NaN \n",
|
||||
" 106 NaN NaN \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" \n",
|
||||
" m_netReserveInsuranceLiability m_policyReserve \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 105 NaN NaN \n",
|
||||
" 106 NaN NaN \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" \n",
|
||||
" m_amortizeInsuranceReserve m_nsuranceFeesCommissionExpenses \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 105 NaN NaN \n",
|
||||
" 106 NaN NaN \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" \n",
|
||||
" m_operationAdministrativeExpense m_amortizedReinsuranceExpenditure \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 105 NaN NaN \n",
|
||||
" 106 NaN NaN \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" \n",
|
||||
" m_netProfitLossdisposalNonassets m_otherItemsAffectingNetProfit \n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 105 NaN NaN \n",
|
||||
" 106 NaN NaN \n",
|
||||
" 107 NaN NaN \n",
|
||||
" 108 NaN NaN \n",
|
||||
" 109 NaN NaN \n",
|
||||
" \n",
|
||||
" [110 rows x 71 columns],\n",
|
||||
" 'CashFlow': m_timetag m_anntime cash_received_ori_ins_contract_pre \\\n",
|
||||
" 0 20010630 20010822 NaN \n",
|
||||
" 1 20011231 20020417 NaN \n",
|
||||
" 2 20020630 20020814 NaN \n",
|
||||
" 3 20021231 20030326 NaN \n",
|
||||
" 4 20030331 20030425 NaN \n",
|
||||
" .. ... ... ... \n",
|
||||
" 86 20220930 20221017 NaN \n",
|
||||
" 87 20221231 20230331 NaN \n",
|
||||
" 88 20230331 20230426 NaN \n",
|
||||
" 89 20230630 20230803 NaN \n",
|
||||
" 90 20230930 20231021 NaN \n",
|
||||
" \n",
|
||||
" net_cash_received_rei_ope net_increase_insured_funds \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 86 NaN NaN \n",
|
||||
" 87 NaN NaN \n",
|
||||
" 88 NaN NaN \n",
|
||||
" 89 NaN NaN \n",
|
||||
" 90 NaN NaN \n",
|
||||
" \n",
|
||||
" net_increase_in_disposal cash_for_interest \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 86 NaN 2.494929e+09 \n",
|
||||
" 87 NaN 3.247615e+09 \n",
|
||||
" 88 NaN 8.549059e+08 \n",
|
||||
" 89 NaN 1.762971e+09 \n",
|
||||
" 90 NaN 2.334503e+09 \n",
|
||||
" \n",
|
||||
" net_increase_in_repurchase_funds cash_for_payment_original_insurance \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 86 NaN NaN \n",
|
||||
" 87 NaN NaN \n",
|
||||
" 88 NaN NaN \n",
|
||||
" 89 NaN NaN \n",
|
||||
" 90 NaN NaN \n",
|
||||
" \n",
|
||||
" cash_payment_policy_dividends ... m_netReductionDeposInveFunds \\\n",
|
||||
" 0 NaN ... NaN \n",
|
||||
" 1 NaN ... NaN \n",
|
||||
" 2 NaN ... NaN \n",
|
||||
" 3 NaN ... NaN \n",
|
||||
" 4 NaN ... NaN \n",
|
||||
" .. ... ... ... \n",
|
||||
" 86 NaN ... NaN \n",
|
||||
" 87 NaN ... NaN \n",
|
||||
" 88 NaN ... NaN \n",
|
||||
" 89 NaN ... NaN \n",
|
||||
" 90 NaN ... NaN \n",
|
||||
" \n",
|
||||
" m_netIncreaseUnwindingFunds m_netReductionAmountBorrowedFunds \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 86 NaN NaN \n",
|
||||
" 87 NaN NaN \n",
|
||||
" 88 NaN NaN \n",
|
||||
" 89 NaN NaN \n",
|
||||
" 90 NaN NaN \n",
|
||||
" \n",
|
||||
" m_netReductionSaleRepurchaseProceeds m_investmentPaidInCash \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 86 NaN NaN \n",
|
||||
" 87 NaN NaN \n",
|
||||
" 88 NaN NaN \n",
|
||||
" 89 NaN NaN \n",
|
||||
" 90 NaN NaN \n",
|
||||
" \n",
|
||||
" m_paymentOtherCashRelated m_cashOutFlowsInvesactivities \\\n",
|
||||
" 0 NaN NaN \n",
|
||||
" 1 NaN NaN \n",
|
||||
" 2 NaN NaN \n",
|
||||
" 3 NaN NaN \n",
|
||||
" 4 NaN NaN \n",
|
||||
" .. ... ... \n",
|
||||
" 86 NaN NaN \n",
|
||||
" 87 NaN NaN \n",
|
||||
" 88 NaN NaN \n",
|
||||
" 89 NaN NaN \n",
|
||||
" 90 NaN NaN \n",
|
||||
" \n",
|
||||
" m_absorbCashEquityInv m_otherImpactsOnCash m_addOperatingReceivableItems \n",
|
||||
" 0 NaN NaN NaN \n",
|
||||
" 1 NaN NaN NaN \n",
|
||||
" 2 NaN NaN NaN \n",
|
||||
" 3 NaN NaN NaN \n",
|
||||
" 4 NaN NaN NaN \n",
|
||||
" .. ... ... ... \n",
|
||||
" 86 NaN NaN NaN \n",
|
||||
" 87 NaN NaN NaN \n",
|
||||
" 88 NaN NaN NaN \n",
|
||||
" 89 NaN NaN NaN \n",
|
||||
" 90 NaN NaN NaN \n",
|
||||
" \n",
|
||||
" [91 rows x 110 columns],\n",
|
||||
" 'Capital': m_timetag m_anntime total_capital circulating_capital \\\n",
|
||||
" 0 20010827 20010822 2.500000e+08 7.150000e+07 \n",
|
||||
" 1 20020726 20020718 2.750000e+08 7.865000e+07 \n",
|
||||
" 2 20030715 20030708 3.025000e+08 8.651500e+07 \n",
|
||||
" 3 20040702 20040625 3.932500e+08 1.124695e+08 \n",
|
||||
" 4 20050808 20050730 4.719000e+08 1.349634e+08 \n",
|
||||
" 5 20060509 20060509 4.719000e+08 1.349634e+08 \n",
|
||||
" 6 20060525 20060522 9.438000e+08 3.023180e+08 \n",
|
||||
" 7 20070525 20070518 9.438000e+08 4.079310e+08 \n",
|
||||
" 8 20080526 20080520 9.438000e+08 4.551210e+08 \n",
|
||||
" 9 20090525 20090519 9.438000e+08 9.438000e+08 \n",
|
||||
" 10 20090630 20090807 9.438000e+08 9.438000e+08 \n",
|
||||
" 11 20100630 20100812 9.438000e+08 9.438000e+08 \n",
|
||||
" 12 20101231 20110321 9.438000e+08 9.438000e+08 \n",
|
||||
" 13 20110630 20110831 9.438000e+08 9.438000e+08 \n",
|
||||
" 14 20110704 20110627 1.038180e+09 1.038180e+09 \n",
|
||||
" 15 20111231 20120411 1.038180e+09 1.038180e+09 \n",
|
||||
" 16 20121231 20130329 1.038180e+09 1.038180e+09 \n",
|
||||
" 17 20130630 20130831 1.038180e+09 1.038180e+09 \n",
|
||||
" 18 20130930 20131016 1.038180e+09 1.038180e+09 \n",
|
||||
" 19 20140626 20140618 1.141998e+09 1.141998e+09 \n",
|
||||
" 20 20140630 20140829 1.141998e+09 1.141998e+09 \n",
|
||||
" 21 20150331 20150421 1.141998e+09 1.141998e+09 \n",
|
||||
" 22 20150630 20150828 1.141998e+09 1.141998e+09 \n",
|
||||
" 23 20150720 20150710 1.256198e+09 1.256198e+09 \n",
|
||||
" 24 20150930 20151023 1.256198e+09 1.256198e+09 \n",
|
||||
" 25 20151231 20160324 1.256198e+09 1.256198e+09 \n",
|
||||
" 26 20160630 20160827 1.256198e+09 1.256198e+09 \n",
|
||||
" 27 20160930 20161029 1.256198e+09 1.256198e+09 \n",
|
||||
" 28 20170331 20170425 1.256198e+09 1.256198e+09 \n",
|
||||
" 29 20170630 20170728 1.256198e+09 1.256198e+09 \n",
|
||||
" 30 20191231 20200422 1.256198e+09 1.256198e+09 \n",
|
||||
" 31 20200331 20200428 1.256198e+09 1.256198e+09 \n",
|
||||
" 32 20201230 20201231 1.256198e+09 1.256198e+09 \n",
|
||||
" 33 20230210 20230211 1.256198e+09 1.256198e+09 \n",
|
||||
" 34 20230331 20230426 1.256198e+09 1.256198e+09 \n",
|
||||
" 35 20230626 20230628 1.256198e+09 1.256198e+09 \n",
|
||||
" 36 20230630 20230803 1.256198e+09 1.256198e+09 \n",
|
||||
" \n",
|
||||
" restrict_circulating_capital freeFloatCapital \n",
|
||||
" 0 0.0 0.0 \n",
|
||||
" 1 0.0 0.0 \n",
|
||||
" 2 0.0 0.0 \n",
|
||||
" 3 0.0 0.0 \n",
|
||||
" 4 0.0 0.0 \n",
|
||||
" 5 0.0 0.0 \n",
|
||||
" 6 0.0 0.0 \n",
|
||||
" 7 0.0 0.0 \n",
|
||||
" 8 0.0 0.0 \n",
|
||||
" 9 0.0 0.0 \n",
|
||||
" 10 0.0 330036900.0 \n",
|
||||
" 11 0.0 328861200.0 \n",
|
||||
" 12 0.0 332114800.0 \n",
|
||||
" 13 0.0 331784800.0 \n",
|
||||
" 14 0.0 364963280.0 \n",
|
||||
" 15 0.0 366660300.0 \n",
|
||||
" 16 0.0 396490000.0 \n",
|
||||
" 17 0.0 366224100.0 \n",
|
||||
" 18 0.0 364309100.0 \n",
|
||||
" 19 0.0 434023700.0 \n",
|
||||
" 20 0.0 434023000.0 \n",
|
||||
" 21 0.0 404739300.0 \n",
|
||||
" 22 0.0 434023000.0 \n",
|
||||
" 23 0.0 477425300.0 \n",
|
||||
" 24 0.0 477425800.0 \n",
|
||||
" 25 0.0 477425845.0 \n",
|
||||
" 26 0.0 449613757.0 \n",
|
||||
" 27 0.0 477425845.0 \n",
|
||||
" 28 0.0 449613757.0 \n",
|
||||
" 29 0.0 477425845.0 \n",
|
||||
" 30 0.0 527665845.0 \n",
|
||||
" 31 0.0 499853757.0 \n",
|
||||
" 32 0.0 550093757.0 \n",
|
||||
" 33 0.0 549945427.0 \n",
|
||||
" 34 0.0 549253243.0 \n",
|
||||
" 35 0.0 549140936.0 \n",
|
||||
" 36 0.0 549136536.0 ,\n",
|
||||
" 'HolderNum': declareDate endDate shareholder shareholderA shareholderB \\\n",
|
||||
" 0 20030331 20030331 36706.0 36706.0 0.0 \n",
|
||||
" 1 20030630 20030630 38846.0 38846.0 0.0 \n",
|
||||
" 2 20030930 20030930 37305.0 37305.0 0.0 \n",
|
||||
" 3 20040326 20031231 32349.0 32349.0 0.0 \n",
|
||||
" 4 20040429 20040331 21736.0 21736.0 0.0 \n",
|
||||
" .. ... ... ... ... ... \n",
|
||||
" 78 20230331 20221231 167516.0 167516.0 0.0 \n",
|
||||
" 79 20230331 20230228 159541.0 159541.0 0.0 \n",
|
||||
" 80 20230426 20230331 156190.0 156190.0 0.0 \n",
|
||||
" 81 20230803 20230630 161750.0 161750.0 0.0 \n",
|
||||
" 82 20231021 20230930 150025.0 150025.0 0.0 \n",
|
||||
" \n",
|
||||
" shareholderH shareholderFloat shareholderOther \n",
|
||||
" 0 0.0 NaN NaN \n",
|
||||
" 1 0.0 38838.0 8.0 \n",
|
||||
" 2 0.0 NaN NaN \n",
|
||||
" 3 0.0 NaN NaN \n",
|
||||
" 4 0.0 NaN NaN \n",
|
||||
" .. ... ... ... \n",
|
||||
" 78 0.0 167516.0 0.0 \n",
|
||||
" 79 0.0 0.0 0.0 \n",
|
||||
" 80 0.0 0.0 0.0 \n",
|
||||
" 81 0.0 0.0 0.0 \n",
|
||||
" 82 0.0 0.0 0.0 \n",
|
||||
" \n",
|
||||
" [83 rows x 8 columns],\n",
|
||||
" 'Top10Holder': declareDate endDate name type quantity reason ratio nature \\\n",
|
||||
" 0 20010726 20010827 0.0 0.0 161706052.0 0.0 64.680 0.0 \n",
|
||||
" 1 20010726 20010827 0.0 0.0 338000.0 0.0 0.135 0.0 \n",
|
||||
" 2 20010726 20010827 0.0 0.0 10000000.0 0.0 4.000 0.0 \n",
|
||||
" 3 20010726 20010827 0.0 0.0 1500000.0 0.0 0.600 0.0 \n",
|
||||
" 4 20010726 20010827 0.0 0.0 1443804.0 0.0 0.580 0.0 \n",
|
||||
" .. ... ... ... ... ... ... ... ... \n",
|
||||
" 589 20230331 20221231 0.0 0.0 5379160.0 0.0 0.430 0.0 \n",
|
||||
" 590 20230426 20230331 0.0 0.0 679099269.0 0.0 54.060 0.0 \n",
|
||||
" 591 20230628 20230626 0.0 0.0 679211576.0 0.0 54.070 0.0 \n",
|
||||
" 592 20230803 20230630 0.0 0.0 679211576.0 0.0 54.070 0.0 \n",
|
||||
" 593 20231021 20230930 0.0 0.0 679211576.0 0.0 54.070 0.0 \n",
|
||||
" \n",
|
||||
" rank \n",
|
||||
" 0 1.0 \n",
|
||||
" 1 10.0 \n",
|
||||
" 2 2.0 \n",
|
||||
" 3 3.0 \n",
|
||||
" 4 4.0 \n",
|
||||
" .. ... \n",
|
||||
" 589 10.0 \n",
|
||||
" 590 1.0 \n",
|
||||
" 591 1.0 \n",
|
||||
" 592 1.0 \n",
|
||||
" 593 1.0 \n",
|
||||
" \n",
|
||||
" [594 rows x 9 columns],\n",
|
||||
" 'Top10FlowHolder': declareDate endDate name type quantity reason ratio nature \\\n",
|
||||
" 0 20040326 20031231 0.0 0.0 1280917.0 0.0 0.4230 0.0 \n",
|
||||
" 1 20040326 20031231 0.0 0.0 1189829.0 0.0 0.3930 0.0 \n",
|
||||
" 2 20040326 20031231 0.0 0.0 1000000.0 0.0 0.3310 0.0 \n",
|
||||
" 3 20040326 20031231 0.0 0.0 3342834.0 0.0 1.1050 0.0 \n",
|
||||
" 4 20040326 20031231 0.0 0.0 907407.0 0.0 0.3000 0.0 \n",
|
||||
" .. ... ... ... ... ... ... ... ... \n",
|
||||
" 668 20230331 20221231 0.0 0.0 5445803.0 0.0 0.4335 0.0 \n",
|
||||
" 669 20230331 20221231 0.0 0.0 5379160.0 0.0 0.4282 0.0 \n",
|
||||
" 670 20230426 20230331 0.0 0.0 679099269.0 0.0 54.0600 0.0 \n",
|
||||
" 671 20230803 20230630 0.0 0.0 679211576.0 0.0 54.0700 0.0 \n",
|
||||
" 672 20231021 20230930 0.0 0.0 679211576.0 0.0 54.0700 0.0 \n",
|
||||
" \n",
|
||||
" rank \n",
|
||||
" 0 5.0 \n",
|
||||
" 1 6.0 \n",
|
||||
" 2 8.0 \n",
|
||||
" 3 1.0 \n",
|
||||
" 4 9.0 \n",
|
||||
" .. ... \n",
|
||||
" 668 9.0 \n",
|
||||
" 669 10.0 \n",
|
||||
" 670 1.0 \n",
|
||||
" 671 1.0 \n",
|
||||
" 672 1.0 \n",
|
||||
" \n",
|
||||
" [673 rows x 9 columns],\n",
|
||||
" 'PershareIndex': m_timetag m_anntime s_fa_ocfps s_fa_bps s_fa_eps_basic \\\n",
|
||||
" 0 20070331 20070428 0.4032 6.1700 0.57 \n",
|
||||
" 1 20070630 20070817 0.7267 24.0100 0.90 \n",
|
||||
" 2 20070930 20071023 1.6405 7.2800 1.69 \n",
|
||||
" 3 20071231 20090325 1.8471 8.7200 3.00 \n",
|
||||
" 4 20080331 20080422 1.0518 9.6500 0.93 \n",
|
||||
" .. ... ... ... ... ... \n",
|
||||
" 68 20220930 20221017 7.4871 164.5511 35.34 \n",
|
||||
" 69 20221231 20230331 29.2140 157.2258 49.93 \n",
|
||||
" 70 20230331 20230426 4.1751 173.7590 16.55 \n",
|
||||
" 71 20230630 20230803 24.1898 159.9399 28.64 \n",
|
||||
" 72 20230930 20231021 39.8042 173.3872 42.09 \n",
|
||||
" \n",
|
||||
" s_fa_eps_diluted s_fa_undistributedps s_fa_surpluscapitalps \\\n",
|
||||
" 0 NaN 2.3815 1.4566 \n",
|
||||
" 1 0.90 2.7022 1.4567 \n",
|
||||
" 2 1.69 3.4870 1.4568 \n",
|
||||
" 3 3.00 5.3793 1.4568 \n",
|
||||
" 4 NaN 6.3047 1.4569 \n",
|
||||
" .. ... ... ... \n",
|
||||
" 68 35.34 136.9667 1.0945 \n",
|
||||
" 69 49.93 128.4049 1.0945 \n",
|
||||
" 70 16.55 144.9397 1.0945 \n",
|
||||
" 71 28.64 129.9407 1.0945 \n",
|
||||
" 72 42.09 143.3907 1.0945 \n",
|
||||
" \n",
|
||||
" adjusted_earnings_per_share du_return_on_equity ... equity_roe \\\n",
|
||||
" 0 NaN 9.6551 ... NaN \n",
|
||||
" 1 0.899 14.8845 ... 14.88 \n",
|
||||
" 2 1.680 26.1630 ... NaN \n",
|
||||
" 3 3.000 39.5989 ... 39.30 \n",
|
||||
" 4 NaN 10.0724 ... NaN \n",
|
||||
" .. ... ... ... ... \n",
|
||||
" 68 NaN 22.4101 ... 21.91 \n",
|
||||
" 69 49.990 32.4077 ... 30.26 \n",
|
||||
" 70 NaN 10.0028 ... 10.00 \n",
|
||||
" 71 28.620 18.0614 ... 16.70 \n",
|
||||
" 72 NaN 25.4632 ... 24.82 \n",
|
||||
" \n",
|
||||
" net_roe total_roe gross_profit net_profit actual_tax_rate \\\n",
|
||||
" 0 9.2101 NaN 85.0268 35.3655 NaN \n",
|
||||
" 1 13.8530 NaN 85.1958 34.0022 NaN \n",
|
||||
" 2 23.1357 NaN 85.1373 37.4401 NaN \n",
|
||||
" 3 34.3793 NaN 87.9565 40.9821 NaN \n",
|
||||
" 4 9.5894 NaN 89.9267 46.0020 NaN \n",
|
||||
" .. ... ... ... ... ... \n",
|
||||
" 68 21.4794 NaN 91.8744 53.1366 NaN \n",
|
||||
" 69 31.7541 NaN 91.8667 52.6795 NaN \n",
|
||||
" 70 9.5269 NaN 92.5956 55.5393 NaN \n",
|
||||
" 71 17.9082 NaN 91.7981 53.6564 NaN \n",
|
||||
" 72 24.2765 NaN 91.7075 53.0919 NaN \n",
|
||||
" \n",
|
||||
" pre_pay_operate_income sales_cash_flow gear_ratio inventory_turnover \n",
|
||||
" 0 1.4417 1.2356 40.4210 0.1192 \n",
|
||||
" 1 0.9290 1.2867 39.1859 0.1898 \n",
|
||||
" 2 0.4992 1.1884 31.7955 0.3247 \n",
|
||||
" 3 0.1555 1.0277 20.1557 0.4068 \n",
|
||||
" 4 0.6517 1.2842 19.6501 0.0856 \n",
|
||||
" .. ... ... ... ... \n",
|
||||
" 68 NaN 1.1017 13.8484 0.2066 \n",
|
||||
" 69 NaN 1.1337 19.4210 0.2795 \n",
|
||||
" 70 NaN 0.9228 12.3562 0.0728 \n",
|
||||
" 71 NaN 0.9928 13.3925 0.1432 \n",
|
||||
" 72 NaN 1.0773 14.1400 0.2146 \n",
|
||||
" \n",
|
||||
" [73 rows x 28 columns]}}"
|
||||
]
|
||||
},
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 财务数据\n",
|
||||
"download_financial_data([\"600519.SH\"])\n",
|
||||
"data3 = get_financial_data([\"600519.SH\"])\n",
|
||||
"data3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5259491f-6e9c-41f5-b599-fd4ea5968fa7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
199
5.课程代码/2.Option_spread_strategy/使用文档/16/16_demo.ipynb
Normal file
199
5.课程代码/2.Option_spread_strategy/使用文档/16/16_demo.ipynb
Normal file
@@ -0,0 +1,199 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 配置迅投研数据服务\n",
|
||||
"from vnpy.trader.setting import SETTINGS\n",
|
||||
"\n",
|
||||
"SETTINGS[\"datafeed.name\"] = \"xt\"\n",
|
||||
"SETTINGS[\"datafeed.username\"] = \"token\"\n",
|
||||
"SETTINGS[\"datafeed.password\"] = \"4aff6f3b0dcfc990ec9476213ba784e17c34e757\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 加载功能模块\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"from vnpy.trader.datafeed import get_datafeed\n",
|
||||
"from vnpy.trader.object import HistoryRequest, Exchange, Interval\n",
|
||||
"\n",
|
||||
"from vnpy_sqlite import Database as SqliteDatabase\n",
|
||||
"from elite_database import Database as EliteDatabase"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 初始化数据服务\n",
|
||||
"datafeed = get_datafeed()\n",
|
||||
"datafeed.init()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"数据长度 51143\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 查询期权历史数据\n",
|
||||
"req = HistoryRequest(\n",
|
||||
" symbol=\"m2205-C-3000\",\n",
|
||||
" exchange=Exchange.DCE,#SZSE\n",
|
||||
" start=datetime(2017, 1, 1),\n",
|
||||
" end=datetime.now(),\n",
|
||||
" interval=Interval.MINUTE\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"bars = datafeed.query_bar_history(req)\n",
|
||||
"print(\"数据长度\", len(bars))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "IndexError",
|
||||
"evalue": "list index out of range",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[1;32mIn[9], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# 查看K线数据内容\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[43mbars\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\n",
|
||||
"\u001b[1;31mIndexError\u001b[0m: list index out of range"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 查看K线数据内容\n",
|
||||
"bars[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 创建SQLite数据库实例并写入数据\n",
|
||||
"db1 = SqliteDatabase()\n",
|
||||
"db1.save_bar_data(bars)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 测试SQLite数据查询性能\n",
|
||||
"%timeit bars = db1.load_bar_data(req.symbol, req.exchange, req.interval, req.start, req.end)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 重新查询一次数据\n",
|
||||
"bars = datafeed.query_bar_history(req)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 创建Elite数据库实例并写入数据\n",
|
||||
"db2 = EliteDatabase()\n",
|
||||
"db2.save_bar_data(bars)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 测试Elite数据查询性能\n",
|
||||
"%timeit bars = db2.load_bar_data(req.symbol, req.exchange, req.interval, req.start, req.end)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"153/6.25"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
},
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "1b43cb0bd93d5abbadd54afed8252f711d4681fe6223ad6b67ffaee289648f85"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
1337
5.课程代码/2.Option_spread_strategy/使用文档/17/17_demo.ipynb
Normal file
1337
5.课程代码/2.Option_spread_strategy/使用文档/17/17_demo.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
190
5.课程代码/2.Option_spread_strategy/使用文档/18/update_data.py
Normal file
190
5.课程代码/2.Option_spread_strategy/使用文档/18/update_data.py
Normal file
@@ -0,0 +1,190 @@
|
||||
from multiprocessing import Process
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.trader.database import BarOverview
|
||||
from vnpy.trader.datafeed import get_datafeed
|
||||
from vnpy.trader.object import ContractData, BarData, HistoryRequest
|
||||
from vnpy.trader.constant import Exchange, Product, OptionType, Interval
|
||||
from vnpy.trader.setting import SETTINGS
|
||||
|
||||
from elite_database import EliteDatabase
|
||||
|
||||
|
||||
# 配置迅投研数据服务
|
||||
SETTINGS["datafeed.name"] = "xt"
|
||||
SETTINGS["datafeed.username"] = "token"
|
||||
SETTINGS["datafeed.password"] = "4aff6f3b0dcfc990ec9476213ba784e17c34e757"
|
||||
|
||||
|
||||
# 交易所映射关系
|
||||
EXCHANGE_XT2VT = {
|
||||
"SH": Exchange.SSE,
|
||||
"SZ": Exchange.SZSE,
|
||||
"BJ": Exchange.BSE,
|
||||
"SF": Exchange.SHFE,
|
||||
"IF": Exchange.CFFEX,
|
||||
"INE": Exchange.INE,
|
||||
"DF": Exchange.DCE,
|
||||
"ZF": Exchange.CZCE,
|
||||
"GF": Exchange.GFEX
|
||||
}
|
||||
|
||||
|
||||
def update_history_data() -> None:
|
||||
"""更新历史合约信息"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import download_history_data
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 下载历史合约信息
|
||||
download_history_data("", "historycontract")
|
||||
|
||||
print("xtquant历史合约信息下载完成")
|
||||
|
||||
|
||||
def update_contract_data(sector_name: str) -> None:
|
||||
"""更新合约数据"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import (
|
||||
get_stock_list_in_sector,
|
||||
get_instrument_detail
|
||||
)
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 查询中金所历史合约代码
|
||||
vt_symbols: list[str] = get_stock_list_in_sector(sector_name)
|
||||
|
||||
# 遍历列表查询合约信息
|
||||
contracts: list[ContractData] = []
|
||||
|
||||
for xt_symbol in vt_symbols:
|
||||
# 拆分XT代码
|
||||
symbol, xt_exchange = xt_symbol.split(".")
|
||||
|
||||
# 筛选期权合约合约
|
||||
if "-" in symbol:
|
||||
data: dict = get_instrument_detail(xt_symbol, True)
|
||||
|
||||
type_str = data["InstrumentID"].split("-")[1]
|
||||
if type_str == "C":
|
||||
option_type = OptionType.CALL
|
||||
elif type_str == "P":
|
||||
option_type = OptionType.PUT
|
||||
|
||||
contract: ContractData = ContractData(
|
||||
symbol=data["InstrumentID"],
|
||||
exchange=EXCHANGE_XT2VT[xt_exchange.replace("O", "")],
|
||||
name=data["InstrumentName"],
|
||||
product=Product.OPTION,
|
||||
size=data["VolumeMultiple"],
|
||||
pricetick=data["PriceTick"],
|
||||
min_volume=data["MinLimitOrderVolume"],
|
||||
option_strike=data["ExtendInfo"]["OptExercisePrice"],
|
||||
option_listed=datetime.strptime(data["OpenDate"], "%Y%m%d"),
|
||||
option_expiry=datetime.strptime(data["ExpireDate"], "%Y%m%d"),
|
||||
option_portfolio=data["ProductID"],
|
||||
option_index=str(data["ExtendInfo"]["OptExercisePrice"]),
|
||||
option_type=option_type,
|
||||
gateway_name="XT"
|
||||
)
|
||||
contracts.append(contract)
|
||||
|
||||
# 保存合约信息到数据库
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
database.save_contract_data(contracts)
|
||||
|
||||
print("合约信息更新成功", len(contracts))
|
||||
|
||||
|
||||
def update_bar_data() -> None:
|
||||
"""更新K线数据"""
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 获取当前时间戳
|
||||
now: datetime = datetime.now()
|
||||
|
||||
# 获取合约信息
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
contracts: list[ContractData] = database.load_contract_data()
|
||||
|
||||
# 获取数据汇总
|
||||
data: list[BarOverview] = database.get_bar_overview()
|
||||
|
||||
overviews: dict[str, BarOverview] = {}
|
||||
for o in data:
|
||||
# 只保留分钟线数据
|
||||
if o.interval != Interval.MINUTE:
|
||||
continue
|
||||
|
||||
vt_symbol: str = f"{o.symbol}.{o.exchange.value}"
|
||||
overviews[vt_symbol] = o
|
||||
|
||||
# 遍历所有合约信息
|
||||
for contract in contracts:
|
||||
# 如果没有到期时间,则跳过
|
||||
if not contract.option_expiry:
|
||||
continue
|
||||
|
||||
# 查询数据汇总
|
||||
overview: BarOverview = overviews.get(contract.vt_symbol, None)
|
||||
|
||||
# 如果已经到期,则跳过
|
||||
if overview and contract.option_expiry < now:
|
||||
continue
|
||||
|
||||
# 初始化查询开始的时间中金所期权最早在2019-12-13,商品期权最早为豆粕期权2017年3月31日
|
||||
start: datetime = datetime(2017, 3, 1)
|
||||
|
||||
# 实现增量查询
|
||||
if overview:
|
||||
start = overview.end
|
||||
|
||||
# 执行数据查询和更新入库
|
||||
req: HistoryRequest = HistoryRequest(
|
||||
symbol=contract.symbol,
|
||||
exchange=contract.exchange,
|
||||
start=start,
|
||||
end=datetime.now(),
|
||||
interval=Interval.MINUTE
|
||||
)
|
||||
|
||||
bars: list[BarData] = datafeed.query_bar_history(req)
|
||||
|
||||
if bars:
|
||||
database.save_bar_data(bars)
|
||||
|
||||
start_dt: datetime = bars[0].datetime
|
||||
end_dt: datetime = bars[-1].datetime
|
||||
msg: str = f"{contract.vt_symbol}数据更新成功,{start_dt} - {end_dt}"
|
||||
print(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 使用子进程更新历史合约信息
|
||||
process: Process = Process(target=update_history_data)
|
||||
process.start()
|
||||
process.join() # 等待子进程执行完成
|
||||
|
||||
# 更新合约信息
|
||||
update_contract_data("中金所")
|
||||
update_contract_data("过期中金所")
|
||||
|
||||
# 更新历史数据
|
||||
update_bar_data()
|
||||
|
||||
|
||||
# "IF":"过期中金所",
|
||||
# "SF":"过期上期所",不在此更新第26课
|
||||
# "DF":"过期大商所",不在此更新第26课
|
||||
# "ZF":"过期郑商所",未完成,不在此更新第26课
|
||||
# "INE":"过期能源中心",
|
||||
# "SHO":"过期上证期权",未完成,不在此更新第26课
|
||||
# "SZO":"过期深证期权",未完成,不在此更新第26课
|
||||
176
5.课程代码/2.Option_spread_strategy/使用文档/19/19_demo.ipynb
Normal file
176
5.课程代码/2.Option_spread_strategy/使用文档/19/19_demo.ipynb
Normal file
@@ -0,0 +1,176 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 加载功能模块\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"from vnpy.trader.constant import Interval\n",
|
||||
"\n",
|
||||
"from elite_optionstrategy import BacktestingEngine\n",
|
||||
"\n",
|
||||
"from buy_option_strategy import BuyOptionStrategy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 创建回测引擎\n",
|
||||
"engine = BacktestingEngine()\n",
|
||||
"\n",
|
||||
"engine.set_parameters(\n",
|
||||
" interval=Interval.MINUTE,\n",
|
||||
" start=datetime(2023, 1, 1),\n",
|
||||
" end=datetime(2023, 6, 30),\n",
|
||||
" rate=0,\n",
|
||||
" slippage=0.6 + (16 / 100),\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"engine.add_strategy(BuyOptionStrategy, {})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" 1%| | 2/180 [00:00<00:16, 10.53it/s]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2024-03-09 09:42:27.361177\t触发异常,回测终止\n",
|
||||
"2024-03-09 09:42:27.362176\tTraceback (most recent call last):\n",
|
||||
" File \"C:\\veighna_elite_simulation\\lib\\site-packages\\elite_optionstrategy\\backtesting.py\", line 114, in run_backtesting\n",
|
||||
" File \"C:\\veighna_elite_simulation\\lib\\site-packages\\elite_optionstrategy\\backtesting.py\", line 397, in _run_intraday\n",
|
||||
" File \"C:\\veighna_elite_simulation\\lib\\site-packages\\elite_optionstrategy\\backtesting.py\", line 442, in _new_bars\n",
|
||||
" File \"D:\\Gitee_Code\\trading_strategy\\VNPY_Code\\Option_spread_strategy\\使用文档\\19\\buy_option_strategy.py\", line 66, in on_bars\n",
|
||||
" portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)\n",
|
||||
" File \"C:\\veighna_elite_simulation\\lib\\site-packages\\elite_optionstrategy\\template.py\", line 247, in get_portfolio\n",
|
||||
"KeyError: 'IO'\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 历史数据回放\n",
|
||||
"engine.run_backtesting()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2024-03-09 09:28:32.115670\t开始计算逐日盯市盈亏\n",
|
||||
"2024-03-09 09:28:32.115670\t逐日盯市盈亏计算完成\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 计算每日盈亏\n",
|
||||
"engine.calculate_result()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计绩效结果\n",
|
||||
"result = engine.calculate_statistics()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 显示资金图表\n",
|
||||
"engine.show_chart()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 打印逐笔成交\n",
|
||||
"for trade in engine.all_trades.values():\n",
|
||||
" print(trade.datetime, trade.vt_symbol, trade.direction.value, trade.offset.value, trade.volume, \"@\", trade.price)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for result in engine.daily_results.values():\n",
|
||||
" print(result.today_close_data[\"IO2201-C-4900.CFFEX\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
},
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "1b43cb0bd93d5abbadd54afed8252f711d4681fe6223ad6b67ffaee289648f85"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
152
5.课程代码/2.Option_spread_strategy/使用文档/19/buy_option_strategy.py
Normal file
152
5.课程代码/2.Option_spread_strategy/使用文档/19/buy_option_strategy.py
Normal file
@@ -0,0 +1,152 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class BuyOptionStrategy(StrategyTemplate):
|
||||
"""基于均线信号买入期权的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(20) # 快速均线周期
|
||||
slow_window: int = Parameter(120) # 慢速均线周期
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars = self.load_bars(self.underlying_symbol, 10, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多平值call
|
||||
atm_call = front_chain.get_option_by_level(cp=1, level=0)
|
||||
self.set_target(atm_call.vt_symbol, self.fixed_size)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多平值put
|
||||
atm_put = front_chain.get_option_by_level(cp=-1, level=0)
|
||||
self.set_target(atm_put.vt_symbol, self.fixed_size)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
139
5.课程代码/2.Option_spread_strategy/使用文档/19/download_data.ipynb
Normal file
139
5.课程代码/2.Option_spread_strategy/使用文档/19/download_data.ipynb
Normal file
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 配置迅投研数据服务\n",
|
||||
"from vnpy.trader.setting import SETTINGS\n",
|
||||
"\n",
|
||||
"SETTINGS[\"datafeed.name\"] = \"xt\"\n",
|
||||
"SETTINGS[\"datafeed.username\"] = \"token\"\n",
|
||||
"SETTINGS[\"datafeed.password\"] = \"4aff6f3b0dcfc990ec9476213ba784e17c34e757\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 加载功能模块\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"from vnpy.trader.datafeed import get_datafeed\n",
|
||||
"from vnpy.trader.object import HistoryRequest, Exchange, Interval\n",
|
||||
"\n",
|
||||
"from vnpy_sqlite import Database as SqliteDatabase\n",
|
||||
"from elite_database import Database as EliteDatabase"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 初始化数据服务\n",
|
||||
"datafeed = get_datafeed()\n",
|
||||
"datafeed.init()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"数据长度 174959\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 查询期权历史数据\n",
|
||||
"req = HistoryRequest(\n",
|
||||
" symbol=\"IFJQ00\", # 加权指数 \n",
|
||||
" # symbol=\"IF00\", # 主力连续(未平滑)\n",
|
||||
" exchange=Exchange.CFFEX,\n",
|
||||
" start=datetime(2015, 1, 1),\n",
|
||||
" end=datetime.now(),\n",
|
||||
" interval=Interval.MINUTE\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"bars = datafeed.query_bar_history(req)\n",
|
||||
"print(\"数据长度\", len(bars))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 创建Elite数据库实例并写入数据\n",
|
||||
"db2 = EliteDatabase()\n",
|
||||
"db2.save_bar_data(bars)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
},
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "1b43cb0bd93d5abbadd54afed8252f711d4681fe6223ad6b67ffaee289648f85"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
184
5.课程代码/2.Option_spread_strategy/使用文档/19/update_data.py
Normal file
184
5.课程代码/2.Option_spread_strategy/使用文档/19/update_data.py
Normal file
@@ -0,0 +1,184 @@
|
||||
from multiprocessing import Process
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.trader.database import BarOverview
|
||||
from vnpy.trader.datafeed import get_datafeed
|
||||
from vnpy.trader.object import ContractData, BarData, HistoryRequest
|
||||
from vnpy.trader.constant import Exchange, Product, OptionType, Interval
|
||||
from vnpy.trader.setting import SETTINGS
|
||||
|
||||
from elite_database import EliteDatabase
|
||||
|
||||
|
||||
# 配置迅投研数据服务
|
||||
SETTINGS["datafeed.name"] = "xt"
|
||||
SETTINGS["datafeed.username"] = "token"
|
||||
SETTINGS["datafeed.password"] = "4aff6f3b0dcfc990ec9476213ba784e17c34e757"
|
||||
|
||||
|
||||
# 交易所映射关系
|
||||
EXCHANGE_XT2VT = {
|
||||
"SH": Exchange.SSE,
|
||||
"SZ": Exchange.SZSE,
|
||||
"BJ": Exchange.BSE,
|
||||
"SF": Exchange.SHFE,
|
||||
"IF": Exchange.CFFEX,
|
||||
"INE": Exchange.INE,
|
||||
"DF": Exchange.DCE,
|
||||
"ZF": Exchange.CZCE,
|
||||
"GF": Exchange.GFEX
|
||||
}
|
||||
|
||||
|
||||
def update_history_data() -> None:
|
||||
"""更新历史合约信息"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import download_history_data
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 下载历史合约信息
|
||||
download_history_data("", "historycontract")
|
||||
|
||||
print("xtquant历史合约信息下载完成")
|
||||
|
||||
|
||||
def update_contract_data(sector_name: str) -> None:
|
||||
"""更新合约数据"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import (
|
||||
get_stock_list_in_sector,
|
||||
get_instrument_detail
|
||||
)
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 查询中金所历史合约代码
|
||||
vt_symbols: list[str] = get_stock_list_in_sector(sector_name)
|
||||
|
||||
# 遍历列表查询合约信息
|
||||
contracts: list[ContractData] = []
|
||||
|
||||
for xt_symbol in vt_symbols:
|
||||
# 拆分XT代码
|
||||
symbol, xt_exchange = xt_symbol.split(".")
|
||||
|
||||
# 筛选期权合约合约
|
||||
if "-" in symbol:
|
||||
data: dict = get_instrument_detail(xt_symbol, True)
|
||||
|
||||
type_str = data["InstrumentID"].split("-")[1]
|
||||
if type_str == "C":
|
||||
option_type = OptionType.CALL
|
||||
elif type_str == "P":
|
||||
option_type = OptionType.PUT
|
||||
|
||||
option_underlying: str = data["InstrumentID"].split("-")[0]
|
||||
|
||||
contract: ContractData = ContractData(
|
||||
symbol=data["InstrumentID"],
|
||||
exchange=EXCHANGE_XT2VT[xt_exchange.replace("O", "")],
|
||||
name=data["InstrumentName"],
|
||||
product=Product.OPTION,
|
||||
size=data["VolumeMultiple"],
|
||||
pricetick=data["PriceTick"],
|
||||
min_volume=data["MinLimitOrderVolume"],
|
||||
option_strike=data["ExtendInfo"]["OptExercisePrice"],
|
||||
option_listed=datetime.strptime(data["OpenDate"], "%Y%m%d"),
|
||||
option_expiry=datetime.strptime(data["ExpireDate"], "%Y%m%d"),
|
||||
option_underlying=option_underlying,
|
||||
option_portfolio=data["ProductID"],
|
||||
option_index=str(data["ExtendInfo"]["OptExercisePrice"]),
|
||||
option_type=option_type,
|
||||
gateway_name="XT"
|
||||
)
|
||||
contracts.append(contract)
|
||||
|
||||
# 保存合约信息到数据库
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
database.save_contract_data(contracts)
|
||||
|
||||
print("合约信息更新成功", len(contracts))
|
||||
|
||||
|
||||
def update_bar_data() -> None:
|
||||
"""更新K线数据"""
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 获取当前时间戳
|
||||
now: datetime = datetime.now()
|
||||
|
||||
# 获取合约信息
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
contracts: list[ContractData] = database.load_contract_data()
|
||||
|
||||
# 获取数据汇总
|
||||
data: list[BarOverview] = database.get_bar_overview()
|
||||
|
||||
overviews: dict[str, BarOverview] = {}
|
||||
for o in data:
|
||||
# 只保留分钟线数据
|
||||
if o.interval != Interval.MINUTE:
|
||||
continue
|
||||
|
||||
vt_symbol: str = f"{o.symbol}.{o.exchange.value}"
|
||||
overviews[vt_symbol] = o
|
||||
|
||||
# 遍历所有合约信息
|
||||
for contract in contracts:
|
||||
# 如果没有到期时间,则跳过
|
||||
if not contract.option_expiry:
|
||||
continue
|
||||
|
||||
# 查询数据汇总
|
||||
overview: BarOverview = overviews.get(contract.vt_symbol, None)
|
||||
|
||||
# 如果已经到期,则跳过
|
||||
if overview and contract.option_expiry < now:
|
||||
continue
|
||||
|
||||
# 初始化查询开始的时间
|
||||
start: datetime = datetime(2018, 1, 1)
|
||||
|
||||
# 实现增量查询
|
||||
if overview:
|
||||
start = overview.end
|
||||
|
||||
# 执行数据查询和更新入库
|
||||
req: HistoryRequest = HistoryRequest(
|
||||
symbol=contract.symbol,
|
||||
exchange=contract.exchange,
|
||||
start=start,
|
||||
end=datetime.now(),
|
||||
interval=Interval.MINUTE
|
||||
)
|
||||
|
||||
bars: list[BarData] = datafeed.query_bar_history(req)
|
||||
|
||||
if bars:
|
||||
database.save_bar_data(bars)
|
||||
|
||||
start_dt: datetime = bars[0].datetime
|
||||
end_dt: datetime = bars[-1].datetime
|
||||
msg: str = f"{contract.vt_symbol}数据更新成功,{start_dt} - {end_dt}"
|
||||
print(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 使用子进程更新历史合约信息
|
||||
process: Process = Process(target=update_history_data)
|
||||
process.start()
|
||||
process.join() # 等待子进程执行完成
|
||||
|
||||
# 更新合约信息
|
||||
update_contract_data("中金所")
|
||||
update_contract_data("过期中金所")
|
||||
|
||||
# 更新历史数据
|
||||
# update_bar_data()
|
||||
318
5.课程代码/2.Option_spread_strategy/使用文档/20/template.py
Normal file
318
5.课程代码/2.Option_spread_strategy/使用文档/20/template.py
Normal file
@@ -0,0 +1,318 @@
|
||||
from abc import ABC
|
||||
from typing import Union, Type, TYPE_CHECKING
|
||||
from collections import defaultdict
|
||||
|
||||
from vnpy.trader.constant import Interval, Direction, Offset
|
||||
from vnpy.trader.object import BarData, TickData, OrderData, TradeData, ContractData
|
||||
from vnpy.trader.utility import virtual
|
||||
|
||||
from .object import PortfolioData
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .engine import StrategyEngine
|
||||
|
||||
|
||||
class StrategyTemplate(ABC):
|
||||
"""期权策略模板"""
|
||||
|
||||
author: str = ""
|
||||
|
||||
def __init__(self, engine: "StrategyEngine", name: str) -> None:
|
||||
"""构造函数"""
|
||||
self.engine: "StrategyEngine" = engine
|
||||
self.name: str = name
|
||||
|
||||
self.vt_symbols: set[str] = set()
|
||||
self.inited: bool = False
|
||||
self.trading: bool = False
|
||||
|
||||
# 初始化变量和参数列表
|
||||
if not hasattr(self, "parameters"):
|
||||
self.parameters: list[str] = []
|
||||
|
||||
if not hasattr(self, "variables"):
|
||||
self.variables: list[str] = []
|
||||
|
||||
self.variables = ["inited", "trading", "pos_data", "target_data"] + self.variables
|
||||
|
||||
# 委托缓存数据
|
||||
self.orders: dict[str, OrderData] = {}
|
||||
self.active_orderids: set[str] = set()
|
||||
|
||||
# 持仓和目标数据
|
||||
self.pos_data: dict[str, int] = defaultdict(int) # 实际持仓
|
||||
self.target_data: dict[str, int] = defaultdict(int) # 目标持仓
|
||||
|
||||
# 期权组合
|
||||
self.portfolios: dict[str, PortfolioData] = {}
|
||||
|
||||
def update_setting(self, setting: dict) -> None:
|
||||
"""更新策略参数"""
|
||||
for name in self.parameters:
|
||||
if name in setting:
|
||||
setattr(self, name, setting[name])
|
||||
|
||||
def get_parameters(self) -> dict:
|
||||
"""查询策略参数"""
|
||||
strategy_parameters: dict = {}
|
||||
for name in self.parameters:
|
||||
strategy_parameters[name] = getattr(self, name)
|
||||
return strategy_parameters
|
||||
|
||||
def get_variables(self) -> dict:
|
||||
"""查询策略变量"""
|
||||
strategy_variables: dict = {}
|
||||
for name in self.variables:
|
||||
strategy_variables[name] = getattr(self, name)
|
||||
return strategy_variables
|
||||
|
||||
def get_data(self) -> dict:
|
||||
"""查询策略状态数据"""
|
||||
strategy_data: dict = {
|
||||
"strategy_name": self.name,
|
||||
"vt_symbols": self.vt_symbols,
|
||||
"class_name": self.__class__.__name__,
|
||||
"author": self.author,
|
||||
"parameters": self.get_parameters(),
|
||||
"variables": self.get_variables(),
|
||||
}
|
||||
return strategy_data
|
||||
|
||||
@virtual
|
||||
def on_init(self) -> None:
|
||||
"""策略初始化"""
|
||||
pass
|
||||
|
||||
@virtual
|
||||
def on_start(self) -> None:
|
||||
"""策略启动"""
|
||||
pass
|
||||
|
||||
@virtual
|
||||
def on_stop(self) -> None:
|
||||
"""策略停止"""
|
||||
pass
|
||||
|
||||
@virtual
|
||||
def on_tick(self, tick: TickData) -> None:
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
@virtual
|
||||
def on_bars(self, bars: dict[str, BarData]) -> None:
|
||||
"""K线推送"""
|
||||
pass
|
||||
|
||||
def update_trade(self, trade: TradeData) -> None:
|
||||
"""更新成交数据"""
|
||||
if trade.direction == Direction.LONG:
|
||||
self.pos_data[trade.vt_symbol] += trade.volume
|
||||
else:
|
||||
self.pos_data[trade.vt_symbol] -= trade.volume
|
||||
|
||||
def update_order(self, order: OrderData) -> None:
|
||||
"""更新委托数据"""
|
||||
self.orders[order.vt_orderid] = order
|
||||
|
||||
if not order.is_active() and order.vt_orderid in self.active_orderids:
|
||||
self.active_orderids.remove(order.vt_orderid)
|
||||
|
||||
def buy(self, vt_symbol: str, price: float, volume: float) -> list[str]:
|
||||
"""买入开仓"""
|
||||
return self.send_order(vt_symbol, Direction.LONG, Offset.OPEN, price, volume)
|
||||
|
||||
def sell(self, vt_symbol: str, price: float, volume: float) -> list[str]:
|
||||
"""卖出平仓"""
|
||||
return self.send_order(vt_symbol, Direction.SHORT, Offset.CLOSE, price, volume)
|
||||
|
||||
def short(self, vt_symbol: str, price: float, volume: float) -> list[str]:
|
||||
"""卖出开仓"""
|
||||
return self.send_order(vt_symbol, Direction.SHORT, Offset.OPEN, price, volume)
|
||||
|
||||
def cover(self, vt_symbol: str, price: float, volume: float) -> list[str]:
|
||||
"""买入平仓"""
|
||||
return self.send_order(vt_symbol, Direction.LONG, Offset.CLOSE, price, volume)
|
||||
|
||||
def send_order(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
direction: Direction,
|
||||
offset: Offset,
|
||||
price: float,
|
||||
volume: float,
|
||||
) -> list[str]:
|
||||
"""委托下单"""
|
||||
if not self.trading:
|
||||
return []
|
||||
|
||||
vt_orderids = self.engine.send_order(
|
||||
self,
|
||||
vt_symbol,
|
||||
direction,
|
||||
offset,
|
||||
price,
|
||||
volume
|
||||
)
|
||||
self.active_orderids.update(vt_orderids)
|
||||
return vt_orderids
|
||||
|
||||
def cancel_order(self, vt_orderid: str) -> None:
|
||||
"""委托撤单"""
|
||||
if not self.trading:
|
||||
return
|
||||
|
||||
self.engine.cancel_order(self, vt_orderid)
|
||||
|
||||
def cancel_all(self) -> None:
|
||||
"""全撤委托"""
|
||||
for vt_orderid in list(self.active_orderids):
|
||||
self.cancel_order(vt_orderid)
|
||||
|
||||
def get_pos(self, vt_symbol: str) -> int:
|
||||
"""查询当前持仓"""
|
||||
return self.pos_data.get(vt_symbol, 0)
|
||||
|
||||
def get_target(self, vt_symbol: str) -> int:
|
||||
"""查询目标仓位"""
|
||||
return self.target_data[vt_symbol]
|
||||
|
||||
def set_target(self, vt_symbol: str, target: int) -> None:
|
||||
"""设置目标仓位"""
|
||||
self.target_data[vt_symbol] = target
|
||||
|
||||
def clear_targets(self) -> None:
|
||||
"""清空目标仓位"""
|
||||
self.target_data.clear()
|
||||
|
||||
def execute_trading(self, price_data: dict[str, float], percent_add: float) -> None:
|
||||
"""基于目标执行调仓交易"""
|
||||
self.cancel_all()
|
||||
|
||||
# 只发出当前K线切片有行情的合约的委托
|
||||
for vt_symbol, price in price_data.items():
|
||||
# 计算仓差
|
||||
target: int = self.get_target(vt_symbol)
|
||||
pos: int = self.get_pos(vt_symbol)
|
||||
diff: int = target - pos
|
||||
|
||||
# 多头
|
||||
if diff > 0:
|
||||
# 计算多头委托价
|
||||
order_price: float = price * (1 + percent_add)
|
||||
|
||||
# 计算买平和买开数量
|
||||
cover_volume: int = 0
|
||||
buy_volume: int = 0
|
||||
|
||||
if pos < 0:
|
||||
cover_volume = min(diff, abs(pos))
|
||||
buy_volume = diff - cover_volume
|
||||
else:
|
||||
buy_volume = diff
|
||||
|
||||
# 发出对应委托
|
||||
if cover_volume:
|
||||
self.cover(vt_symbol, order_price, cover_volume)
|
||||
|
||||
if buy_volume:
|
||||
self.buy(vt_symbol, order_price, buy_volume)
|
||||
# 空头
|
||||
elif diff < 0:
|
||||
# 计算空头委托价
|
||||
order_price: float = price * (1 - percent_add)
|
||||
|
||||
# 计算卖平和卖开数量
|
||||
sell_volume: int = 0
|
||||
short_volume: int = 0
|
||||
|
||||
if pos > 0:
|
||||
sell_volume = min(abs(diff), pos)
|
||||
short_volume = abs(diff) - sell_volume
|
||||
else:
|
||||
short_volume = abs(diff)
|
||||
|
||||
# 发出对应委托
|
||||
if sell_volume:
|
||||
self.sell(vt_symbol, order_price, sell_volume)
|
||||
|
||||
if short_volume:
|
||||
self.short(vt_symbol, order_price, short_volume)
|
||||
|
||||
def write_log(self, msg: str) -> None:
|
||||
"""输出日志"""
|
||||
self.engine.write_log(msg, self)
|
||||
|
||||
def get_portfolio(self, portfolio_name: str) -> PortfolioData:
|
||||
"""获取期权组合"""
|
||||
return self.portfolios[portfolio_name]
|
||||
|
||||
def load_bars(self, vt_symbol: str, days: int, interval: Interval) -> list[BarData]:
|
||||
"""加载历史K线数据"""
|
||||
return self.engine.load_bars(vt_symbol, days, interval)
|
||||
|
||||
def init_portfolio(self, portfolio_name: str) -> bool:
|
||||
"""查询期权合约"""
|
||||
# 避免重复订阅
|
||||
if portfolio_name in self.portfolios:
|
||||
return True
|
||||
|
||||
# 向引擎发起查询
|
||||
contracts: list[ContractData] = self.engine.init_portfolio(self, portfolio_name)
|
||||
|
||||
# 如果有返回合约,则创建PortfolioData对象
|
||||
if contracts:
|
||||
portfolio: PortfolioData = PortfolioData(contracts[0])
|
||||
self.portfolios[portfolio_name] = portfolio
|
||||
|
||||
for contract in contracts:
|
||||
self.vt_symbols.add(contract.vt_symbol)
|
||||
portfolio.add_contract(contract)
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def subscribe_options(self, portfolio_name: str) -> bool:
|
||||
"""订阅期权行情"""
|
||||
# 避免重复订阅
|
||||
if portfolio_name in self.portfolios:
|
||||
return True
|
||||
|
||||
# 向引擎发起订阅
|
||||
contracts: list[ContractData] = self.engine.subscribe_options(self, portfolio_name)
|
||||
|
||||
# 如果有返回合约,则创建PortfolioData对象
|
||||
if contracts:
|
||||
portfolio: PortfolioData = PortfolioData(contracts[0])
|
||||
self.portfolios[portfolio_name] = portfolio
|
||||
|
||||
for contract in contracts:
|
||||
self.vt_symbols.add(contract.vt_symbol)
|
||||
portfolio.add_contract(contract)
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def subscribe_data(self, vt_symbol: str) -> bool:
|
||||
"""订阅标的行情"""
|
||||
n: bool = self.engine.subscribe_data(self, vt_symbol)
|
||||
if n:
|
||||
self.vt_symbols.add(vt_symbol)
|
||||
|
||||
return n
|
||||
|
||||
def put_event(self) -> None:
|
||||
"""推送策略数据更新事件"""
|
||||
if self.inited:
|
||||
self.engine.put_strategy_event(self)
|
||||
|
||||
def send_email(self, msg: str) -> None:
|
||||
"""发送邮件信息"""
|
||||
if self.inited:
|
||||
self.engine.send_email(msg, self)
|
||||
|
||||
def sync_data(self):
|
||||
"""同步策略状态数据到文件"""
|
||||
if self.trading:
|
||||
self.engine.sync_strategy_data(self)
|
||||
85
5.课程代码/2.Option_spread_strategy/使用文档/22/22_demo.ipynb
Normal file
85
5.课程代码/2.Option_spread_strategy/使用文档/22/22_demo.ipynb
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "470f6407-4081-4da1-af10-893e6f2d4d7b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from elite_database import EliteDatabase"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "0cc34541-a8ce-4d0f-8939-43bb4efc303b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"db = EliteDatabase()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "fdafd1d3-b3c7-48cf-910b-c38f8784bf31",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"contracts = db.load_contract_data()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "772229fb-e7cc-470f-9bf0-4ebe2db534e4",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"contract = contracts[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1fdf863d-a16d-4ed0-9383-bccbffff6ce7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(contract)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "74e1a672-dfb4-434d-92e3-41906da04584",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
136
5.课程代码/2.Option_spread_strategy/使用文档/23/23_demo.ipynb
Normal file
136
5.课程代码/2.Option_spread_strategy/使用文档/23/23_demo.ipynb
Normal file
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 加载功能模块\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"from vnpy.trader.constant import Interval\n",
|
||||
"\n",
|
||||
"from elite_optionstrategy import BacktestingEngine\n",
|
||||
"\n",
|
||||
"from buy_option_strategy import BuyOptionStrategy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 创建回测引擎\n",
|
||||
"engine = BacktestingEngine()\n",
|
||||
"\n",
|
||||
"engine.set_parameters(\n",
|
||||
" interval=Interval.MINUTE,\n",
|
||||
" start=datetime(2022, 1, 1),\n",
|
||||
" end=datetime(2022, 1, 28),\n",
|
||||
" rate=0,\n",
|
||||
" slippage=0.6 + (16 / 100),\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"engine.add_strategy(BuyOptionStrategy, {})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 历史数据回放\n",
|
||||
"engine.run_backtesting()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 获取引擎内最新交易日的策略对象\n",
|
||||
"strategy = engine.strategy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 获取策略内部对象\n",
|
||||
"portfolio = strategy.get_portfolio(\"IO\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 查看ChainData\n",
|
||||
"chain = portfolio.get_chain_by_level(0)\n",
|
||||
"chain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chain.calculate_synthetic()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 查看OptionData\n",
|
||||
"option = chain.get_option_by_level(cp=1, level=0)\n",
|
||||
"option"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
},
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "1b43cb0bd93d5abbadd54afed8252f711d4681fe6223ad6b67ffaee289648f85"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
159
5.课程代码/2.Option_spread_strategy/使用文档/23/buy_option_strategy.py
Normal file
159
5.课程代码/2.Option_spread_strategy/使用文档/23/buy_option_strategy.py
Normal file
@@ -0,0 +1,159 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
ChainData,
|
||||
OptionData,
|
||||
)
|
||||
|
||||
|
||||
class BuyOptionStrategy(StrategyTemplate):
|
||||
"""基于均线信号买入期权的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(20) # 快速均线周期
|
||||
slow_window: int = Parameter(120) # 慢速均线周期
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
|
||||
def on_init(self) -> None:
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor: MaFactor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars: list[BarData] = self.load_bars(self.underlying_symbol, 10, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self) -> None:
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self) -> None:
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData) -> None:
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]) -> None:
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain: ChainData = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多平值call
|
||||
atm_call: OptionData = front_chain.get_option_by_level(cp=1, level=0)
|
||||
self.set_target(atm_call.vt_symbol, self.fixed_size)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多平值put
|
||||
atm_put: OptionData = front_chain.get_option_by_level(cp=-1, level=0)
|
||||
self.set_target(atm_put.vt_symbol, self.fixed_size)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.fast_ma: float = 0
|
||||
self.slow_ma: float = 0
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
92
5.课程代码/2.Option_spread_strategy/使用文档/25/test.ipynb
Normal file
92
5.课程代码/2.Option_spread_strategy/使用文档/25/test.ipynb
Normal file
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from update_etf_data import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"xtquant历史合约信息下载完成\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"update_history_data()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"合约信息更新成功 446\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"update_contract_data(\"深证期权\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"合约信息更新成功 2681\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"update_contract_data(\"过期深证期权\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
186
5.课程代码/2.Option_spread_strategy/使用文档/25/update_etf_data.py
Normal file
186
5.课程代码/2.Option_spread_strategy/使用文档/25/update_etf_data.py
Normal file
@@ -0,0 +1,186 @@
|
||||
from multiprocessing import Process
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.trader.database import BarOverview
|
||||
from vnpy.trader.datafeed import get_datafeed
|
||||
from vnpy.trader.object import ContractData, BarData, HistoryRequest
|
||||
from vnpy.trader.constant import Exchange, Product, OptionType, Interval
|
||||
from vnpy.trader.setting import SETTINGS
|
||||
|
||||
from elite_database import EliteDatabase
|
||||
|
||||
|
||||
# 配置迅投研数据服务
|
||||
SETTINGS["datafeed.name"] = "xt"
|
||||
SETTINGS["datafeed.username"] = "token"
|
||||
SETTINGS["datafeed.password"] = "37b023f6623f9ddcb474dd210c70582d1b1e67d2"
|
||||
|
||||
|
||||
# 交易所映射关系
|
||||
EXCHANGE_XT2VT = {
|
||||
"SH": Exchange.SSE,
|
||||
"SZ": Exchange.SZSE,
|
||||
"BJ": Exchange.BSE,
|
||||
"SF": Exchange.SHFE,
|
||||
"IF": Exchange.CFFEX,
|
||||
"INE": Exchange.INE,
|
||||
"DF": Exchange.DCE,
|
||||
"ZF": Exchange.CZCE,
|
||||
"GF": Exchange.GFEX
|
||||
}
|
||||
|
||||
|
||||
def update_history_data() -> None:
|
||||
"""更新历史合约信息"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import download_history_data
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 下载历史合约信息
|
||||
download_history_data("", "historycontract")
|
||||
|
||||
print("xtquant历史合约信息下载完成")
|
||||
|
||||
|
||||
def update_contract_data(sector_name: str) -> None:
|
||||
"""更新合约数据"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import (
|
||||
get_stock_list_in_sector,
|
||||
get_instrument_detail
|
||||
)
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 查询历史合约代码
|
||||
vt_symbols: list[str] = get_stock_list_in_sector(sector_name)
|
||||
|
||||
# 遍历列表查询合约信息
|
||||
contracts: list[ContractData] = []
|
||||
|
||||
for xt_symbol in vt_symbols:
|
||||
# 拆分XT代码
|
||||
symbol, xt_exchange = xt_symbol.split(".")
|
||||
|
||||
# 筛选期权合约合约(ETF期权代码为8位)
|
||||
if len(symbol) == 8:
|
||||
data: dict = get_instrument_detail(xt_symbol, True)
|
||||
|
||||
name: str = data["InstrumentName"]
|
||||
if "购" in name:
|
||||
option_type = OptionType.CALL
|
||||
elif "沽" in name:
|
||||
option_type = OptionType.PUT
|
||||
else:
|
||||
continue
|
||||
|
||||
contract: ContractData = ContractData(
|
||||
symbol=data["InstrumentID"],
|
||||
exchange=EXCHANGE_XT2VT[xt_exchange.replace("O", "")],
|
||||
name=data["InstrumentName"],
|
||||
product=Product.OPTION,
|
||||
size=data["VolumeMultiple"],
|
||||
pricetick=data["PriceTick"],
|
||||
min_volume=data["MinLimitOrderVolume"],
|
||||
option_strike=data["ExtendInfo"]["OptExercisePrice"],
|
||||
option_listed=datetime.strptime(data["OpenDate"], "%Y%m%d"),
|
||||
option_expiry=datetime.strptime(data["ExpireDate"], "%Y%m%d"),
|
||||
option_portfolio=data["ProductID"],
|
||||
option_index=str(data["ExtendInfo"]["OptExercisePrice"]),
|
||||
option_type=option_type,
|
||||
gateway_name="XT"
|
||||
)
|
||||
contracts.append(contract)
|
||||
|
||||
# 保存合约信息到数据库
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
database.save_contract_data(contracts)
|
||||
|
||||
print("合约信息更新成功", len(contracts))
|
||||
|
||||
|
||||
def update_bar_data() -> None:
|
||||
"""更新K线数据"""
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 获取当前时间戳
|
||||
now: datetime = datetime.now()
|
||||
|
||||
# 获取合约信息
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
contracts: list[ContractData] = database.load_contract_data()
|
||||
|
||||
# 获取数据汇总
|
||||
data: list[BarOverview] = database.get_bar_overview()
|
||||
|
||||
overviews: dict[str, BarOverview] = {}
|
||||
for o in data:
|
||||
# 只保留分钟线数据
|
||||
if o.interval != Interval.MINUTE:
|
||||
continue
|
||||
|
||||
vt_symbol: str = f"{o.symbol}.{o.exchange.value}"
|
||||
overviews[vt_symbol] = o
|
||||
|
||||
# 遍历所有合约信息
|
||||
for contract in contracts:
|
||||
# 如果没有到期时间,则跳过
|
||||
if not contract.option_expiry:
|
||||
continue
|
||||
|
||||
# 查询数据汇总
|
||||
overview: BarOverview = overviews.get(contract.vt_symbol, None)
|
||||
|
||||
# 如果已经到期,则跳过
|
||||
if overview and contract.option_expiry < now:
|
||||
continue
|
||||
|
||||
# 初始化查询开始的时间
|
||||
start: datetime = datetime(2018, 1, 1)
|
||||
|
||||
# 实现增量查询
|
||||
if overview:
|
||||
start = overview.end
|
||||
|
||||
# 执行数据查询和更新入库
|
||||
req: HistoryRequest = HistoryRequest(
|
||||
symbol=contract.symbol,
|
||||
exchange=contract.exchange,
|
||||
start=start,
|
||||
end=datetime.now(),
|
||||
interval=Interval.MINUTE
|
||||
)
|
||||
|
||||
bars: list[BarData] = datafeed.query_bar_history(req)
|
||||
|
||||
if bars:
|
||||
database.save_bar_data(bars)
|
||||
|
||||
start_dt: datetime = bars[0].datetime
|
||||
end_dt: datetime = bars[-1].datetime
|
||||
msg: str = f"{contract.vt_symbol}数据更新成功,{start_dt} - {end_dt}"
|
||||
print(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 使用子进程更新历史合约信息
|
||||
process: Process = Process(target=update_history_data)
|
||||
process.start()
|
||||
process.join() # 等待子进程执行完成
|
||||
|
||||
# 更新合约信息
|
||||
update_contract_data("上证期权")
|
||||
update_contract_data("过期上证期权")
|
||||
|
||||
update_contract_data("深证期权")
|
||||
update_contract_data("过期深证期权")
|
||||
|
||||
# 更新历史数据
|
||||
update_bar_data()
|
||||
BIN
5.课程代码/2.Option_spread_strategy/使用文档/26/2024031574052027.dmp
Normal file
BIN
5.课程代码/2.Option_spread_strategy/使用文档/26/2024031574052027.dmp
Normal file
Binary file not shown.
102
5.课程代码/2.Option_spread_strategy/使用文档/26/get_history_sector.py
Normal file
102
5.课程代码/2.Option_spread_strategy/使用文档/26/get_history_sector.py
Normal file
@@ -0,0 +1,102 @@
|
||||
#encoding:gbk
|
||||
|
||||
import re
|
||||
|
||||
def init(C):
|
||||
|
||||
option_code_list1 = get_option_code(C,"IF",data_type = 0) # 获取中金所当前可交易期权合约
|
||||
|
||||
option_code_list2 = get_option_code(C,"SHO",data_type = 1) # 获取上交所已退市可交易期权合约
|
||||
option_code_list3 = get_option_code(C,"IF",data_type = 2) # 获取 中金所 所有期权(包含历史)合约
|
||||
|
||||
print(option_code_list1[:5])
|
||||
print("="*20)
|
||||
print(option_code_list2[:5])
|
||||
print("="*20)
|
||||
print(option_code_list3[:5])
|
||||
|
||||
# 可通过C.get_option_detail_data()查看合约具体信息
|
||||
|
||||
def hanldbar(C):
|
||||
return
|
||||
|
||||
def get_option_code(C,market,data_type = 0):
|
||||
|
||||
'''
|
||||
|
||||
ToDo:取出指定market的期权合约
|
||||
|
||||
Args:
|
||||
market: 目标市场,比如中金所填 IF
|
||||
|
||||
data_type: 返回数据范围,可返回已退市合约,默认仅返回当前
|
||||
|
||||
0: 仅当前
|
||||
1: 仅历史
|
||||
2: 历史 + 当前
|
||||
|
||||
'''
|
||||
_history_sector_dict = {
|
||||
"IF":"过期中金所",
|
||||
"SF":"过期上期所",
|
||||
"DF":"过期大商所",
|
||||
"ZF":"过期郑商所",
|
||||
"INE":"过期能源中心",
|
||||
"SHO":"过期上证期权",
|
||||
"SZO":"过期深证期权",
|
||||
}
|
||||
|
||||
# _now_secotr_dict = {
|
||||
# "IF":"中金所",
|
||||
# "SF":"上期所",
|
||||
# "DF":"大商所",
|
||||
# "ZF":"郑商所",
|
||||
# "INE":"能源中心",
|
||||
# "SHO":"上证期权",
|
||||
# "SZO":"深证期权",
|
||||
# }
|
||||
|
||||
_sector = _history_sector_dict.get(market)
|
||||
# _now_sector = _now_secotr_dict.get(market)
|
||||
if _sector == None:
|
||||
raise KeyError(f"不存在该市场:{market}")
|
||||
_now_sector = _sector[2:]
|
||||
|
||||
|
||||
# 过期上证和过期深证有专门的板块,不需要处理
|
||||
if market == "SHO" or market == "SZO":
|
||||
if data_type == 0:
|
||||
_list = C.get_stock_list_in_sector(_now_sector)
|
||||
elif data_type == 1:
|
||||
_list = C.get_stock_list_in_sector(_sector)
|
||||
elif data_type == 2:
|
||||
_list = C.get_stock_list_in_sector(_sector) + C.get_stock_list_in_sector(_now_sector)
|
||||
else:
|
||||
raise KeyError(f"data_type参数错误:{data_type}")
|
||||
return _list
|
||||
|
||||
# 期货期权需要额外处理
|
||||
if data_type == 0:
|
||||
all_list = C.get_stock_list_in_sector(_now_sector)
|
||||
elif data_type == 1:
|
||||
all_list = C.get_stock_list_in_sector(_sector)
|
||||
elif data_type == 2:
|
||||
all_list = C.get_stock_list_in_sector(_sector) + C.get_stock_list_in_sector(_now_sector)
|
||||
else:
|
||||
raise KeyError(f"data_type参数错误:{data_type}")
|
||||
|
||||
_list = []
|
||||
pattern1 = r'^[A-Z]{2}\d{4}-[A-Z]-\d{4}\.[A-Z]+$'
|
||||
pattern2 = r'^[a-zA-Z]+\d+[a-zA-Z]\d+\.[A-Z]+$'
|
||||
pattern3 = r'^[a-zA-Z]+\d+-[a-zA-Z]-\d+\.[A-Z]+$'
|
||||
for i in all_list:
|
||||
if re.match(pattern1,i):
|
||||
_list.append(i)
|
||||
elif re.match(pattern2,i):
|
||||
_list.append(i)
|
||||
elif re.match(pattern3,i):
|
||||
_list.append(i)
|
||||
# _list =[i for i in all_list if re.match(pattern, i)]
|
||||
return _list
|
||||
|
||||
|
||||
1159
5.课程代码/2.Option_spread_strategy/使用文档/26/test.ipynb
Normal file
1159
5.课程代码/2.Option_spread_strategy/使用文档/26/test.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
194
5.课程代码/2.Option_spread_strategy/使用文档/26/update_commodity_data.py
Normal file
194
5.课程代码/2.Option_spread_strategy/使用文档/26/update_commodity_data.py
Normal file
@@ -0,0 +1,194 @@
|
||||
from multiprocessing import Process
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.trader.database import BarOverview
|
||||
from vnpy.trader.datafeed import get_datafeed
|
||||
from vnpy.trader.object import ContractData, BarData, HistoryRequest
|
||||
from vnpy.trader.constant import Exchange, Product, OptionType, Interval
|
||||
from vnpy.trader.setting import SETTINGS
|
||||
|
||||
from elite_database import EliteDatabase
|
||||
|
||||
|
||||
# 配置迅投研数据服务
|
||||
SETTINGS["datafeed.name"] = "xt"
|
||||
SETTINGS["datafeed.username"] = "token"
|
||||
SETTINGS["datafeed.password"] = "4aff6f3b0dcfc990ec9476213ba784e17c34e757"
|
||||
|
||||
|
||||
# 交易所映射关系
|
||||
EXCHANGE_XT2VT = {
|
||||
"SH": Exchange.SSE,
|
||||
"SZ": Exchange.SZSE,
|
||||
"BJ": Exchange.BSE,
|
||||
"SF": Exchange.SHFE,
|
||||
"IF": Exchange.CFFEX,
|
||||
"INE": Exchange.INE,
|
||||
"DF": Exchange.DCE,
|
||||
"ZF": Exchange.CZCE,
|
||||
"GF": Exchange.GFEX
|
||||
}
|
||||
|
||||
|
||||
def update_history_data() -> None:
|
||||
"""更新历史合约信息"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import download_history_data
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 下载历史合约信息
|
||||
download_history_data("", "historycontract")
|
||||
|
||||
print("xtquant历史合约信息下载完成")
|
||||
|
||||
|
||||
def update_contract_data(sector_name: str) -> None:
|
||||
"""更新合约数据"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import (
|
||||
get_stock_list_in_sector,
|
||||
get_instrument_detail
|
||||
)
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 查询交易所历史合约代码
|
||||
vt_symbols: list[str] = get_stock_list_in_sector(sector_name)
|
||||
|
||||
# 遍历列表查询合约信息
|
||||
contracts: list[ContractData] = []
|
||||
|
||||
for xt_symbol in vt_symbols:
|
||||
# 筛选期权合约合约
|
||||
data: dict = get_instrument_detail(xt_symbol, True)
|
||||
option_strike: float = data["ExtendInfo"]["OptExercisePrice"]
|
||||
if not option_strike:
|
||||
continue
|
||||
|
||||
# 拆分XT代码
|
||||
symbol, xt_exchange = xt_symbol.split(".")
|
||||
|
||||
# 移除产品前缀
|
||||
for ix, w in enumerate(symbol):
|
||||
if w.isdigit():
|
||||
break
|
||||
|
||||
suffix: str = symbol[ix:]
|
||||
|
||||
# 判断期权类型
|
||||
if "C" in suffix:
|
||||
option_type = OptionType.CALL
|
||||
elif "P" in suffix:
|
||||
option_type = OptionType.PUT
|
||||
else:
|
||||
continue
|
||||
|
||||
contract: ContractData = ContractData(
|
||||
symbol=data["InstrumentID"],
|
||||
exchange=EXCHANGE_XT2VT[xt_exchange.replace("O", "")],
|
||||
name=data["InstrumentName"],
|
||||
product=Product.OPTION,
|
||||
size=data["VolumeMultiple"],
|
||||
pricetick=data["PriceTick"],
|
||||
min_volume=data["MinLimitOrderVolume"],
|
||||
option_strike=data["ExtendInfo"]["OptExercisePrice"],
|
||||
option_listed=datetime.strptime(data["OpenDate"], "%Y%m%d"),
|
||||
option_expiry=datetime.strptime(data["ExpireDate"], "%Y%m%d"),
|
||||
option_portfolio=data["ProductID"],
|
||||
option_index=str(data["ExtendInfo"]["OptExercisePrice"]),
|
||||
option_type=option_type,
|
||||
gateway_name="XT"
|
||||
)
|
||||
contracts.append(contract)
|
||||
|
||||
# 保存合约信息到数据库
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
database.save_contract_data(contracts)
|
||||
|
||||
print("合约信息更新成功", len(contracts))
|
||||
|
||||
return contracts
|
||||
|
||||
|
||||
def update_bar_data() -> None:
|
||||
"""更新K线数据"""
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 获取当前时间戳
|
||||
now: datetime = datetime.now()
|
||||
|
||||
# 获取合约信息
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
contracts: list[ContractData] = database.load_contract_data()
|
||||
|
||||
# 获取数据汇总
|
||||
data: list[BarOverview] = database.get_bar_overview()
|
||||
|
||||
overviews: dict[str, BarOverview] = {}
|
||||
for o in data:
|
||||
# 只保留分钟线数据
|
||||
if o.interval != Interval.MINUTE:
|
||||
continue
|
||||
|
||||
vt_symbol: str = f"{o.symbol}.{o.exchange.value}"
|
||||
overviews[vt_symbol] = o
|
||||
|
||||
# 遍历所有合约信息
|
||||
for contract in contracts:
|
||||
# 如果没有到期时间,则跳过
|
||||
if not contract.option_expiry:
|
||||
continue
|
||||
|
||||
# 查询数据汇总
|
||||
overview: BarOverview = overviews.get(contract.vt_symbol, None)
|
||||
|
||||
# 如果已经到期,则跳过
|
||||
if overview and contract.option_expiry < now:
|
||||
continue
|
||||
|
||||
# 初始化查询开始的时间
|
||||
start: datetime = datetime(2017, 1, 1)
|
||||
|
||||
# 实现增量查询
|
||||
if overview:
|
||||
start = overview.end
|
||||
|
||||
# 执行数据查询和更新入库
|
||||
req: HistoryRequest = HistoryRequest(
|
||||
symbol=contract.symbol,
|
||||
exchange=contract.exchange,
|
||||
start=start,
|
||||
end=datetime.now(),
|
||||
interval=Interval.MINUTE
|
||||
)
|
||||
|
||||
bars: list[BarData] = datafeed.query_bar_history(req)
|
||||
|
||||
if bars:
|
||||
database.save_bar_data(bars)
|
||||
|
||||
start_dt: datetime = bars[0].datetime
|
||||
end_dt: datetime = bars[-1].datetime
|
||||
msg: str = f"{contract.vt_symbol}数据更新成功,{start_dt} - {end_dt}"
|
||||
print(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 使用子进程更新历史合约信息
|
||||
process: Process = Process(target=update_history_data)
|
||||
process.start()
|
||||
process.join() # 等待子进程执行完成
|
||||
|
||||
# 更新合约信息
|
||||
update_contract_data("郑商所")
|
||||
update_contract_data("过期郑商所")
|
||||
|
||||
# 更新历史数据
|
||||
update_bar_data()
|
||||
69
5.课程代码/2.Option_spread_strategy/使用文档/27/test.ipynb
Normal file
69
5.课程代码/2.Option_spread_strategy/使用文档/27/test.ipynb
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from update_rqdata_data import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"contracts = update_contract_data(Exchange.CFFEX)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(contracts[0])\n",
|
||||
"print(contracts[-1])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"update_bar_data()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
154
5.课程代码/2.Option_spread_strategy/使用文档/27/update_rqdata_data.py
Normal file
154
5.课程代码/2.Option_spread_strategy/使用文档/27/update_rqdata_data.py
Normal file
@@ -0,0 +1,154 @@
|
||||
from datetime import datetime
|
||||
|
||||
import rqdatac
|
||||
import pandas as pd
|
||||
|
||||
from vnpy.trader.database import BarOverview
|
||||
from vnpy.trader.datafeed import get_datafeed
|
||||
from vnpy.trader.object import ContractData, BarData, HistoryRequest
|
||||
from vnpy.trader.constant import Exchange, Product, OptionType, Interval
|
||||
|
||||
from elite_database import EliteDatabase
|
||||
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
|
||||
# 交易所映射关系
|
||||
EXCHANGE_RQ2VT = {
|
||||
"XSHG": Exchange.SSE,
|
||||
"XSHE": Exchange.SZSE,
|
||||
"SHFE": Exchange.SHFE,
|
||||
"CFFEX": Exchange.CFFEX,
|
||||
"INE": Exchange.INE,
|
||||
"DCE": Exchange.DCE,
|
||||
"CZCE": Exchange.CZCE,
|
||||
"GFEX": Exchange.GFEX
|
||||
}
|
||||
|
||||
|
||||
def update_contract_data(exchange: Exchange) -> None:
|
||||
"""更新合约数据"""
|
||||
# 查询期权信息
|
||||
df: pd.DataFrame = rqdatac.all_instruments(type="Option")
|
||||
|
||||
# 转换合约对象
|
||||
contracts: list[ContractData] = []
|
||||
|
||||
for tp in df.itertuples():
|
||||
# 交易所过滤
|
||||
if exchange != EXCHANGE_RQ2VT[tp.exchange]:
|
||||
continue
|
||||
|
||||
# 确认期权类型
|
||||
if tp.option_type == "C":
|
||||
option_type = OptionType.CALL
|
||||
else:
|
||||
option_type = OptionType.PUT
|
||||
|
||||
# 获取最小价格变动
|
||||
pricetick: float = rqdatac.instruments(tp.order_book_id).tick_size()
|
||||
|
||||
# 创建期权对象
|
||||
contract = ContractData(
|
||||
symbol=tp.trading_code,
|
||||
exchange=exchange,
|
||||
name=tp.trading_code,
|
||||
product=Product.OPTION,
|
||||
size=tp.contract_multiplier,
|
||||
pricetick=pricetick,
|
||||
min_volume=tp.round_lot,
|
||||
option_strike=tp.strike_price,
|
||||
option_listed=datetime.strptime(tp.listed_date, "%Y-%m-%d"),
|
||||
option_expiry=datetime.strptime(tp.maturity_date, "%Y-%m-%d"),
|
||||
option_portfolio=tp.underlying_symbol,
|
||||
option_index=str(tp.strike_price),
|
||||
option_underlying=tp.trading_code.split("-")[0],
|
||||
option_type=option_type,
|
||||
gateway_name="RQ"
|
||||
)
|
||||
|
||||
contracts.append(contract)
|
||||
|
||||
# 保存合约信息到数据库
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
database.save_contract_data(contracts)
|
||||
|
||||
print("合约信息更新成功", len(contracts))
|
||||
|
||||
return contracts
|
||||
|
||||
|
||||
def update_bar_data() -> None:
|
||||
"""更新K线数据"""
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 获取当前时间戳
|
||||
now: datetime = datetime.now()
|
||||
|
||||
# 获取合约信息
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
contracts: list[ContractData] = database.load_contract_data()
|
||||
|
||||
# 获取数据汇总
|
||||
data: list[BarOverview] = database.get_bar_overview()
|
||||
|
||||
overviews: dict[str, BarOverview] = {}
|
||||
for o in data:
|
||||
# 只保留分钟线数据
|
||||
if o.interval != Interval.MINUTE:
|
||||
continue
|
||||
|
||||
vt_symbol: str = f"{o.symbol}.{o.exchange.value}"
|
||||
overviews[vt_symbol] = o
|
||||
|
||||
# 遍历所有合约信息
|
||||
for contract in contracts:
|
||||
# 如果没有到期时间,则跳过
|
||||
if not contract.option_expiry:
|
||||
continue
|
||||
|
||||
# 查询数据汇总
|
||||
overview: BarOverview = overviews.get(contract.vt_symbol, None)
|
||||
|
||||
# 如果已经到期,则跳过
|
||||
if overview and contract.option_expiry < now:
|
||||
continue
|
||||
|
||||
# 初始化查询开始的时间
|
||||
start: datetime = datetime(2018, 1, 1)
|
||||
|
||||
# 实现增量查询
|
||||
if overview:
|
||||
start = overview.end
|
||||
|
||||
# 执行数据查询和更新入库
|
||||
req: HistoryRequest = HistoryRequest(
|
||||
symbol=contract.symbol,
|
||||
exchange=contract.exchange,
|
||||
start=start,
|
||||
end=datetime.now(),
|
||||
interval=Interval.MINUTE
|
||||
)
|
||||
|
||||
bars: list[BarData] = datafeed.query_bar_history(req)
|
||||
|
||||
if bars:
|
||||
database.save_bar_data(bars)
|
||||
|
||||
start_dt: datetime = bars[0].datetime
|
||||
end_dt: datetime = bars[-1].datetime
|
||||
msg: str = f"{contract.vt_symbol}数据更新成功,{start_dt} - {end_dt}"
|
||||
print(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 更新合约信息
|
||||
update_contract_data(Exchange.CFFEX)
|
||||
|
||||
# 更新历史数据
|
||||
update_bar_data()
|
||||
3114
5.课程代码/2.Option_spread_strategy/使用文档/28/28_demo.ipynb
Normal file
3114
5.课程代码/2.Option_spread_strategy/使用文档/28/28_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
152
5.课程代码/2.Option_spread_strategy/使用文档/28/buy_option_strategy.py
Normal file
152
5.课程代码/2.Option_spread_strategy/使用文档/28/buy_option_strategy.py
Normal file
@@ -0,0 +1,152 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class BuyOptionStrategy(StrategyTemplate):
|
||||
"""基于均线信号买入期权的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(20) # 快速均线周期
|
||||
slow_window: int = Parameter(120) # 慢速均线周期
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars = self.load_bars(self.underlying_symbol, 10, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多平值call
|
||||
atm_call = front_chain.get_option_by_level(cp=1, level=0)
|
||||
self.set_target(atm_call.vt_symbol, self.fixed_size)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多平值put
|
||||
atm_put = front_chain.get_option_by_level(cp=-1, level=0)
|
||||
self.set_target(atm_put.vt_symbol, self.fixed_size)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
3013
5.课程代码/2.Option_spread_strategy/使用文档/29/29_demo.ipynb
Normal file
3013
5.课程代码/2.Option_spread_strategy/使用文档/29/29_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,70 @@
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class BuyStraddleStrategy(StrategyTemplate):
|
||||
"""持续做多跨式价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 如果已有仓位则不操作(持有到期)
|
||||
if self.pos_data:
|
||||
return
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 买入跨式价差
|
||||
atm_call = front_chain.get_option_by_level(cp=1, level=0)
|
||||
atm_put = front_chain.get_option_by_level(cp=-1, level=0)
|
||||
|
||||
self.set_target(atm_call.vt_symbol, self.fixed_size)
|
||||
self.set_target(atm_put.vt_symbol, self.fixed_size)
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from update_etf_data import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"合约信息更新成功 642\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"contracts = update_contract_data(\"上证期权\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"ContractData(gateway_name='XT', extra=None, symbol='10005765', exchange=<Exchange.SSE: 'SSE'>, name='50ETF购3月2411A', product=<Product.OPTION: '期权'>, size=10161, pricetick=0.0001, min_volume=1, stop_supported=False, net_position=False, history_data=False, option_strike=2.411, option_underlying='510050-2403', option_type=<OptionType.CALL: '看涨期权'>, option_listed=datetime.datetime(2023, 7, 27, 0, 0), option_expiry=datetime.datetime(2024, 3, 27, 0, 0), option_portfolio='510050', option_index='2.411')\n",
|
||||
"ContractData(gateway_name='XT', extra=None, symbol='10006712', exchange=<Exchange.SSE: 'SSE'>, name='300ETF沽6月3700', product=<Product.OPTION: '期权'>, size=10000, pricetick=0.0001, min_volume=1, stop_supported=False, net_position=False, history_data=False, option_strike=3.7, option_underlying='510300-2406', option_type=<OptionType.PUT: '看跌期权'>, option_listed=datetime.datetime(2024, 1, 19, 0, 0), option_expiry=datetime.datetime(2024, 6, 26, 0, 0), option_portfolio='510300', option_index='3.7')\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(contracts[0])\n",
|
||||
"print(contracts[-1])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"update_bar_data()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from update_rqdata_data import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"合约信息更新成功 4808\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"contracts = update_contract_data(Exchange.CFFEX)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"ContractData(gateway_name='RQ', extra=None, symbol='HO2301-C-2325', exchange=<Exchange.CFFEX: 'CFFEX'>, name='HO2301-C-2325', product=<Product.OPTION: '期权'>, size=100.0, pricetick=0.2, min_volume=1.0, stop_supported=False, net_position=False, history_data=False, option_strike=2325.0, option_underlying='HO2301', option_type=<OptionType.CALL: '看涨期权'>, option_listed=datetime.datetime(2022, 12, 21, 0, 0), option_expiry=datetime.datetime(2023, 1, 20, 0, 0), option_portfolio='HO', option_index='2325.0')\n",
|
||||
"ContractData(gateway_name='RQ', extra=None, symbol='MO2412-P-6600', exchange=<Exchange.CFFEX: 'CFFEX'>, name='MO2412-P-6600', product=<Product.OPTION: '期权'>, size=100.0, pricetick=0.2, min_volume=1.0, stop_supported=False, net_position=False, history_data=False, option_strike=6600.0, option_underlying='MO2412', option_type=<OptionType.PUT: '看跌期权'>, option_listed=datetime.datetime(2023, 12, 18, 0, 0), option_expiry=datetime.datetime(2024, 12, 20, 0, 0), option_portfolio='MO', option_index='6600.0')\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(contracts[0])\n",
|
||||
"print(contracts[-1])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"update_bar_data()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
from multiprocessing import Process
|
||||
from datetime import datetime
|
||||
|
||||
from vnpy.trader.database import BarOverview
|
||||
from vnpy.trader.datafeed import get_datafeed
|
||||
from vnpy.trader.object import ContractData, BarData, HistoryRequest
|
||||
from vnpy.trader.constant import Exchange, Product, OptionType, Interval
|
||||
from vnpy.trader.setting import SETTINGS
|
||||
|
||||
from elite_database import EliteDatabase
|
||||
|
||||
|
||||
# 配置迅投研数据服务
|
||||
SETTINGS["datafeed.name"] = "xt"
|
||||
SETTINGS["datafeed.username"] = "token"
|
||||
SETTINGS["datafeed.password"] = ""
|
||||
|
||||
|
||||
# 交易所映射关系
|
||||
EXCHANGE_XT2VT = {
|
||||
"SH": Exchange.SSE,
|
||||
"SZ": Exchange.SZSE,
|
||||
"BJ": Exchange.BSE,
|
||||
"SF": Exchange.SHFE,
|
||||
"IF": Exchange.CFFEX,
|
||||
"INE": Exchange.INE,
|
||||
"DF": Exchange.DCE,
|
||||
"ZF": Exchange.CZCE,
|
||||
"GF": Exchange.GFEX
|
||||
}
|
||||
|
||||
|
||||
def update_history_data() -> None:
|
||||
"""更新历史合约信息"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import download_history_data
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 下载历史合约信息
|
||||
download_history_data("", "historycontract")
|
||||
|
||||
print("xtquant历史合约信息下载完成")
|
||||
|
||||
|
||||
def update_contract_data(sector_name: str) -> None:
|
||||
"""更新合约数据"""
|
||||
# 在子进程中加载xtquant
|
||||
from xtquant.xtdata import (
|
||||
get_stock_list_in_sector,
|
||||
get_instrument_detail
|
||||
)
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 查询历史合约代码
|
||||
vt_symbols: list[str] = get_stock_list_in_sector(sector_name)
|
||||
|
||||
# 遍历列表查询合约信息
|
||||
contracts: list[ContractData] = []
|
||||
|
||||
for xt_symbol in vt_symbols:
|
||||
# 拆分XT代码
|
||||
symbol, xt_exchange = xt_symbol.split(".")
|
||||
|
||||
# 筛选期权合约合约(ETF期权代码为8位)
|
||||
if len(symbol) == 8:
|
||||
data: dict = get_instrument_detail(xt_symbol, True)
|
||||
#print(data)
|
||||
#raise Exception("fuck")
|
||||
name: str = data["InstrumentName"]
|
||||
if "购" in name:
|
||||
option_type = OptionType.CALL
|
||||
elif "沽" in name:
|
||||
option_type = OptionType.PUT
|
||||
else:
|
||||
continue
|
||||
|
||||
# 获取期权组合
|
||||
option_portfolio = data["ExtendInfo"]["OptUndlCode"]
|
||||
|
||||
# 获取期权链(标的)
|
||||
option_expiry = datetime.strptime(data["ExpireDate"], "%Y%m%d")
|
||||
option_underlying = option_portfolio + "-" + option_expiry.strftime("%y%m")
|
||||
|
||||
# 生成合约对象
|
||||
contract: ContractData = ContractData(
|
||||
symbol=data["InstrumentID"],
|
||||
exchange=EXCHANGE_XT2VT[xt_exchange.replace("O", "")],
|
||||
name=data["InstrumentName"],
|
||||
product=Product.OPTION,
|
||||
size=data["VolumeMultiple"],
|
||||
pricetick=data["PriceTick"],
|
||||
min_volume=data["MinLimitOrderVolume"],
|
||||
option_strike=data["ExtendInfo"]["OptExercisePrice"],
|
||||
option_listed=datetime.strptime(data["OpenDate"], "%Y%m%d"),
|
||||
option_expiry=datetime.strptime(data["ExpireDate"], "%Y%m%d"),
|
||||
option_portfolio=option_portfolio,
|
||||
option_underlying=option_underlying,
|
||||
option_index=str(data["ExtendInfo"]["OptExercisePrice"]),
|
||||
option_type=option_type,
|
||||
gateway_name="XT"
|
||||
)
|
||||
contracts.append(contract)
|
||||
|
||||
# 保存合约信息到数据库
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
database.save_contract_data(contracts)
|
||||
|
||||
print("合约信息更新成功", len(contracts))
|
||||
|
||||
return contracts
|
||||
|
||||
|
||||
def update_bar_data() -> None:
|
||||
"""更新K线数据"""
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 获取当前时间戳
|
||||
now: datetime = datetime.now()
|
||||
|
||||
# 获取合约信息
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
contracts: list[ContractData] = database.load_contract_data()
|
||||
|
||||
# 获取数据汇总
|
||||
data: list[BarOverview] = database.get_bar_overview()
|
||||
|
||||
overviews: dict[str, BarOverview] = {}
|
||||
for o in data:
|
||||
# 只保留分钟线数据
|
||||
if o.interval != Interval.MINUTE:
|
||||
continue
|
||||
|
||||
vt_symbol: str = f"{o.symbol}.{o.exchange.value}"
|
||||
overviews[vt_symbol] = o
|
||||
|
||||
# 遍历所有合约信息
|
||||
for contract in contracts:
|
||||
# 如果没有到期时间,则跳过
|
||||
if not contract.option_expiry:
|
||||
continue
|
||||
|
||||
# 查询数据汇总
|
||||
overview: BarOverview = overviews.get(contract.vt_symbol, None)
|
||||
|
||||
# 如果已经到期,则跳过
|
||||
if overview and contract.option_expiry < now:
|
||||
continue
|
||||
|
||||
# 初始化查询开始的时间
|
||||
start: datetime = datetime(2018, 1, 1)
|
||||
|
||||
# 实现增量查询
|
||||
if overview:
|
||||
start = overview.end
|
||||
|
||||
# 执行数据查询和更新入库
|
||||
req: HistoryRequest = HistoryRequest(
|
||||
symbol=contract.symbol,
|
||||
exchange=contract.exchange,
|
||||
start=start,
|
||||
end=datetime.now(),
|
||||
interval=Interval.MINUTE
|
||||
)
|
||||
|
||||
bars: list[BarData] = datafeed.query_bar_history(req)
|
||||
|
||||
if bars:
|
||||
database.save_bar_data(bars)
|
||||
|
||||
start_dt: datetime = bars[0].datetime
|
||||
end_dt: datetime = bars[-1].datetime
|
||||
msg: str = f"{contract.vt_symbol}数据更新成功,{start_dt} - {end_dt}"
|
||||
print(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 使用子进程更新历史合约信息
|
||||
process: Process = Process(target=update_history_data)
|
||||
process.start()
|
||||
process.join() # 等待子进程执行完成
|
||||
|
||||
# 更新合约信息
|
||||
update_contract_data("上证期权")
|
||||
update_contract_data("过期上证期权")
|
||||
|
||||
update_contract_data("深证期权")
|
||||
update_contract_data("过期深证期权")
|
||||
|
||||
# 更新历史数据
|
||||
update_bar_data()
|
||||
@@ -0,0 +1,163 @@
|
||||
from datetime import datetime
|
||||
|
||||
import rqdatac
|
||||
import pandas as pd
|
||||
|
||||
from vnpy.trader.database import BarOverview
|
||||
from vnpy.trader.datafeed import get_datafeed
|
||||
from vnpy.trader.object import ContractData, BarData, HistoryRequest
|
||||
from vnpy.trader.constant import Exchange, Product, OptionType, Interval
|
||||
|
||||
from elite_database import EliteDatabase
|
||||
|
||||
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
|
||||
# 交易所映射关系
|
||||
EXCHANGE_RQ2VT = {
|
||||
"XSHG": Exchange.SSE,
|
||||
"XSHE": Exchange.SZSE,
|
||||
"SHFE": Exchange.SHFE,
|
||||
"CFFEX": Exchange.CFFEX,
|
||||
"INE": Exchange.INE,
|
||||
"DCE": Exchange.DCE,
|
||||
"CZCE": Exchange.CZCE,
|
||||
"GFEX": Exchange.GFEX
|
||||
}
|
||||
|
||||
|
||||
def update_contract_data(exchange: Exchange) -> None:
|
||||
"""更新合约数据"""
|
||||
# 查询期权信息
|
||||
df: pd.DataFrame = rqdatac.all_instruments(type="Option")
|
||||
|
||||
# 转换合约对象
|
||||
contracts: list[ContractData] = []
|
||||
|
||||
for tp in df.itertuples():
|
||||
# 交易所过滤
|
||||
if exchange != EXCHANGE_RQ2VT[tp.exchange]:
|
||||
continue
|
||||
|
||||
# 确认期权类型
|
||||
if tp.option_type == "C":
|
||||
option_type = OptionType.CALL
|
||||
else:
|
||||
option_type = OptionType.PUT
|
||||
|
||||
# 获取最小价格变动
|
||||
pricetick: float = rqdatac.instruments(tp.order_book_id).tick_size()
|
||||
|
||||
# 获取期权链(标的)
|
||||
if "-" in tp.trading_code:
|
||||
option_underlying = tp.trading_code.split("-")[0]
|
||||
else:
|
||||
suffix = tp.trading_code.replace(tp.underlying_symbol, "")
|
||||
ix = suffix.index(tp.option_type)
|
||||
time_str = suffix[:ix]
|
||||
option_underlying = tp.underlying_symbol + time_str
|
||||
|
||||
# 创建期权对象
|
||||
contract = ContractData(
|
||||
symbol=tp.trading_code,
|
||||
exchange=exchange,
|
||||
name=tp.trading_code,
|
||||
product=Product.OPTION,
|
||||
size=tp.contract_multiplier,
|
||||
pricetick=pricetick,
|
||||
min_volume=tp.round_lot,
|
||||
option_strike=tp.strike_price,
|
||||
option_listed=datetime.strptime(tp.listed_date, "%Y-%m-%d"),
|
||||
option_expiry=datetime.strptime(tp.maturity_date, "%Y-%m-%d"),
|
||||
option_portfolio=tp.underlying_symbol,
|
||||
option_index=str(tp.strike_price),
|
||||
option_underlying=option_underlying,
|
||||
option_type=option_type,
|
||||
gateway_name="RQ"
|
||||
)
|
||||
|
||||
contracts.append(contract)
|
||||
|
||||
# 保存合约信息到数据库
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
database.save_contract_data(contracts)
|
||||
|
||||
print("合约信息更新成功", len(contracts))
|
||||
|
||||
return contracts
|
||||
|
||||
|
||||
def update_bar_data() -> None:
|
||||
"""更新K线数据"""
|
||||
# 初始化数据服务
|
||||
datafeed = get_datafeed()
|
||||
datafeed.init()
|
||||
|
||||
# 获取当前时间戳
|
||||
now: datetime = datetime.now()
|
||||
|
||||
# 获取合约信息
|
||||
database: EliteDatabase = EliteDatabase()
|
||||
contracts: list[ContractData] = database.load_contract_data()
|
||||
|
||||
# 获取数据汇总
|
||||
data: list[BarOverview] = database.get_bar_overview()
|
||||
|
||||
overviews: dict[str, BarOverview] = {}
|
||||
for o in data:
|
||||
# 只保留分钟线数据
|
||||
if o.interval != Interval.MINUTE:
|
||||
continue
|
||||
|
||||
vt_symbol: str = f"{o.symbol}.{o.exchange.value}"
|
||||
overviews[vt_symbol] = o
|
||||
|
||||
# 遍历所有合约信息
|
||||
for contract in contracts:
|
||||
# 如果没有到期时间,则跳过
|
||||
if not contract.option_expiry:
|
||||
continue
|
||||
|
||||
# 查询数据汇总
|
||||
overview: BarOverview = overviews.get(contract.vt_symbol, None)
|
||||
|
||||
# 如果已经到期,则跳过
|
||||
if overview and contract.option_expiry < now:
|
||||
continue
|
||||
|
||||
# 初始化查询开始的时间
|
||||
start: datetime = datetime(2018, 1, 1)
|
||||
|
||||
# 实现增量查询
|
||||
if overview:
|
||||
start = overview.end
|
||||
|
||||
# 执行数据查询和更新入库
|
||||
req: HistoryRequest = HistoryRequest(
|
||||
symbol=contract.symbol,
|
||||
exchange=contract.exchange,
|
||||
start=start,
|
||||
end=datetime.now(),
|
||||
interval=Interval.MINUTE
|
||||
)
|
||||
|
||||
bars: list[BarData] = datafeed.query_bar_history(req)
|
||||
|
||||
if bars:
|
||||
database.save_bar_data(bars)
|
||||
|
||||
start_dt: datetime = bars[0].datetime
|
||||
end_dt: datetime = bars[-1].datetime
|
||||
msg: str = f"{contract.vt_symbol}数据更新成功,{start_dt} - {end_dt}"
|
||||
print(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 更新合约信息
|
||||
update_contract_data(Exchange.CFFEX)
|
||||
|
||||
# 更新历史数据
|
||||
update_bar_data()
|
||||
BIN
5.课程代码/2.Option_spread_strategy/使用文档/3/3_option_pnl.xlsx
Normal file
BIN
5.课程代码/2.Option_spread_strategy/使用文档/3/3_option_pnl.xlsx
Normal file
Binary file not shown.
4542
5.课程代码/2.Option_spread_strategy/使用文档/31/31_demo.ipynb
Normal file
4542
5.课程代码/2.Option_spread_strategy/使用文档/31/31_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
100
5.课程代码/2.Option_spread_strategy/使用文档/31/buy_straddle_strategy.py
Normal file
100
5.课程代码/2.Option_spread_strategy/使用文档/31/buy_straddle_strategy.py
Normal file
@@ -0,0 +1,100 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
ChainData,
|
||||
OptionData
|
||||
)
|
||||
|
||||
|
||||
class BuyStraddleStrategy(StrategyTemplate):
|
||||
"""持续做多跨式价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.05) # 委托超价比例
|
||||
rolling_days: int = Parameter(5) # 移仓剩余天数
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 默认交易当月期权链
|
||||
chain_level: int = 0
|
||||
|
||||
# 如果已有目标则检查是否要移仓
|
||||
if self.target_data:
|
||||
# 获取期权到期时间
|
||||
for vt_symbol in self.target_data.keys():
|
||||
option: OptionData = portfolio.get_option(vt_symbol)
|
||||
expiry: datetime = option.contract.option_expiry
|
||||
break
|
||||
|
||||
# 获取当前时间
|
||||
for bar in bars.values():
|
||||
now: datetime = bar.datetime.replace(tzinfo=None) # 移除时区
|
||||
break
|
||||
|
||||
# 计算剩余时间
|
||||
time_left: timedelta = expiry - now
|
||||
|
||||
# 如果尚未到时间,则继续持仓
|
||||
if time_left.days > self.rolling_days:
|
||||
return
|
||||
|
||||
# 需要交易次月期权链
|
||||
chain_level = 1
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取目标期权链
|
||||
chain: ChainData = portfolio.get_chain_by_level(chain_level)
|
||||
if not chain:
|
||||
self.write_log("无法获取对应期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
chain.calculate_atm()
|
||||
|
||||
# 清空当前目标
|
||||
self.clear_targets()
|
||||
|
||||
# 买入跨式价差
|
||||
atm_call = chain.get_option_by_level(cp=1, level=0)
|
||||
atm_put = chain.get_option_by_level(cp=-1, level=0)
|
||||
|
||||
self.set_target(atm_call.vt_symbol, self.fixed_size)
|
||||
self.set_target(atm_put.vt_symbol, self.fixed_size)
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
4495
5.课程代码/2.Option_spread_strategy/使用文档/32/32_demo.ipynb
Normal file
4495
5.课程代码/2.Option_spread_strategy/使用文档/32/32_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,70 @@
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class ShortStraddleStrategy(StrategyTemplate):
|
||||
"""持续做空跨式价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 如果已有目标则不操作(持有到期)
|
||||
if self.pos_data:
|
||||
return
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 卖出跨式价差
|
||||
atm_call = front_chain.get_option_by_level(cp=1, level=0)
|
||||
atm_put = front_chain.get_option_by_level(cp=-1, level=0)
|
||||
|
||||
self.set_target(atm_call.vt_symbol, -self.fixed_size)
|
||||
self.set_target(atm_put.vt_symbol, -self.fixed_size)
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
4495
5.课程代码/2.Option_spread_strategy/使用文档/33/33_demo.ipynb
Normal file
4495
5.课程代码/2.Option_spread_strategy/使用文档/33/33_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,68 @@
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class ShortStraddleStrategy(StrategyTemplate):
|
||||
"""持续做空跨式价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 如果目标为空(尚未开仓或已经到期),则执行开仓
|
||||
if not self.target_data:
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 卖出跨式价差
|
||||
atm_call = front_chain.get_option_by_level(cp=1, level=0)
|
||||
atm_put = front_chain.get_option_by_level(cp=-1, level=0)
|
||||
|
||||
self.set_target(atm_call.vt_symbol, -self.fixed_size)
|
||||
self.set_target(atm_put.vt_symbol, -self.fixed_size)
|
||||
|
||||
# 执行具体的委托交易(每次on_bars都执行,避免某一轮委托未能成交导致偏差)
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
4502
5.课程代码/2.Option_spread_strategy/使用文档/34/34_demo.ipynb
Normal file
4502
5.课程代码/2.Option_spread_strategy/使用文档/34/34_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,87 @@
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
ChainData,
|
||||
OptionData
|
||||
)
|
||||
|
||||
|
||||
class ShortRestrikeStrategy(StrategyTemplate):
|
||||
"""带调仓的做空跨式价差策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
restrike_diff: float = Parameter(500) # ReStrike的偏差值
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
chain: ChainData = portfolio.get_chain_by_level(0)
|
||||
if not chain:
|
||||
self.write_log("无法获取对应期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值行权价
|
||||
chain.calculate_atm()
|
||||
|
||||
# 如果已有目标则检查是否要ReStrike
|
||||
if self.target_data:
|
||||
# 获取持仓的行权价
|
||||
for vt_symbol in self.target_data.keys():
|
||||
option: OptionData = portfolio.get_option(vt_symbol)
|
||||
option_strike: float = option.strike
|
||||
break
|
||||
|
||||
# 获取ATM的行权价
|
||||
atm_strike: float = chain.atm_strike
|
||||
|
||||
# 如果偏差在可接受范围内,则无需调仓
|
||||
if abs(option_strike - atm_strike) < self.restrike_diff:
|
||||
return
|
||||
|
||||
# 清空当前目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做空跨式价差
|
||||
atm_call = chain.get_option_by_level(cp=1, level=0)
|
||||
atm_put = chain.get_option_by_level(cp=-1, level=0)
|
||||
|
||||
self.set_target(atm_call.vt_symbol, -self.fixed_size)
|
||||
self.set_target(atm_put.vt_symbol, -self.fixed_size)
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
4495
5.课程代码/2.Option_spread_strategy/使用文档/35/33_demo.ipynb
Normal file
4495
5.课程代码/2.Option_spread_strategy/使用文档/35/33_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
4353
5.课程代码/2.Option_spread_strategy/使用文档/35/35_demo.ipynb
Normal file
4353
5.课程代码/2.Option_spread_strategy/使用文档/35/35_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,69 @@
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class ShortStrangleStrategy(StrategyTemplate):
|
||||
"""持续做空宽跨式价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
otm_level: int = Parameter(2) # 宽跨式虚值档位
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 如果目标为空(尚未开仓或已经到期),则执行开仓
|
||||
if not self.target_data:
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 卖出宽跨式价差
|
||||
otm_call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
otm_put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
self.set_target(otm_call.vt_symbol, -self.fixed_size)
|
||||
self.set_target(otm_put.vt_symbol, -self.fixed_size)
|
||||
|
||||
# 执行具体的委托交易(每次on_bars都执行,避免某一轮委托未能成交导致偏差)
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
5744
5.课程代码/2.Option_spread_strategy/使用文档/37/37_demo.ipynb
Normal file
5744
5.课程代码/2.Option_spread_strategy/使用文档/37/37_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
166
5.课程代码/2.Option_spread_strategy/使用文档/37/bull_bear_strategy.py
Normal file
166
5.课程代码/2.Option_spread_strategy/使用文档/37/bull_bear_strategy.py
Normal file
@@ -0,0 +1,166 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class BullBearStrategy(StrategyTemplate):
|
||||
"""基于均线信号买入牛熊价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(20) # 快速均线周期
|
||||
slow_window: int = Parameter(120) # 慢速均线周期
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
long_level: int = Parameter(0) # 做多腿档位
|
||||
short_level: int = Parameter(2) # 做空腿档位
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多Bull Spread
|
||||
long_option = front_chain.get_option_by_level(cp=1, level=self.long_level)
|
||||
short_option = front_chain.get_option_by_level(cp=1, level=self.short_level)
|
||||
|
||||
self.set_target(long_option.vt_symbol, self.fixed_size)
|
||||
self.set_target(short_option.vt_symbol, -self.fixed_size)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多Bear Spread
|
||||
long_option = front_chain.get_option_by_level(cp=-1, level=self.long_level)
|
||||
short_option = front_chain.get_option_by_level(cp=-1, level=self.short_level)
|
||||
|
||||
self.set_target(long_option.vt_symbol, self.fixed_size)
|
||||
self.set_target(short_option.vt_symbol, -self.fixed_size)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.bg.update_bar(bar)
|
||||
|
||||
def update_window_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
5744
5.课程代码/2.Option_spread_strategy/使用文档/38/38_demo.ipynb
Normal file
5744
5.课程代码/2.Option_spread_strategy/使用文档/38/38_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
166
5.课程代码/2.Option_spread_strategy/使用文档/38/bull_bear_strategy.py
Normal file
166
5.课程代码/2.Option_spread_strategy/使用文档/38/bull_bear_strategy.py
Normal file
@@ -0,0 +1,166 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class BullBearStrategy(StrategyTemplate):
|
||||
"""基于均线信号买入牛熊价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(20) # 快速均线周期
|
||||
slow_window: int = Parameter(120) # 慢速均线周期
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
long_level: int = Parameter(0) # 做多腿档位
|
||||
short_level: int = Parameter(2) # 做空腿档位
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多Bull Spread
|
||||
long_option = front_chain.get_option_by_level(cp=1, level=self.long_level)
|
||||
short_option = front_chain.get_option_by_level(cp=1, level=self.short_level)
|
||||
|
||||
self.set_target(long_option.vt_symbol, self.fixed_size)
|
||||
self.set_target(short_option.vt_symbol, -self.fixed_size)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多Bear Spread
|
||||
long_option = front_chain.get_option_by_level(cp=-1, level=self.long_level)
|
||||
short_option = front_chain.get_option_by_level(cp=-1, level=self.short_level)
|
||||
|
||||
self.set_target(long_option.vt_symbol, self.fixed_size)
|
||||
self.set_target(short_option.vt_symbol, -self.fixed_size)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.bg.update_bar(bar)
|
||||
|
||||
def update_window_bar(self, bar: BarData) -> None:
|
||||
"""周期K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
4650
5.课程代码/2.Option_spread_strategy/使用文档/39/39_demo.ipynb
Normal file
4650
5.课程代码/2.Option_spread_strategy/使用文档/39/39_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
172
5.课程代码/2.Option_spread_strategy/使用文档/39/bull_bear_strategy.py
Normal file
172
5.课程代码/2.Option_spread_strategy/使用文档/39/bull_bear_strategy.py
Normal file
@@ -0,0 +1,172 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class BullBearStrategy(StrategyTemplate):
|
||||
"""基于均线信号买入牛熊价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(20) # 快速均线周期
|
||||
slow_window: int = Parameter(120) # 慢速均线周期
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
long_level: int = Parameter(0) # 做多腿档位
|
||||
short_level: int = Parameter(2) # 做空腿档位
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
data = load_json("bull_bear_data.json")
|
||||
self.ma_signal = data.get("ma_signal", 0)
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
data = {"ma_signal": self.ma_signal}
|
||||
save_json("bull_bear_data.json", data)
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多Bull Spread
|
||||
long_option = front_chain.get_option_by_level(cp=1, level=self.long_level)
|
||||
short_option = front_chain.get_option_by_level(cp=1, level=self.short_level)
|
||||
|
||||
self.set_target(long_option.vt_symbol, self.fixed_size)
|
||||
self.set_target(short_option.vt_symbol, -self.fixed_size)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多Bear Spread
|
||||
long_option = front_chain.get_option_by_level(cp=-1, level=self.long_level)
|
||||
short_option = front_chain.get_option_by_level(cp=-1, level=self.short_level)
|
||||
|
||||
self.set_target(long_option.vt_symbol, self.fixed_size)
|
||||
self.set_target(short_option.vt_symbol, -self.fixed_size)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.bg.update_bar(bar)
|
||||
|
||||
def update_window_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
BIN
5.课程代码/2.Option_spread_strategy/使用文档/4/4_spread_pnl.xlsx
Normal file
BIN
5.课程代码/2.Option_spread_strategy/使用文档/4/4_spread_pnl.xlsx
Normal file
Binary file not shown.
5996
5.课程代码/2.Option_spread_strategy/使用文档/41/41_cta.ipynb
Normal file
5996
5.课程代码/2.Option_spread_strategy/使用文档/41/41_cta.ipynb
Normal file
File diff suppressed because one or more lines are too long
6424
5.课程代码/2.Option_spread_strategy/使用文档/41/41_demo.ipynb
Normal file
6424
5.课程代码/2.Option_spread_strategy/使用文档/41/41_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,173 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class AdvancedSpreadStrategy(StrategyTemplate):
|
||||
"""基于均线信号做空复合价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(5) # 快速均线周期
|
||||
slow_window: int = Parameter(60) # 慢速均线周期
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
otm_level: int = Parameter(0) # 做空期权档位
|
||||
leg1_ratio: int = Parameter(4) # 顺势腿的比例
|
||||
leg2_ratio: int = Parameter(1) # 逆势腿的比例
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
data = load_json("bull_bear_data.json")
|
||||
self.ma_signal = data.get("ma_signal", 0)
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
data = {"ma_signal": self.ma_signal}
|
||||
save_json("bull_bear_data.json", data)
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
if call and put:
|
||||
self.set_target(put.vt_symbol, -self.fixed_size * self.leg1_ratio)
|
||||
self.set_target(call.vt_symbol, -self.fixed_size * self.leg2_ratio)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
if call and put:
|
||||
self.set_target(call.vt_symbol, -self.fixed_size * self.leg1_ratio)
|
||||
self.set_target(put.vt_symbol, -self.fixed_size * self.leg2_ratio)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.bg.update_bar(bar)
|
||||
|
||||
def update_window_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
118
5.课程代码/2.Option_spread_strategy/使用文档/41/double_ma_strategy.py
Normal file
118
5.课程代码/2.Option_spread_strategy/使用文档/41/double_ma_strategy.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from vnpy_ctastrategy import (
|
||||
CtaTemplate,
|
||||
StopOrder,
|
||||
TickData,
|
||||
BarData,
|
||||
TradeData,
|
||||
OrderData,
|
||||
BarGenerator,
|
||||
ArrayManager,
|
||||
)
|
||||
|
||||
|
||||
class DoubleMaStrategy(CtaTemplate):
|
||||
author = "用Python的交易员"
|
||||
|
||||
fast_window = 5
|
||||
slow_window = 60
|
||||
|
||||
fast_ma0 = 0.0
|
||||
fast_ma1 = 0.0
|
||||
|
||||
slow_ma0 = 0.0
|
||||
slow_ma1 = 0.0
|
||||
|
||||
parameters = ["fast_window", "slow_window"]
|
||||
variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"]
|
||||
|
||||
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
|
||||
""""""
|
||||
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
|
||||
|
||||
self.bg = BarGenerator(self.on_bar, 30, self.on_window_bar)
|
||||
self.am = ArrayManager(self.slow_window + 10)
|
||||
|
||||
def on_init(self):
|
||||
"""
|
||||
Callback when strategy is inited.
|
||||
"""
|
||||
self.write_log("策略初始化")
|
||||
self.load_bar(10)
|
||||
|
||||
def on_start(self):
|
||||
"""
|
||||
Callback when strategy is started.
|
||||
"""
|
||||
self.write_log("策略启动")
|
||||
self.put_event()
|
||||
|
||||
def on_stop(self):
|
||||
"""
|
||||
Callback when strategy is stopped.
|
||||
"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
self.put_event()
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""
|
||||
Callback of new tick data update.
|
||||
"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def on_bar(self, bar: BarData):
|
||||
"""
|
||||
Callback of new bar data update.
|
||||
"""
|
||||
self.bg.update_bar(bar)
|
||||
|
||||
def on_window_bar(self, bar: BarData):
|
||||
am = self.am
|
||||
am.update_bar(bar)
|
||||
if not am.inited:
|
||||
return
|
||||
|
||||
fast_ma = am.sma(self.fast_window, array=True)
|
||||
self.fast_ma0 = fast_ma[-1]
|
||||
self.fast_ma1 = fast_ma[-2]
|
||||
|
||||
slow_ma = am.sma(self.slow_window, array=True)
|
||||
self.slow_ma0 = slow_ma[-1]
|
||||
self.slow_ma1 = slow_ma[-2]
|
||||
|
||||
cross_over = self.fast_ma0 > self.slow_ma0 and self.fast_ma1 < self.slow_ma1
|
||||
cross_below = self.fast_ma0 < self.slow_ma0 and self.fast_ma1 > self.slow_ma1
|
||||
|
||||
if cross_over:
|
||||
if self.pos == 0:
|
||||
self.buy(bar.close_price, 1)
|
||||
elif self.pos < 0:
|
||||
self.cover(bar.close_price, 1)
|
||||
self.buy(bar.close_price, 1)
|
||||
|
||||
elif cross_below:
|
||||
if self.pos == 0:
|
||||
self.short(bar.close_price, 1)
|
||||
elif self.pos > 0:
|
||||
self.sell(bar.close_price, 1)
|
||||
self.short(bar.close_price, 1)
|
||||
|
||||
self.put_event()
|
||||
|
||||
def on_order(self, order: OrderData):
|
||||
"""
|
||||
Callback of new order data update.
|
||||
"""
|
||||
pass
|
||||
|
||||
def on_trade(self, trade: TradeData):
|
||||
"""
|
||||
Callback of new trade data update.
|
||||
"""
|
||||
self.put_event()
|
||||
|
||||
def on_stop_order(self, stop_order: StopOrder):
|
||||
"""
|
||||
Callback of stop order update.
|
||||
"""
|
||||
pass
|
||||
2361
5.课程代码/2.Option_spread_strategy/使用文档/42/42_demo.ipynb
Normal file
2361
5.课程代码/2.Option_spread_strategy/使用文档/42/42_demo.ipynb
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,199 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class AdvancedSpreadStrategy(StrategyTemplate):
|
||||
"""基于均线信号做空符合价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("i_o") # 期权产品代码,沪深300:IO;
|
||||
underlying_symbol: str = Parameter("iJQ00.DCE") # 标的合约代码,沪深300:IFJQ00;
|
||||
fast_window: int = Parameter(5) # 快速均线周期
|
||||
slow_window: int = Parameter(60) # 慢速均线周期
|
||||
risk_level: int = Parameter(40) # 开仓风险度
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
otm_level: int = Parameter(0) # 做空期权档位
|
||||
leg1_ratio: int = Parameter(4) # 顺势腿的比例
|
||||
leg2_ratio: int = Parameter(1) # 逆势腿的比例
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
trading_size: int = Variable(1) # 当前交易数量
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
data = load_json("bull_bear_data.json")
|
||||
self.ma_signal = data.get("ma_signal", 0)
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
data = {"ma_signal": self.ma_signal}
|
||||
save_json("bull_bear_data.json", data)
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做空Put
|
||||
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
if call and put:
|
||||
atr_value: float = self.factor.get_atr()
|
||||
if atr_value:
|
||||
self.trading_size = int(self.risk_level / atr_value)
|
||||
self.trading_size = max(self.trading_size, 1)
|
||||
self.trading_size = 1 # 强制开启最小交易
|
||||
else:
|
||||
self.trading_size = 1
|
||||
|
||||
self.set_target(put.vt_symbol, -self.trading_size * self.leg1_ratio)
|
||||
self.set_target(call.vt_symbol, -self.trading_size * self.leg2_ratio)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做空Call
|
||||
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
if call and put:
|
||||
atr_value: float = self.factor.get_atr()
|
||||
if atr_value:
|
||||
self.trading_size = int(self.risk_level / atr_value)
|
||||
self.trading_size = max(self.trading_size, 1)
|
||||
self.trading_size = 1 # 强制开启最小交易
|
||||
else:
|
||||
self.trading_size = 1
|
||||
|
||||
self.set_target(call.vt_symbol, -self.trading_size * self.leg1_ratio)
|
||||
self.set_target(put.vt_symbol, -self.trading_size * self.leg2_ratio)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar, 5, self.update_window_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.bg.update_bar(bar)
|
||||
|
||||
def update_window_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
|
||||
def get_atr(self) -> float:
|
||||
"""获取ATR风险度"""
|
||||
if self.am.inited:
|
||||
return self.am.atr(self.slow_window)
|
||||
else:
|
||||
return 0
|
||||
@@ -0,0 +1,192 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
)
|
||||
|
||||
|
||||
class AdvancedSpreadStrategy(StrategyTemplate):
|
||||
"""基于均线信号做空符合价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("MO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IMJQ00.CFFEX") # 标的合约代码,IMJQ00.CFFEX
|
||||
aroon_window: int = Parameter(5) # AROON周期
|
||||
risk_level: int = Parameter(40) # 开仓风险度
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
otm_level: int = Parameter(0) # 做空期权档位
|
||||
leg1_ratio: int = Parameter(2) # 顺势腿的比例
|
||||
leg2_ratio: int = Parameter(1) # 逆势腿的比例
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
trading_size: int = Variable(1) # 当前交易数量
|
||||
|
||||
def on_init(self):
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor = AroonFactor(
|
||||
self.underlying_symbol,
|
||||
self.aroon_window,
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self):
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
data = load_json("bull_bear_data.json")
|
||||
self.ma_signal = data.get("ma_signal", 0)
|
||||
|
||||
def on_stop(self):
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
data = {"ma_signal": self.ma_signal}
|
||||
save_json("bull_bear_data.json", data)
|
||||
|
||||
def on_tick(self, tick: TickData):
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]):
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做空Put
|
||||
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
if call and put:
|
||||
atr_value: float = self.factor.get_atr()
|
||||
if atr_value:
|
||||
self.trading_size = int(self.risk_level / atr_value)
|
||||
self.trading_size = max(self.trading_size, 1)
|
||||
else:
|
||||
self.trading_size = 1
|
||||
|
||||
self.set_target(put.vt_symbol, -self.trading_size * self.leg1_ratio)
|
||||
self.set_target(call.vt_symbol, -self.trading_size * self.leg2_ratio)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做空Call
|
||||
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
if call and put:
|
||||
atr_value: float = self.factor.get_atr()
|
||||
if atr_value:
|
||||
self.trading_size = int(self.risk_level / atr_value)
|
||||
self.trading_size = max(self.trading_size, 1)
|
||||
else:
|
||||
self.trading_size = 1
|
||||
|
||||
self.set_target(call.vt_symbol, -self.trading_size * self.leg1_ratio)
|
||||
self.set_target(put.vt_symbol, -self.trading_size * self.leg2_ratio)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class AroonFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
aroon_window: int,
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.aroon_window: int = aroon_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
|
||||
self.am: ArrayManager = ArrayManager(aroon_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.bg.update_bar(bar)
|
||||
|
||||
def update_window_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.aroon_up, self.aroon_down = self.am.aroon(self.aroon_window)
|
||||
|
||||
# 判断信号
|
||||
if self.aroon_up > self.aroon_down: # and (self.aroon_up > 50)
|
||||
self.signal = 1
|
||||
elif self.aroon_up < self.aroon_down: # and (self.aroon_down < 50)
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
|
||||
def get_atr(self) -> float:
|
||||
"""获取ATR风险度"""
|
||||
if self.am.inited:
|
||||
return self.am.atr(self.aroon_window)
|
||||
else:
|
||||
return 0
|
||||
@@ -0,0 +1,203 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
ChainData,
|
||||
OptionData,
|
||||
OptionBarGenerator,
|
||||
)
|
||||
|
||||
|
||||
class AdvancedSpreadStrategy(StrategyTemplate):
|
||||
"""基于均线信号做空符合价差的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(5) # 快速均线周期
|
||||
slow_window: int = Parameter(60) # 慢速均线周期
|
||||
risk_level: int = Parameter(40) # 开仓风险度
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
otm_level: int = Parameter(0) # 做空期权档位
|
||||
leg1_ratio: int = Parameter(4) # 顺势腿的比例
|
||||
leg2_ratio: int = Parameter(1) # 逆势腿的比例
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
trading_size: int = Variable(1) # 当前交易数量
|
||||
atm_strike: float = Variable(0) # 当前平值行权价
|
||||
|
||||
def on_init(self) -> None:
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
# K线截面合成器
|
||||
self.obg: OptionBarGenerator = OptionBarGenerator(self.on_bars)
|
||||
|
||||
# 订阅行情
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor: MaFactor = MaFactor(self.underlying_symbol, self.fast_window, self.slow_window)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars: list[BarData] = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
# 缓存文件名称
|
||||
self.data_filename: str = f"{self.name}_data.json"
|
||||
|
||||
def on_start(self) -> None:
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
data: dict = load_json(self.data_filename)
|
||||
self.ma_signal = data.get("ma_signal", 0)
|
||||
|
||||
def on_stop(self) -> None:
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
data: dict = {"ma_signal": self.ma_signal}
|
||||
save_json(self.data_filename, data)
|
||||
|
||||
def on_tick(self, tick: TickData) -> None:
|
||||
"""Tick推送"""
|
||||
self.obg.update_tick(tick)
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]) -> None:
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain: ChainData = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
self.atm_strike = front_chain.atm_strike
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 做空Put
|
||||
call: OptionData = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
put: OptionData = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
if call and put:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
atr_value: float = self.factor.get_atr()
|
||||
if atr_value:
|
||||
self.trading_size = int(self.risk_level / atr_value)
|
||||
self.trading_size = max(self.trading_size, 1)
|
||||
else:
|
||||
self.trading_size = 1
|
||||
|
||||
self.set_target(put.vt_symbol, -self.trading_size * self.leg1_ratio)
|
||||
self.set_target(call.vt_symbol, -self.trading_size * self.leg2_ratio)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 做空Call
|
||||
call: OptionData = front_chain.get_option_by_level(cp=1, level=self.otm_level)
|
||||
put: OptionData = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
|
||||
|
||||
if call and put:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
atr_value: float = self.factor.get_atr()
|
||||
if atr_value:
|
||||
self.trading_size = int(self.risk_level / atr_value)
|
||||
self.trading_size = max(self.trading_size, 1)
|
||||
else:
|
||||
self.trading_size = 1
|
||||
|
||||
self.set_target(call.vt_symbol, -self.trading_size * self.leg1_ratio)
|
||||
self.set_target(put.vt_symbol, -self.trading_size * self.leg2_ratio)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
# 推送UI事件更新
|
||||
self.put_event()
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(self, vt_symbol: str, fast_window: int, slow_window: int) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.bg.update_bar(bar)
|
||||
|
||||
def update_window_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
|
||||
def get_atr(self) -> float:
|
||||
"""获取ATR风险度"""
|
||||
if self.am.inited:
|
||||
return self.am.atr(self.slow_window)
|
||||
else:
|
||||
return 0
|
||||
BIN
5.课程代码/2.Option_spread_strategy/使用文档/5/5_spread_pnl.xlsx
Normal file
BIN
5.课程代码/2.Option_spread_strategy/使用文档/5/5_spread_pnl.xlsx
Normal file
Binary file not shown.
BIN
5.课程代码/2.Option_spread_strategy/使用文档/5/5_股指期权T报价_20231019.png
Normal file
BIN
5.课程代码/2.Option_spread_strategy/使用文档/5/5_股指期权T报价_20231019.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 388 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user