增加交易策略、交易指标、量化库代码等文件夹

This commit is contained in:
Win_home
2025-04-27 15:54:09 +08:00
parent ca3b209096
commit f57150dae8
589 changed files with 854346 additions and 1757 deletions

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because one or more lines are too long

View 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()

File diff suppressed because one or more lines are too long

View 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()

File diff suppressed because one or more lines are too long

View 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)

View 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

View 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()

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because one or more lines are too long

View 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()

File diff suppressed because one or more lines are too long

View 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()

File diff suppressed because one or more lines are too long

View 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)

View 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

View 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()

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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
}

View 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
}

File diff suppressed because it is too large Load Diff

View 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课

View 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
}

View 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

View 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
}

View 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()

View 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)

View 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
}

View 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
}

View 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

View 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
}

View 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()

View 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

File diff suppressed because it is too large Load Diff

View 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()

View 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
}

View 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()

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because one or more lines are too long

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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()

View File

@@ -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()

File diff suppressed because one or more lines are too long

View 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)

File diff suppressed because one or more lines are too long

View File

@@ -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)

File diff suppressed because one or more lines are too long

View File

@@ -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)

File diff suppressed because one or more lines are too long

View File

@@ -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)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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)

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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

View 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

File diff suppressed because one or more lines are too long

View File

@@ -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") # 期权产品代码沪深300IO;
underlying_symbol: str = Parameter("iJQ00.DCE") # 标的合约代码,沪深300IFJQ00;
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

View File

@@ -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

View File

@@ -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

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