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

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

View File

@@ -0,0 +1,132 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"ename": "ModuleNotFoundError",
"evalue": "No module named 'vnpy_ctastrategy.strategies.vip09'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[1;32mIn[2], line 5\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mvnpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mtrader\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01moptimize\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m OptimizationSetting\n\u001b[0;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mvnpy_ctastrategy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mbacktesting\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m BacktestingEngine\n\u001b[1;32m----> 5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mvnpy_ctastrategy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mstrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mvip09\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m vip09\n\u001b[0;32m 6\u001b[0m \u001b[38;5;66;03m# from vip09 import vip09\u001b[39;00m\n",
"\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'vnpy_ctastrategy.strategies.vip09'"
]
}
],
"source": [
"from datetime import datetime\n",
"\n",
"from vnpy.trader.optimize import OptimizationSetting\n",
"from vnpy_ctastrategy.backtesting import BacktestingEngine\n",
"# from vnpy_ctastrategy.strategies.vip09 import vip09\n",
"from vip09 import vip09"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"engine = BacktestingEngine()\n",
"engine.set_parameters(\n",
" vt_symbol=\"rb00.SHFE\",\n",
" interval=\"1m\",\n",
" start=datetime(2020, 1, 1),\n",
" end=datetime(2024, 3, 21),\n",
" rate=1.5/10000,\n",
" slippage=1,\n",
" size=10,\n",
" pricetick=1,\n",
" capital=1_000_00,\n",
")\n",
"engine.add_strategy(vip09, {})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"engine.load_data()\n",
"engine.run_backtesting()\n",
"df = engine.calculate_result()\n",
"engine.calculate_statistics()\n",
"engine.show_chart()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"'''用于参数优化'''\n",
"# setting = OptimizationSetting()\n",
"# setting.set_target(\"sharpe_ratio\")\n",
"# setting.add_parameter(\"Length\", 5, 100, 5)\n",
"# setting.add_parameter(\"N\", 5, 100, 5)\n",
"# setting.add_parameter(\"X\", 1, 20, 1)\n",
"# setting.add_parameter(\"TS\", 5, 100, 5)\n",
"# from multiprocessing import cpu_count\n",
"# # 获取 CPU 核心数量\n",
"# num_cores = cpu_count()\n",
"# print(f\"获取 CPU 核心数量:\",round(num_cores/2))\n",
"# engine.run_ga_optimization(setting, max_workers=round(num_cores/2))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"#engine.run_bf_optimization(setting)"
]
},
{
"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.10.9"
},
"vscode": {
"interpreter": {
"hash": "1b43cb0bd93d5abbadd54afed8252f711d4681fe6223ad6b67ffaee289648f85"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -0,0 +1,238 @@
from vnpy_ctastrategy import (
CtaTemplate,
TargetPosTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
import pandas as pd
class vip09(TargetPosTemplate):
""""""
author = "松鼠Quant"
Length = 30
N=5
X=10
TS = 45
lots=1
current_bar = 0
Highup=0
Lowdown=0
HigherAfterEntry = float('inf')
LowerAfterEntry = -float('inf')
liQKA = 0
DliqPoint = 0
KliqPoint = 0
OBVValue=[0]
MAOBV=[0]
M2=[0]
cond1=[0]*2
cond2=[0]*2
cond3=[0]*2
cond4=[0]*2
cond5=[0]*2
kong_cond1=[0]*2
kong_cond2=[0]*2
kong_cond3=[0]*2
kong_cond4=[0]*2
kong_cond5=[0]*2
MA1=0
MA2=0
MA3=0
parameters = ["Length",'N','X',"TS",'lots']
variables = ["HigherAfterEntry","LowerAfterEntry","liQKA","DliqPoint","KliqPoint"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
""""""
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
#df: pd.DataFrame = pd.read_csv(r"index_contract.csv")
#self.contracts_sizes = {row.vt_symbol.split('.')[0]: row.contract_size for _, row in df.iterrows()}
self.bg = BarGenerator(self.on_bar)
self.am = ArrayManager(200)
self.pos=0
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.load_bar(1)
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.
"""
self.bg.update_tick(tick)
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
am = self.am
am.update_bar(bar)
if not am.inited:
return
# 如果历史数据还没有初始化完毕,则直接返回
# 注意am 是交易系统中的一个数据管理器,可能用于管理历史数据
# bar 是当前的K线数据其中包含了开盘价、最高价、最低价、收盘价和成交量等信息
if self.current_bar == 0:
self.OBVValue = [0]
else:
if am.close_array[-1] > am.close_array[-2]:
self.OBVValue += [self.OBVValue[-1] + am.volume_array[-1]]
elif am.close_array[-1] < am.close_array[-2]:
self.OBVValue += [self.OBVValue[-1] - am.volume_array[-1]]
# 根据收盘价的涨跌更新 OBV 值
# 如果当前收盘价大于昨日收盘价,则 OBV 值加上当前成交量
# 如果当前收盘价小于昨日收盘价,则 OBV 值减去当前成交量
# 注意OBV 是一种基于成交量变化来反映买卖力量的技术指标,用于判断市场的买卖压力
self.current_bar=self.current_bar+1 #Bar线计数
#print(bar.datetime,"current_bar:",self.current_bar)
# 记录当前Bar的计数器值并打印当前Bar的时间和计数器值
if(self.current_bar<self.Length*3):
return
# 如果当前Bar的计数器值小于三倍的Length则直接返回
# 这可能是因为需要一定数量的历史数据才能计算出所需的指标值
# print(f'{self.OBVValue},OBVValue')
self.MA1=am.ema(self.Length,array=True)
self.MA2=am.ema(self.Length*2,array=True)
self.MA3=am.ema(self.Length*3,array=True)
# 计算三条指定长度的指数移动平均线EMA
# 分别记为MA1、MA2和MA3
self.MAOBV += [(sum(self.OBVValue[-self.Length:]) / self.Length)]
self.M2 += [(sum(self.OBVValue[-self.X:]) / self.X)]
# 计算 OBV 和 M2 的移动平均值
self.cond1=self.MA1 if am.close_array[-1] > self.MA1[-2] else self.cond1
self.cond2=self.MA1 if self.M2[-1] > self.M2[-2] else self.cond2
self.cond3=self.MA2 if am.close_array[-1] > self.MA2[-1] and self.MAOBV[-1] > self.MAOBV[-2] else self.cond3
self.cond4=self.MA2 if am.close_array[-1] > self.MA2[-1] else self.cond4
self.cond5=self.MA3 if am.close_array[-1] > self.MA3[-1] and self.MAOBV[-1] > self.MAOBV[-2] else self.cond5
# 根据条件更新多头条件指标cond1到cond5
# 根据条件更新空头条件指标kong_cond1到kong_cond5
self.kong_cond1=self.MA1 if am.close_array[-1] < self.MA1[-2] else self.kong_cond1
self.kong_cond2=self.MA1 if self.M2[-1] < self.M2[-2] else self.kong_cond2
self.kong_cond3=self.MA2 if am.close_array[-1] < self.MA2[-1] and self.MAOBV[-1] < self.MAOBV[-2] else self.kong_cond3
self.kong_cond4=self.MA2 if am.close_array[-1] < self.MA2[-1] else self.kong_cond4
self.kong_cond5=self.MA3 if am.close_array[-1] < self.MA3[-1] and self.MAOBV[-1] < self.MAOBV[-2] else self.kong_cond5
# 更新空头条件指标kong_cond1到kong_cond5
self.Highup=max(am.high_array[-self.N:-1])
self.Lowdown=min(am.low_array[-self.N:-1])
# 计算最近N个Bar的最高价和最低价分别记为Highup和Lowdown
Long_line=am.close_array[-1]>self.MA3[-1] and self.MAOBV[-1]>self.MAOBV[-2]
short_line=am.close_array[-1]<self.MA3[-1] and self.MAOBV[-1]<self.MAOBV[-2]
#print(f'{self.MAOBV[-1]},MAOBV')
#print(f'{Long_line},Long_line')
#print(f'{short_line},short_line')
if Long_line:
if self.cond4[-1]>self.cond5[-2] and self.cond5[-1]>self.cond5[-2] and self.cond4[-1]>self.cond4[-2] and self.cond3[-1]>self.cond3[-2] and self.cond2[-1]>self.cond2[-2] and self.cond1[-1]>self.cond1[-2] :
if self.pos!=1 and bar.high_price>=self.Highup :
if self.pos == 0:
self.buy(bar.close_price, self.lots)
elif self.pos < 0:
self.cover(bar.close_price, self.lots)
self.buy(bar.close_price, self.lots)
self.LowerAfterEntry = bar.close_price
if short_line:
if self.kong_cond4[-1]<self.kong_cond5[-1] and self.kong_cond5[-1]<self.kong_cond5[-2] and self.kong_cond4[-1]<self.kong_cond4[-2] and self.kong_cond3[-1]<self.kong_cond3[-2] and self.kong_cond2[-1]<self.kong_cond2[-2] and self.kong_cond1[-1]<self.kong_cond1[-2]:
if self.pos!=-1 and bar.low_price<=self.Lowdown :
if self.pos == 0:
self.short(bar.close_price, self.lots)
elif self.pos > 0:
self.sell(bar.close_price, self.lots)
self.short(bar.close_price, self.lots)
self.HigherAfterEntry = bar.close_price
#记录入场后的最高价和最低价
if self.pos>0:
#self.HigherAfterEntry = HigherAfterEntry
self.LowerAfterEntry = max(self.LowerAfterEntry, bar.low_price)
elif self.pos<0:
self.HigherAfterEntry = min(self.HigherAfterEntry, bar.high_price)
#self.LowerAfterEntry = LowerAfterEntry
if self.pos == 0:
self.liQKA = 1
else:
self.liQKA = self.liQKA - 0.1
self.liQKA = max(self.liQKA, 0.5)
if self.pos>0:
DliqPoint = self.LowerAfterEntry - ((bar.open_price)*self.TS/1000)*self.liQKA
#print(bar.datetime,"DliqPoint",DliqPoint,"low_price",bar.low_price,"self.LowerAfterEntry",self.LowerAfterEntry)
if self.pos<0:
KliqPoint = self.HigherAfterEntry + ((bar.open_price)*self.TS/1000)*self.liQKA
#print(bar.datetime,"KliqPoint",KliqPoint,"high_price",bar.high_price,"self.HigherAfterEntry",self.HigherAfterEntry)
if (self.pos>0 and bar.low_price <= DliqPoint and DliqPoint>0):
#多头出场
self.sell(bar.close_price, self.lots)
elif (self.pos<0 and bar.high_price > KliqPoint and KliqPoint>0):
#空头出场
self.cover(bar.close_price, self.lots)
self.current_bar += 1
self.put_event()
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

View File

@@ -0,0 +1,179 @@
//------------------------------------------------------------------------
// <20><><EFBFBD><EFBFBD>: vip09
// <20><><EFBFBD><EFBFBD>: vip09
// <20><><EFBFBD><EFBFBD>: <20><>ʽӦ<CABD><D3A6>
// <20><><EFBFBD><EFBFBD>: <20>û<EFBFBD>Ӧ<EFBFBD><D3A6>
// <20><><EFBFBD><EFBFBD>: Void
//------------------------------------------------------------------------
Params
//Ĭ<><C4AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>888 1Сʱ
Numeric Length(20); //<2F><><EFBFBD><EFBFBD>
Numeric Offset(2); //<2F><>׼<EFBFBD><EFBFBD><EEB1B6>
Numeric X(0.5);
Numeric SS(0.01);
Numeric TRS(75);//<2F>ƶ<EFBFBD>ֹ<EFBFBD><D6B9>ֹӯ<D6B9><D3AF><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ<EFBFBD><CEA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 5-100<30><30>5
Numeric Fund(20000); //Ͷ<>뱣֤<EBB1A3><D6A4><EFBFBD><EFBFBD>
Vars
Numeric Lots(0);
Series<Numeric> ma1;
Series<Numeric> UpLine; //<2F>Ϲ<EFBFBD>
Series<Numeric> DownLine; //<2F>¹<EFBFBD>
Series<Numeric> MidLine; //<2F>м<EFBFBD><D0BC><EFBFBD>
Series<Numeric> Band;
Series<Numeric> cond1;
Series<Numeric> cond2;
Series<Numeric> cond3;
Series<Numeric> cond4;
Series<Numeric> kcond1;
Series<Numeric> kcond2;
Series<Numeric> kcond3;
Series<Numeric> kcond4;
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Series<Numeric> MyPrice;//<2F><><EFBFBD>ּ۸<D6BC>
Series<Numeric> MyPrice2;//<2F><><EFBFBD>ּ۸<D6BC>
Series<Numeric> HighAfterEntry;//<2F><><EFBFBD>ֺ<EFBFBD><D6BA><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>߼<EFBFBD>
Series<Numeric> LowAfterEntry;//<2F><><EFBFBD>ֺ<EFBFBD><D6BA><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>ͼ<EFBFBD>
Series<Numeric> liQKA;
Series<Numeric> DliqPoint;
Series<Numeric> KliqPoint;
Series<Numeric> barcoutN;
Series<Numeric> bar_entry_count;
Series<Numeric> kaicang_kg;
Series<Numeric> BB;
Series<Numeric> WIDTH;
Plot plt1;
Plot plt2;
Events
//<2F>˴<EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
//<2F><>ʼ<EFBFBD><CABC><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڼ䣬<DABC><E4A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB>һ<EFBFBD>Σ<EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵȲ<DDB5><C8B2><EFBFBD>
OnInit()
{
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD>й<EFBFBD>
Range[0:DataCount-1]
{
//=========<3D><><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>==============
AddDataFlag(Enum_Data_RolloverBackWard()); //<2F><><EFBFBD>ú<EFBFBD><C3BA><EFBFBD>Ȩ
AddDataFlag(Enum_Data_RolloverRealPrice()); //<2F><><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3><EFBFBD><EFBFBD>ʵ<EFBFBD>۸<EFBFBD>
AddDataFlag(Enum_Data_AutoSwapPosition()); //<2F><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
//AddDataFlag(Enum_Data_IgnoreSwapSignalCalc()); //<2F><><EFBFBD>ú<EFBFBD><C3BA>Ի<EFBFBD><D4BB><EFBFBD><EFBFBD>źż<C5BA><C5BC><EFBFBD>
plt1.figure(0); //plt_vol<6F><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB>壬û<E5A3AC><C3BB>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>id,ϵͳ<CFB5>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
plt2.figure(0);
}
}
//Bar<61><72><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>indexs<78><73>ʾ<EFBFBD><EFBFBD><E4BBAF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դͼ<D4B4><CDBC>ID<49><44><EFBFBD><EFBFBD>
OnBar(ArrayRef<Integer> indexs)
{
Lots = Max(1, Round(Fund/(O*ContractUnit*BigPointValue* MarginRatio/rollover), 0));
MidLine = AverageFC(Close,Length);
Band = StandardDev(Close,Length,2);
UpLine = MidLine + Offset * Band;
DownLine = MidLine - Offset * Band;
PlotNumeric("MidLine",cond1,cond1,White);
PlotNumeric("UpLine",cond2,cond2,red);
PlotNumeric("DownLine",cond3,cond3,Green);
//<2F><><EFBFBD>ּ<EFBFBD><D6BC>ޣ<EFBFBD>BB<42><42>=<3D><><EFBFBD><EFBFBD><EFBFBD>̼<EFBFBD>-<2D><><EFBFBD><EFBFBD><EFBFBD>¹<EFBFBD><C2B9>۸<EFBFBD><DBB8><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϲ<EFBFBD><CFB9>۸<EFBFBD>-<2D><><EFBFBD><EFBFBD><EFBFBD>¹<EFBFBD><C2B9>۸<EFBFBD><DBB8><EFBFBD>
BB=((C-DownLine)/(UpLine-DownLine));
//WIDTH=<3D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϲ<EFBFBD>ֵ-<2D><><EFBFBD><EFBFBD><EFBFBD>¹<EFBFBD>ֵ<EFBFBD><D6B5>/<2F><><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD>ֵ
WIDTH=((UpLine-DownLine)/MidLine);
plt1.line("BB",BB); //<2F><><EFBFBD><EFBFBD>
plt2.line("WIDTH",WIDTH);
if(MarketPosition!=1 and H>=UpLine[1] and C[1]<UpLine[1] and BB[1]>X and WIDTH[1]>SS)
{
Buy(Lots,max(open,UpLine[1])); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3BFAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
LowAfterEntry = EntryPrice;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD>ּ۸<D6BC>;
kaicang_kg=1; // <20><><EFBFBD><EFBFBD><EFBFBD>ѿ<EFBFBD><D1BF><EFBFBD>
bar_entry_count=0; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD>ֵ<EFBFBD>Bar<61><72><EFBFBD><EFBFBD>
barcoutN=0; //<2F><><EFBFBD><EFBFBD>liQKAϵ<41><CFB5><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
liQKA = 1;
}
if(MarketPosition!=-1 and L<=DownLine[1] and C[1]>DownLine[1] and BB[1]<X and WIDTH[1]>SS)
{
SellShort(Lots,min(open,DownLine[1])); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3BFAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
HighAfterEntry = EntryPrice;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD>ּ۸<D6BC>;
kaicang_kg=1; // <20><><EFBFBD><EFBFBD><EFBFBD>ѿ<EFBFBD><D1BF><EFBFBD>
bar_entry_count=0; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD>ֵ<EFBFBD>Bar<61><72><EFBFBD><EFBFBD>
barcoutN=0; //<2F><><EFBFBD><EFBFBD>liQKAϵ<41><CFB5><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
liQKA = 1;
}
if(kaicang_kg[1] ==1) // <20><><EFBFBD><EFBFBD><EFBFBD>ڱ<EFBFBD><DAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>п<EFBFBD><D0BF>ֲ<EFBFBD><D6B2><EFBFBD>
{
bar_entry_count=bar_entry_count+1; // <20><><EFBFBD><EFBFBD><EFBFBD>ּ<EFBFBD><D6BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ
}
Else
{
bar_entry_count=0; // <20><><EFBFBD><EFBFBD>û<EFBFBD>п<EFBFBD><D0BF>֣<EFBFBD><D6A3>򽫿<EFBFBD><F2BDABBF>ּ<EFBFBD><D6BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ 0
}
//<2F>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD><EFBFBD>
If(MarketPosition == 0) // <20><><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>Ĭ<EFBFBD><C4AC>ֵ<EFBFBD><D6B5>
{
liQKA = 1;
barcoutN=0;
}Else if(bar_entry_count>barcoutN) //<2F><><EFBFBD>гֲֵ<D6B2><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD>liQKA<4B><41><EFBFBD><EFBFBD><EFBFBD>ųֲ<C5B3>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD><D3B6>𽥼<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>ֹ<EFBFBD><D6B9>ֹӯ<D6B9><D3AF><EFBFBD>ȳ<EFBFBD><C8B3><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC>١<EFBFBD>
{
liQKA = liQKA - 0.1;
liQKA = Max(liQKA,0.3);
barcoutN=bar_entry_count;
}
Commentary("kaicang_kg[1]"+text(kaicang_kg[1]));
Commentary("bar_entry_count"+text(bar_entry_count));
Commentary("barcoutN"+text(barcoutN));
Commentary("liQKA"+text(liQKA));
// <20><>¼<EFBFBD><C2BC><EFBFBD>ֺ<EFBFBD><D6BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߵ<EFBFBD><DFB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD>
If(bar_entry_count > 0)
{
HighAfterEntry = Min(HighAfterEntry,High); // <20><>ͷֹ<CDB7>𣬸<EFBFBD><F0A3ACB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><CDB5><EFBFBD><EFBFBD>߼<EFBFBD>
LowAfterEntry = Max(LowAfterEntry,Low); // <20><>ͷֹ<CDB7>𣬸<EFBFBD><F0A3ACB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߵ<EFBFBD><DFB5><EFBFBD><EFBFBD>ͼ<EFBFBD>
}
if(MarketPosition>0)
{
DliqPoint = LowAfterEntry - (Open*TRS/1000)*liQKA; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD>߻<EFBFBD><DFBB><EFBFBD><EFBFBD>ųֲ<C5B3>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӱ<EFBFBD><D3B1><EFBFBD>Խ<EFBFBD><D4BD>Խ<EFBFBD><D4BD><EFBFBD>У<EFBFBD>
}
if(MarketPosition<0)
{
KliqPoint = HighAfterEntry + (Open*TRS/1000)*liQKA; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD>߻<EFBFBD><DFBB><EFBFBD><EFBFBD>ųֲ<C5B3>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӱ<EFBFBD><D3B1><EFBFBD>Խ<EFBFBD><D4BD>Խ<EFBFBD><D4BD><EFBFBD>У<EFBFBD>
}
If(KliqPoint[1]>0 and MarketPosition<0)PlotNumeric("KliqPoint[1]",KliqPoint[1]);
if(DliqPoint[1]>0 and MarketPosition>0)PlotNumeric("DliqPoint[1]",DliqPoint[1]);
// <20><><EFBFBD>ж൥ʱ
If(MarketPosition >0 And bar_entry_count >0 And Low <= DliqPoint[1] and DliqPoint[1]>0 and DliqPoint[1]>0 and bar_entry_count>0)
{
Sell(0,Min(Open,DliqPoint[1]));
DliqPoint=0;
kaicang_kg=0;
}
// <20><><EFBFBD>пյ<D0BF>ʱ
If(MarketPosition <0 And bar_entry_count >0 And High >= KliqPoint[1] and KliqPoint[1]>0 and KliqPoint[1]>0 and bar_entry_count>0)
{
BuyToCover(0,Max(Open,KliqPoint[1]));
KliqPoint=0;
kaicang_kg=0;
}
}

View File

@@ -0,0 +1,158 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from datetime import datetime\n",
"\n",
"from vnpy.trader.optimize import OptimizationSetting\n",
"from vnpy_ctastrategy.backtesting import BacktestingEngine\n",
"# from vnpy_ctastrategy.strategies.vip10 import vip10\n",
"from vip10 import vip10"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"engine = BacktestingEngine()\n",
"engine.set_parameters(\n",
" vt_symbol=\"rb888.SHFE\",\n",
" interval=\"1h\",\n",
" start=datetime(2020, 1, 1),\n",
" end=datetime(2024, 3, 21),\n",
" rate=1.5/10000,\n",
" slippage=1,\n",
" size=10,\n",
" pricetick=1,\n",
" capital=1_000_00,\n",
")\n",
"engine.add_strategy(vip10, {})"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-08-25 20:34:47.539362\t开始加载历史数据\n",
"2024-08-25 20:34:47.539362\t加载进度# [0%]\n",
"2024-08-25 20:34:47.747392\t加载进度# [10%]\n",
"2024-08-25 20:34:47.748385\t加载进度## [20%]\n",
"2024-08-25 20:34:47.748385\t加载进度### [30%]\n",
"2024-08-25 20:34:47.749381\t加载进度#### [40%]\n",
"2024-08-25 20:34:47.749381\t加载进度##### [50%]\n",
"2024-08-25 20:34:47.750388\t加载进度###### [60%]\n",
"2024-08-25 20:34:47.750388\t加载进度####### [70%]\n",
"2024-08-25 20:34:47.751394\t加载进度######## [80%]\n",
"2024-08-25 20:34:47.751394\t加载进度######### [90%]\n",
"2024-08-25 20:34:47.751394\t加载进度########## [100%]\n",
"2024-08-25 20:34:47.752372\t历史数据加载完成数据量0\n",
"2024-08-25 20:34:47.752372\t策略初始化完成\n",
"2024-08-25 20:34:47.752372\t开始回放历史数据\n",
"2024-08-25 20:34:47.752372\t历史数据回放结束\n",
"2024-08-25 20:34:47.752372\t开始计算逐日盯市盈亏\n",
"2024-08-25 20:34:47.752372\t回测成交记录为空\n"
]
},
{
"ename": "KeyError",
"evalue": "\"None of ['date'] are in the columns\"",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[1;32mIn[3], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m engine\u001b[38;5;241m.\u001b[39mload_data()\n\u001b[0;32m 2\u001b[0m engine\u001b[38;5;241m.\u001b[39mrun_backtesting()\n\u001b[1;32m----> 3\u001b[0m df \u001b[38;5;241m=\u001b[39m \u001b[43mengine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcalculate_result\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 4\u001b[0m engine\u001b[38;5;241m.\u001b[39mcalculate_statistics()\n\u001b[0;32m 5\u001b[0m engine\u001b[38;5;241m.\u001b[39mshow_chart()\n",
"File \u001b[1;32mc:\\veighna_studio\\lib\\site-packages\\vnpy_ctastrategy\\backtesting.py:283\u001b[0m, in \u001b[0;36mBacktestingEngine.calculate_result\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 280\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m key, value \u001b[38;5;129;01min\u001b[39;00m daily_result\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__dict__\u001b[39m\u001b[38;5;241m.\u001b[39mitems():\n\u001b[0;32m 281\u001b[0m results[key]\u001b[38;5;241m.\u001b[39mappend(value)\n\u001b[1;32m--> 283\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdaily_df \u001b[38;5;241m=\u001b[39m \u001b[43mDataFrame\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_dict\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresults\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_index\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdate\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 285\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moutput(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m逐日盯市盈亏计算完成\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 286\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdaily_df\n",
"File \u001b[1;32mc:\\veighna_studio\\lib\\site-packages\\pandas\\core\\frame.py:6109\u001b[0m, in \u001b[0;36mDataFrame.set_index\u001b[1;34m(self, keys, drop, append, inplace, verify_integrity)\u001b[0m\n\u001b[0;32m 6106\u001b[0m missing\u001b[38;5;241m.\u001b[39mappend(col)\n\u001b[0;32m 6108\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m missing:\n\u001b[1;32m-> 6109\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNone of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmissing\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m are in the columns\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 6111\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m inplace:\n\u001b[0;32m 6112\u001b[0m frame \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\n",
"\u001b[1;31mKeyError\u001b[0m: \"None of ['date'] are in the columns\""
]
}
],
"source": [
"engine.load_data()\n",
"engine.run_backtesting()\n",
"df = engine.calculate_result()\n",
"engine.calculate_statistics()\n",
"engine.show_chart()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"'''用于参数优化'''\n",
"# setting = OptimizationSetting()\n",
"# setting.set_target(\"sharpe_ratio\")\n",
"# setting.add_parameter(\"Length\", 5, 80, 5)\n",
"# setting.add_parameter(\"Offset\", 0.5, 3, 0.5)\n",
"# setting.add_parameter(\"X\", 1, 3, 1)\n",
"# setting.add_parameter(\"TS\", 5, 80, 5)\n",
"# from multiprocessing import cpu_count\n",
"# # 获取 CPU 核心数量\n",
"# num_cores = cpu_count()\n",
"# print(f\"获取 CPU 核心数量:\",round(num_cores/2))\n",
"# engine.run_ga_optimization(setting, max_workers=round(num_cores/2))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"# engine.run_bf_optimization(setting)"
]
},
{
"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.10.9"
},
"vscode": {
"interpreter": {
"hash": "1b43cb0bd93d5abbadd54afed8252f711d4681fe6223ad6b67ffaee289648f85"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -0,0 +1,211 @@
from vnpy_ctastrategy import (
CtaTemplate,
TargetPosTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
import pandas as pd
class vip10(TargetPosTemplate):
""""""
author = "松鼠Quant"
#默认螺纹888 1小时
Length = 50 #布林周期
Offset=2 #标准差倍数倍数
X=2 #过滤均线的Length倍数 范围及步长1-51
TS = 60 #移动止损止盈幅度 参数范围及步长: 5-2005
lots=1 #下单手数
current_bar = 0
Highup=0
Lowdown=0
HigherAfterEntry = float('inf')
LowerAfterEntry = -float('inf')
liQKA = 0
DliqPoint = 0
KliqPoint = 0
OBVValue=[0]
MAOBV=[0]
M2=[0]
cond1=[0]*2
cond2=[0]*2
cond3=[0]*2
kong_cond1=[0]*2
kong_cond2=[0]*2
kong_cond3=[0]*2
MA1=0
MA2=0
MA3=0
BB=0
WIDTH=0
parameters = ["Length",'Offset','X',"TS",'lots']
variables = ["HigherAfterEntry","LowerAfterEntry","liQKA","DliqPoint","KliqPoint"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
""""""
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
#df: pd.DataFrame = pd.read_csv(r"index_contract.csv")
#self.contracts_sizes = {row.vt_symbol.split('.')[0]: row.contract_size for _, row in df.iterrows()}
self.bg = BarGenerator(self.on_bar)
self.am = ArrayManager(300)
self.pos=0
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.load_bar(1)
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.
"""
self.bg.update_tick(tick)
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
self.cancel_all()
am = self.am
am.update_bar(bar)
if not am.inited:
return
# 如果历史数据还没有初始化完毕,则直接返回
# 注意am 是交易系统中的一个数据管理器,可能用于管理历史数据
# bar 是当前的K线数据其中包含了开盘价、最高价、最低价、收盘价和成交量等信息
self.current_bar=self.current_bar+1 #Bar线计数
#print(bar.datetime,"current_bar:",self.current_bar)
# 如果当前Bar的计数器值小于三倍的Length则直接返回
if(self.current_bar<self.Length*self.X):
return
#中轨
self.MA1=am.ema(self.Length,array=True)
self.MA2=am.ema(self.Length*self.X,array=True)
# #上下轨
self.boll_up, self.boll_down = am.boll(self.Length, self.Offset,array=True)
# 多头开仓条件
self.cond1=self.MA1 if self.MA1[-1]>self.MA1[-2] and am.close_array[-1] > self.MA1[-2] else self.cond1
self.cond2=self.boll_up if self.boll_up[-1] > self.boll_up[-2] and am.high_array[-1] > self.boll_up[-1] else self.cond2
self.cond3=self.MA2 if self.MA2[-1] > self.MA2[-2] and am.close_array[-1] > self.MA2[-1] else self.cond3
# 空头开仓条件
self.kong_cond1=self.MA1 if self.MA1[-1] < self.MA1[-2] and am.close_array[-1] < self.MA1[-2] else self.kong_cond1
self.kong_cond2=self.boll_down if self.boll_down[-1] < self.boll_down[-2] and am.low_array[-1] < self.boll_down[-1] else self.kong_cond2
self.kong_cond3=self.MA2 if self.MA2[-1] < self.MA2[-2] and am.close_array[-1] < self.MA2[-1] else self.kong_cond3
#布林极限BB=(收盘价-布林下轨价格)/(布林上轨价格-布林下轨价格)
self.BB=((am.close_array[-1]-self.boll_down[-1])/(self.boll_up[-1]-self.boll_down[-1]))
#极限宽WIDTH=(布林上轨值-布林下轨值)/布林平均值VIP10用不到这个算法可以自己拓展
self.WIDTH=((self.boll_up[-1]-self.boll_down[-1])/self.boll_up[-1])*100
if self.cond1[-1]>self.cond1[-2] and self.cond2[-1]>self.cond2[-2] and self.cond3[-1]>self.cond3[-2] and self.BB>0.5 :
if self.pos!=1 and bar.high_price>=self.cond2[-1] :
if self.pos == 0:
self.buy(bar.close_price, self.lots)
elif self.pos < 0:
self.cover(bar.close_price, self.lots)
self.buy(bar.close_price, self.lots)
self.liQKA = 1
self.LowerAfterEntry = bar.close_price
if self.kong_cond1[-1]<self.kong_cond1[-2] and self.kong_cond2[-1]<self.kong_cond2[-2] and self.kong_cond3[-1]<self.kong_cond3[-2] and self.BB<0.5 :
if self.pos!=-1 and bar.low_price<=self.kong_cond2[-1] :
if self.pos == 0:
self.short(bar.close_price, self.lots)
elif self.pos > 0:
self.sell(bar.close_price, self.lots)
self.short(bar.close_price, self.lots)
self.liQKA = 1
self.HigherAfterEntry = bar.close_price
#记录入场后的最高价和最低价
if self.pos>0:
#self.HigherAfterEntry = HigherAfterEntry
self.LowerAfterEntry = max(self.LowerAfterEntry, bar.low_price)
elif self.pos<0:
self.HigherAfterEntry = min(self.HigherAfterEntry, bar.high_price)
#self.LowerAfterEntry = LowerAfterEntry
if self.pos == 0:
self.liQKA = 1
else:
self.liQKA = self.liQKA - 0.1
self.liQKA = max(self.liQKA, 0.5)
if self.pos>0:
DliqPoint = self.LowerAfterEntry - ((bar.open_price)*self.TS/1000)*self.liQKA
#print(bar.datetime,"DliqPoint",DliqPoint,"low_price",bar.low_price,"self.LowerAfterEntry",self.LowerAfterEntry)
if self.pos<0:
KliqPoint = self.HigherAfterEntry + ((bar.open_price)*self.TS/1000)*self.liQKA
#print(bar.datetime,"KliqPoint",KliqPoint,"high_price",bar.high_price,"self.HigherAfterEntry",self.HigherAfterEntry)
if (self.pos>0 and bar.low_price <= DliqPoint and DliqPoint>0):
#多头出场
self.sell(bar.close_price, self.lots)
elif (self.pos<0 and bar.high_price > KliqPoint and KliqPoint>0):
#空头出场
self.cover(bar.close_price, self.lots)
self.current_bar += 1
self.put_event()
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

View File

@@ -0,0 +1,263 @@
from vnpy_ctastrategy import (
CtaTemplate,
TargetPosTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
import pandas as pd
import numpy as np
import math
class vip11(TargetPosTemplate):
""""""
author = "松鼠Quant"
#默认螺纹888 1H
length = 15
M=35
smoothingFactor = 0.1
TS = 50 #移动止损止盈幅度 参数范围及步长: 5-2005
lots=1 #下单手数
fastLength = 12
slowLength = 26
MACDLength =9
current_bar = 0
Highup=0
Lowdown=0
HigherAfterEntry = float('inf')
LowerAfterEntry = -float('inf')
liQKA = 0
DliqPoint = 0
KliqPoint = 0
OBVValue=[0]
MAOBV=[0]
M2=[0]
cond1=[0]*2
cond2=[0]*2
cond3=[0]*2
kong_cond1=[0]*2
kong_cond2=[0]*2
kong_cond3=[0]*2
MACDValue=[0]*3
normalizedMACD=[1]*3
smoothedMACD=[1]*3
smoothedNormalizedMACD=[1]*3
STCValue=[1]*3
MA1=0
MA2=0
MA3=0
gobro=0
parameters = ["length",'M','smoothingFactor',"TS",'lots']
variables = ["HigherAfterEntry","LowerAfterEntry","liQKA","DliqPoint","KliqPoint"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
""""""
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
#df: pd.DataFrame = pd.read_csv(r"index_contract.csv")
#self.contracts_sizes = {row.vt_symbol.split('.')[0]: row.contract_size for _, row in df.iterrows()}
self.bg = BarGenerator(self.on_bar)
self.am = ArrayManager(300)
self.pos=0
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.load_bar(1)
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.
"""
self.bg.update_tick(tick)
def calculate_con(self,Price1, Price2, Length):
Matches = 0
Price2=Price2-Length
Price2list=[]
Price2list.extend([Price2 + j for j in range(1, Length)]) # 使用extend将元素添加到列表中
# 检查是否有足够的数据进行计算
if len(Price1) < Length :
return 0
else:
for i in range(1,Length-1):
# 计算Con条件
if (Price1[i] >= Price1[i-1] and Price2list[i] >= Price2list[i-1]) or \
(Price1[i] < Price1[i-1] and Price2list[i] < Price2list[i-1]):
Matches += 1
# 计算结果并返回
return 2 * Matches / Length - 1
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
self.cancel_all()
am = self.am
am.update_bar(bar)
if not am.inited:
return
# 如果历史数据还没有初始化完毕,则直接返回
# 注意am 是交易系统中的一个数据管理器,可能用于管理历史数据
# bar 是当前的K线数据其中包含了开盘价、最高价、最低价、收盘价和成交量等信息
self.current_bar=self.current_bar+1 #Bar线计数
#print(bar.datetime,"current_bar:",self.current_bar)
# 如果当前Bar的计数器值小于self.M*2
if(self.current_bar<self.M*2):
return
#均线
self.MA1=am.ema(self.M,array=True)
self.MA2=am.ema(self.M*2,array=True)
# 如果当前Bar的计数器值小于self.MACDLength
if(self.current_bar<self.MACDLength):
return
a1 = 2 / (self.fastLength + 1)
a2 = 2 / (self.slowLength + 1)
# 计算相关系数
r2 = 0.5 * math.pow(self.calculate_con(am.close_array[-self.MACDLength:], self.current_bar, self.MACDLength), 2) + 0.5
kk = r2 * ((1 - a1) * (1 - a2)) + (1 - r2) * ((1 - a1) / (1 - a2))
# 计算MACD值
self.MACDValue.append((am.close_array[-1] - am.close_array[-2]) * (a1 - a2) + (-a2 - a1 + 2) * self.MACDValue[-1] - kk * self.MACDValue[-2])
# 如果当前Bar的计数器值小于self.fastLength
if(self.current_bar<self.fastLength):
return
lowestMACD = min(self.MACDValue[-self.fastLength:])
highestMACD = max(self.MACDValue[-self.fastLength:]) - lowestMACD
# 归一化MACD
self.normalizedMACD.append((self.MACDValue[-1] - lowestMACD) / highestMACD * 100 if highestMACD > 0 else self.normalizedMACD[-1])
# 平滑MACD
self.smoothedMACD.append(self.normalizedMACD[-1] if self.smoothedMACD[-1]==1 else self.smoothedMACD[-2] + self.smoothingFactor * (self.normalizedMACD[-1] - self.smoothedMACD[-2]))
# 计算平滑后MACD的最低值和最高值
lowestSmoothedMACD = min(self.smoothedMACD[-self.fastLength:])
highestSmoothedMACD = max(self.smoothedMACD[-self.fastLength:]) - lowestSmoothedMACD
# 归一化平滑后MACD
self.smoothedNormalizedMACD.append((self.smoothedMACD[-1] - lowestSmoothedMACD) / highestSmoothedMACD * 100 if highestSmoothedMACD > 0 else self.smoothedNormalizedMACD[-1])
# 平滑归一化后MACD得到STC值
self.STCValue.append(self.smoothedNormalizedMACD[-1] if self.STCValue[-1]==1 else self.STCValue[-2] + self.smoothingFactor * (self.smoothedNormalizedMACD[-1] - self.STCValue[-2]))
STCvalue1=round(self.STCValue[-1]-50,0)
STCvalue2=round(self.STCValue[-2]-50,0)
STCvalue3=round(self.STCValue[-3]-50,0)
# 如果当前Bar的计数器值小于self.fastLength
if(self.current_bar<self.length):
return
Highup=max(am.high_array[-self.length:-1])
Lowdown=min(am.low_array[-self.length:-1])
#/*开平仓条件代码-----------------------------------------------------------------------------------------------------------------------------------*/
cond1=STCvalue1>STCvalue2 and STCvalue3>=STCvalue2
cond2=STCvalue1<STCvalue2 and STCvalue3<=STCvalue2
cond3=self.MA1[-1]>self.MA2[-1] and am.close_array[-1]>self.MA2[-1]
cond4=self.MA1[-1]<self.MA2[-1] and am.close_array[-1]<self.MA2[-1]
if cond1:
self.gobro=1
if cond2:
self.gobro=-1
if self.pos!=1 and self.gobro==1 and bar.high_price>=Highup and STCvalue1<0 and cond3==True:
if self.pos == 0:
self.buy(bar.close_price, self.lots)
elif self.pos < 0:
self.cover(bar.close_price, self.lots)
self.buy(bar.close_price, self.lots)
self.liQKA = 1
self.LowerAfterEntry = bar.close_price
if self.pos!=-1 and self.gobro==-1 and bar.low_price<=Lowdown and STCvalue1>0 and cond4==True :
if self.pos == 0:
self.short(bar.close_price, self.lots)
elif self.pos > 0:
self.sell(bar.close_price, self.lots)
self.short(bar.close_price, self.lots)
self.liQKA = 1
self.HigherAfterEntry = bar.close_price
#记录入场后的最高价和最低价
if self.pos>0:
#self.HigherAfterEntry = HigherAfterEntry
self.LowerAfterEntry = max(self.LowerAfterEntry, bar.low_price)
elif self.pos<0:
self.HigherAfterEntry = min(self.HigherAfterEntry, bar.high_price)
#self.LowerAfterEntry = LowerAfterEntry
if self.pos == 0:
self.liQKA = 1
else:
self.liQKA = self.liQKA - 0.1
self.liQKA = max(self.liQKA, 0.5)
if self.pos>0:
DliqPoint = self.LowerAfterEntry - ((bar.open_price)*self.TS/1000)*self.liQKA
#print(bar.datetime,"DliqPoint",DliqPoint,"low_price",bar.low_price,"self.LowerAfterEntry",self.LowerAfterEntry)
if self.pos<0:
KliqPoint = self.HigherAfterEntry + ((bar.open_price)*self.TS/1000)*self.liQKA
#print(bar.datetime,"KliqPoint",KliqPoint,"high_price",bar.high_price,"self.HigherAfterEntry",self.HigherAfterEntry)
if (self.pos>0 and bar.low_price <= DliqPoint and DliqPoint>0):
#多头出场
self.sell(bar.close_price, self.lots)
self.gobro=0
elif (self.pos<0 and bar.high_price > KliqPoint and KliqPoint>0):
#空头出场
self.cover(bar.close_price, self.lots)
self.gobro=0
self.current_bar += 1
self.put_event()
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -0,0 +1,158 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"from datetime import datetime\n",
"\n",
"from vnpy.trader.optimize import OptimizationSetting\n",
"from vnpy_ctastrategy.backtesting import BacktestingEngine\n",
"# from vnpy_ctastrategy.strategies.vip13 import vip13\n",
"from vip13 import vip13"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"engine = BacktestingEngine()\n",
"engine.set_parameters(\n",
" vt_symbol=\"rbJQ00.SHFE\",\n",
" interval=\"1h\",\n",
" start=datetime(2020, 1, 1),\n",
" end=datetime(2024, 3, 21),\n",
" rate=1.5/10000,\n",
" slippage=1,\n",
" size=10,\n",
" pricetick=1,\n",
" capital=1_000_00,\n",
")\n",
"engine.add_strategy(vip13, {})"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2025-01-30 22:14:21.167367\t开始加载历史数据\n",
"2025-01-30 22:14:21.167367\t加载进度# [0%]\n",
"2025-01-30 22:14:21.167367\t加载进度# [10%]\n",
"2025-01-30 22:14:21.167367\t加载进度## [20%]\n",
"2025-01-30 22:14:21.167367\t加载进度### [30%]\n",
"2025-01-30 22:14:21.167367\t加载进度#### [40%]\n",
"2025-01-30 22:14:21.167367\t加载进度##### [50%]\n",
"2025-01-30 22:14:21.167367\t加载进度###### [60%]\n",
"2025-01-30 22:14:21.167367\t加载进度####### [70%]\n",
"2025-01-30 22:14:21.167367\t加载进度######## [80%]\n",
"2025-01-30 22:14:21.167367\t加载进度######### [90%]\n",
"2025-01-30 22:14:21.167367\t加载进度########## [100%]\n",
"2025-01-30 22:14:21.167367\t历史数据加载完成数据量0\n",
"2025-01-30 22:14:21.167367\t策略初始化完成\n",
"2025-01-30 22:14:21.167367\t开始回放历史数据\n",
"2025-01-30 22:14:21.167367\t历史数据回放结束\n",
"2025-01-30 22:14:21.167367\t开始计算逐日盯市盈亏\n",
"2025-01-30 22:14:21.167367\t回测成交记录为空\n"
]
},
{
"ename": "KeyError",
"evalue": "\"None of ['date'] are in the columns\"",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[1;32mIn[10], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m engine\u001b[38;5;241m.\u001b[39mload_data()\n\u001b[0;32m 2\u001b[0m engine\u001b[38;5;241m.\u001b[39mrun_backtesting()\n\u001b[1;32m----> 3\u001b[0m df \u001b[38;5;241m=\u001b[39m \u001b[43mengine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcalculate_result\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 4\u001b[0m engine\u001b[38;5;241m.\u001b[39mcalculate_statistics()\n\u001b[0;32m 5\u001b[0m engine\u001b[38;5;241m.\u001b[39mshow_chart()\n",
"File \u001b[1;32mc:\\veighna_studio\\lib\\site-packages\\vnpy_ctastrategy\\backtesting.py:288\u001b[0m, in \u001b[0;36mBacktestingEngine.calculate_result\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 285\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m key, value \u001b[38;5;129;01min\u001b[39;00m daily_result\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__dict__\u001b[39m\u001b[38;5;241m.\u001b[39mitems():\n\u001b[0;32m 286\u001b[0m results[key]\u001b[38;5;241m.\u001b[39mappend(value)\n\u001b[1;32m--> 288\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdaily_df \u001b[38;5;241m=\u001b[39m \u001b[43mDataFrame\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_dict\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresults\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_index\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdate\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 290\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moutput(_(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m逐日盯市盈亏计算完成\u001b[39m\u001b[38;5;124m\"\u001b[39m))\n\u001b[0;32m 291\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdaily_df\n",
"File \u001b[1;32mc:\\veighna_studio\\lib\\site-packages\\pandas\\core\\frame.py:6109\u001b[0m, in \u001b[0;36mDataFrame.set_index\u001b[1;34m(self, keys, drop, append, inplace, verify_integrity)\u001b[0m\n\u001b[0;32m 6106\u001b[0m missing\u001b[38;5;241m.\u001b[39mappend(col)\n\u001b[0;32m 6108\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m missing:\n\u001b[1;32m-> 6109\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNone of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmissing\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m are in the columns\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 6111\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m inplace:\n\u001b[0;32m 6112\u001b[0m frame \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\n",
"\u001b[1;31mKeyError\u001b[0m: \"None of ['date'] are in the columns\""
]
}
],
"source": [
"engine.load_data()\n",
"engine.run_backtesting()\n",
"df = engine.calculate_result()\n",
"engine.calculate_statistics()\n",
"engine.show_chart()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"# '''用于参数优化'''\n",
"# setting = OptimizationSetting()\n",
"# setting.set_target(\"sharpe_ratio\")\n",
"# setting.add_parameter(\"boll_n\", 5, 60, 5)\n",
"# setting.add_parameter(\"offset\", 0.5,3, 0.5)\n",
"# setting.add_parameter(\"trailing_stop_rate\", 5, 100, 5)\n",
"# setting.add_parameter(\"x\", 5, 80, 5)\n",
"# from multiprocessing import cpu_count\n",
"# # 获取 CPU 核心数量\n",
"# num_cores = cpu_count()\n",
"# print(f\"获取 CPU 核心数量:\",round(num_cores/2))\n",
"# engine.run_ga_optimization(setting, max_workers=round(num_cores/2))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"# engine.run_bf_optimization(setting)"
]
},
{
"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.10.9"
},
"vscode": {
"interpreter": {
"hash": "1b43cb0bd93d5abbadd54afed8252f711d4681fe6223ad6b67ffaee289648f85"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -0,0 +1,116 @@
from vnpy_ctastrategy import (
CtaTemplate,
TargetPosTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
import numpy as np
class vip13(CtaTemplate):
author = "松鼠Quant"
boll_n = 20
offset = 1.5
trailing_stop_rate =60
x = 30
rsi_n = 14
over_sold = 30
over_bought = 70
parameters = ["boll_n", "offset", "trailing_stop_rate", "x"]
variables = ["lots", "up_line", "down_line", "mid_line", "band", "rsi_value", "kg", "highest_low_after_entry", "lowest_high_after_entry", "rsi_n", "over_sold", "over_bought"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
""""""
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.lots = 0
self.up_line = 0
self.down_line = 0
self.mid_line = 0
self.band = 0
self.rsi_value = 0
self.kaiduo = False
self.kaikong = False
self.kg = 0
self.highest_low_after_entry = 0
self.lowest_high_after_entry = 0
self.bg = BarGenerator(self.on_bar)
self.am = ArrayManager(300)
self.pos=0
def on_init(self):
self.write_log("策略初始化")
self.load_bar(10)
def on_start(self):
self.write_log("策略启动")
def on_stop(self):
self.write_log("策略停止")
def on_tick(self, tick: TickData):
pass
def on_bar(self, bar: BarData):
self.am.update_bar(bar)
if not self.am.inited:
return
self.lots = 1
self.calculate_boll()
self.calculate_rsi()
self.kaikong = self.rsi_value > self.over_bought and self.am.close[-1] < self.up_line
self.kaiduo = self.rsi_value < self.over_sold and self.am.close[-1] > self.down_line
if self.kaiduo:
self.kg = 1
self.hd = self.am.high[-self.x:-1].max()
if self.kaikong:
self.kg = -1
self.ld = self.am.low[-self.x:-1].min()
if self.pos != 1 and self.kg == 1 and bar.close_price >= self.hd :
self.buy(bar.close_price, self.lots)
self.highest_low_after_entry = bar.close_price
self.pos=1
if self.pos != -1 and self.kg == -1 and bar.close_price <= self.ld:
self.short(bar.close_price, self.lots)
self.lowest_high_after_entry = bar.close_price
self.pos=-1
self.trailing_stop(bar)
self.put_event()
def calculate_boll(self):
self.mid_line = self.am.sma(self.boll_n)
self.band = self.am.std(self.boll_n)
self.up_line = self.mid_line + self.offset * self.band
self.down_line = self.mid_line - self.offset * self.band
def calculate_rsi(self):
self.rsi_value = self.am.rsi(self.rsi_n)
def trailing_stop(self, bar: BarData):
if self.pos > 0:
self.highest_low_after_entry = max(self.highest_low_after_entry, bar.low_price)
dliq_point = self.highest_low_after_entry - bar.open_price * (self.trailing_stop_rate/1000)
if bar.close_price < dliq_point:
self.sell(bar.close_price, self.lots)
self.pos=0
if self.pos < 0:
self.lowest_high_after_entry = min(self.lowest_high_after_entry, bar.high_price)
kliq_point = self.lowest_high_after_entry + bar.open_price * (self.trailing_stop_rate/1000)
if bar.close_price > kliq_point:
self.cover(bar.close_price, self.lots)
self.pos=0

View File

@@ -0,0 +1,155 @@
from vnpy_ctastrategy import (
CtaTemplate,
TargetPosTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
import numpy as np
import numpy as np
import talib
class vip15(CtaTemplate):
author = "quant789.com"
period = 5
pds = 24
trailing_stop_rate = 65
lots = 1
kg = 0
parameters = ["period", "pds", "trailing_stop_rate", "lots"]
variables = ["sdo_value", "lots", "barcout", "kg", "dd", "ss"]
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)
self.am = ArrayManager(300) # Adjust size as needed
self.sdo_array = 0
self.barcout = 0
self.dd = 0
self.ss = 0
self.over_bought = 40
self.over_sold = -40
self.lb_period = 50
self.highest_low_after_entry = 0
self.lowest_high_after_entry = 0
self.liq_ka = 1
self.dliq_point = 0
self.kliq_point = 0
self.ent_bar = 0
self.ent_price = 0
def calculate_sdo(self):
if len(self.am.close_array) < self.lb_period:
return []
close = self.am.close_array
dist = np.abs(close - np.roll(close, self.period))
lowest_dist = np.minimum.accumulate(dist[::-1])[::-1]
highest_dist = np.maximum.accumulate(dist[::-1])[::-1]
# 避免除以零
denom = highest_dist - lowest_dist
denom[denom == 0] = 1e-10 # 将零值替换为一个很小的数
dval = np.where(denom != 0, (dist - lowest_dist) / denom, 0)
ddval = np.zeros_like(dval)
ddval[close > np.roll(close, self.period)] = dval[close > np.roll(close, self.period)]
ddval[close < np.roll(close, self.period)] = -dval[close < np.roll(close, self.period)]
sdo = np.convolve(ddval, np.ones(self.pds), 'valid') / self.pds * 100
return sdo
def on_init(self):
self.write_log("策略初始化")
self.load_bar(10)
def on_start(self):
self.write_log("策略启动")
def on_stop(self):
self.write_log("策略停止")
def on_tick(self, tick: TickData):
self.bg.update_tick(tick)
def on_bar(self, bar: BarData):
self.am.update_bar(bar)
if not self.am.inited:
return
self.sdo_array = self.calculate_sdo()
cond1 = self.sdo_array[-2] > self.over_bought and self.sdo_array[-1] <= self.over_bought
cond2 = self.sdo_array[-2] < self.over_sold and self.sdo_array[-1] >= self.over_sold
hh = self.am.high_array[-self.period:].max()
ll = self.am.low_array[-self.period:].min()
if cond1==True or cond2==True:
self.dd = hh
self.ss = ll
self.kg = 1
self.barcout = 0
if self.kg > 0:
self.barcout += 1
if self.barcout > self.pds:
self.barcout = 0
self.dd = 0
self.ss = 0
self.kg = 0
if self.kg > 0 and bar.high_price >= self.dd and self.dd>0 : #
self.buy(bar.close_price, self.lots)
self.kg = 0
self.barcout = 0
self.highest_low_after_entry = bar.close_price
self.initialize_vars_on_entry(bar)
if self.kg > 0 and bar.low_price <= self.ss and self.ss>0 : #
self.short(bar.close_price, self.lots)
self.kg = 0
self.barcout = 0
self.lowest_high_after_entry = bar.close_price
self.initialize_vars_on_entry(bar)
else:
self.trailing_stop(bar)
self.put_event()
def trailing_stop(self, bar: BarData):
if self.pos > 0:
self.highest_low_after_entry = max(self.highest_low_after_entry, bar.low_price)
self.dliq_point = self.highest_low_after_entry - (bar.open_price * self.trailing_stop_rate / 10000) * self.liq_ka
if bar.low_price <= self.dliq_point and bar.datetime.timestamp() > self.ent_bar:
self.sell(bar.close_price , abs(self.pos))
elif self.pos < 0:
self.lowest_high_after_entry = min(self.lowest_high_after_entry, bar.high_price)
self.kliq_point = self.lowest_high_after_entry + (bar.open_price * self.trailing_stop_rate / 10000) * self.liq_ka
if bar.high_price >= self.kliq_point and bar.datetime.timestamp() > self.ent_bar:
self.cover(bar.close_price , abs(self.pos))
def initialize_vars_on_entry(self, bar: BarData):
self.ent_bar = bar.datetime.timestamp()
self.ent_price = bar.close_price
self.liq_ka = 1
def on_order(self, order: OrderData):
pass
def on_stop_order(self, stop_order: StopOrder):
pass

View File

@@ -0,0 +1,7 @@
ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>VIP15<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>.rar
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://pan.baidu.com/s/1liwdmvmGJ7wjHWVewZUUWA?pwd=7777 <20><>ȡ<EFBFBD><C8A1>: 7777
--<2D><><EFBFBD>԰ٶ<D4B0><D9B6><EFBFBD><EFBFBD>̳<EFBFBD><CCB3><EFBFBD><EFBFBD><EFBFBD>Աv7<76>ķ<EFBFBD><C4B7><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><EFBFBD><EFBFBD>ϵС<EFBFBD><EFBFBD><EFBFBD><EFBFBD>΢<EFBFBD>ţ<EFBFBD>viquant01
quant789.com<6F><6D><EFBFBD><EFBFBD>ʹ<EFBFBD>ò<EFBFBD><C3B2><EFBFBD>ѡȡ<D1A1><C8A1><EFBFBD><EFBFBD>

View File

@@ -0,0 +1,226 @@
from vnpy_ctastrategy import (
CtaTemplate,
TargetPosTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
import numpy as np
import talib
class vip16(CtaTemplate):
"""
自适应高斯移动平均策略
"""
author = "Your Name"
# 策略参数
length = 65 # 计算周期
ends = 25 # 计算结束点
x = 0.9 # 自适应系数
trailing_stop_rate = 45 # 跟踪止损率
lots = 1 # 交易手数
# 策略变量
volatility_period = 20 # 自适应周期
volatility_std = 1.0 # 波动率标准差
adaptive = True # 是否自适应
current_agma=[]
parameters = ["length", "ends", "x", "trailing_stop_rate", "lots"]
variables = ["volatility_period", "volatility_std", "adaptive"]
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)
self.am = ArrayManager(size=100) # 确保大小足够存储所需数据
# 初始化变量
self.agma = 0
self.score = 0
self.re_score=0
self.long_cout = 0
self.short_cout = 0
self.total_l = 0
self.total_s = 0
self.loss_long_x = 0.1
self.loss_short_x = 0.1
self.highest_low_after_entry = 0
self.lowest_high_after_entry = 0
self.ent_bar = 0
self.current_bar = 0
self.kg = 0
self.Long_jiasu_kg=False
self.Short_jiasu_kg=False
def calculate_agma(self):
"""计算自适应高斯移动平均"""
if not self.am.inited:
return 0
# 计算标准差
if self.adaptive:
sigma = self.am.std(self.volatility_period)
else:
sigma = self.volatility_std
sum_weights = 0
agma = 0
for i in range(self.length):
# 计算高斯权重
weight = np.exp(-((i - (self.length - 1)) / (2 * sigma)) ** 2 / 2)
# 计算最高价和最低价的和
high = self.am.high_array[-(i+1)]
low = self.am.low_array[-(i+1)]
value = high + low
agma += value * weight
sum_weights += weight
return (agma / sum_weights) / 2
def calculate_score(self):
"""计算信号得分"""
if not self.am.inited:
return 0, 0,0,0
re_score=self.score
score = 0
long_cout = 0
short_cout = 0
self.current_agma.append(self.calculate_agma())
if len(self.current_agma)<self.ends + 1:
return score, long_cout, short_cout,re_score
for j in range(1, self.ends + 1):
# 计算AGMA比较得分
if self.current_agma[-1] > self.current_agma[-j]:
score += 1
else:
score -= 1
# 计算多空累计得分
if self.am.close_array[-j] > self.am.open_array[-j]:
long_cout += abs(self.am.close_array[-j] - self.am.open_array[-j])
else:
short_cout += abs(self.am.open_array[-j] - self.am.close_array[-j])
return score, long_cout, short_cout,re_score
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("策略启动")
def on_stop(self):
"""
Callback when strategy is stopped.
"""
self.write_log("策略停止")
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.am.update_bar(bar)
if not self.am.inited:
return
# 更新当前bar计数
self.current_bar += 1
# 计算信号相关指标
self.score, self.long_cout, self.short_cout,self.re_score = self.calculate_score()
if self.long_cout + self.short_cout > 0:
self.total_l = self.long_cout / (self.long_cout + self.short_cout)
self.total_s = self.short_cout / (self.long_cout + self.short_cout)
# 生成交易信号
long_signal = self.score > 20 and self.re_score <= 20 # 上穿20
short_signal = self.score < -20 and self.re_score >= -20 # 下穿-20
if long_signal:
self.kg = 1
elif short_signal:
self.kg = -1
# 计算过去ends周期的最高最低价
hhv = self.am.high_array[-self.ends:].max()
llv = self.am.low_array[-self.ends:].min()
# 入场逻辑
if self.kg == 1 and bar.high_price >= hhv and not self.pos:
self.buy(max(bar.open_price, hhv), self.lots)
self.highest_low_after_entry = max(bar.open_price, hhv)
self.ent_bar = self.current_bar
elif self.kg == -1 and bar.low_price <= llv and not self.pos:
self.short(min(bar.open_price, llv), self.lots)
self.lowest_high_after_entry = min(bar.open_price, llv)
self.ent_bar = self.current_bar
# 更新止损系数
if not self.pos:
self.loss_long_x = 1
self.loss_short_x = 1
self.Long_jiasu_kg=False
self.Short_jiasu_kg=False
else:
if self.total_l >= self.x:
if self.Long_jiasu_kg==False:
self.loss_long_x=self.x
self.Long_jiasu_kg=True
else:
self.loss_long_x = max(self.loss_long_x, self.total_l)
if self.total_s >= self.x:
if self.Short_jiasu_kg==False:
self.loss_short_x=self.x
self.Short_jiasu_kg=True
else:
self.loss_short_x = max(self.loss_short_x, self.total_s)
# 更新跟踪止损价位
if self.pos > 0:
if self.current_bar > self.ent_bar:
self.highest_low_after_entry = max(self.highest_low_after_entry, bar.low_price)
dliq_point = self.highest_low_after_entry - (bar.open_price * self.trailing_stop_rate/1000) * 1 if self.loss_long_x==1 else 1 - self.loss_long_x
if bar.low_price <= dliq_point:
self.sell(min(bar.open_price, dliq_point), abs(self.pos))
elif self.pos < 0:
if self.current_bar > self.ent_bar:
self.lowest_high_after_entry = min(self.lowest_high_after_entry, bar.high_price)
kliq_point = self.lowest_high_after_entry + (bar.open_price * self.trailing_stop_rate/1000) * 1 if self.loss_short_x==1 else 1 - self.loss_short_x
if bar.high_price >= kliq_point:
self.cover(max(bar.open_price, kliq_point), abs(self.pos))
self.put_event()

View File

@@ -0,0 +1,7 @@
ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>VIP15<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>.rar
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://pan.baidu.com/s/1liwdmvmGJ7wjHWVewZUUWA?pwd=7777 <20><>ȡ<EFBFBD><C8A1>: 7777
--<2D><><EFBFBD>԰ٶ<D4B0><D9B6><EFBFBD><EFBFBD>̳<EFBFBD><CCB3><EFBFBD><EFBFBD><EFBFBD>Աv7<76>ķ<EFBFBD><C4B7><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><EFBFBD><EFBFBD>ϵС<EFBFBD><EFBFBD><EFBFBD><EFBFBD>΢<EFBFBD>ţ<EFBFBD>viquant01
quant789.com<6F><6D><EFBFBD><EFBFBD>ʹ<EFBFBD>ò<EFBFBD><C3B2><EFBFBD>ѡȡ<D1A1><C8A1><EFBFBD><EFBFBD>

View File

@@ -0,0 +1,65 @@
### 自适应高斯移动平均策略 (VIP16) 介绍
#### 策略概述
自适应高斯移动平均策略 (VIP16) 是一种基于市场波动性和价格行为的量化交易策略。该策略通过计算自适应高斯移动平均 (AGMA) 来识别市场的趋势,并结合信号得分 (Score) 来生成交易信号。策略的核心思想是通过动态调整标准差 (Sigma) 来适应市场的波动性,从而提高策略的适应性和稳定性。
#### 策略原理
1. **自适应高斯移动平均 (AGMA) 计算**
- 使用自适应的标准差 Sigma 来计算高斯移动平均。标准差可以根据市场波动性自适应调整,或者使用固定的标准差。
- 通过循环计算每个周期的权重和加权平均值,得到自适应高斯移动平均 AGMA。
2. **信号得分 (Score) 计算**
- 通过比较当前 AGMA 与过去 Ends 个周期的 AGMA 值,计算信号得分 Score。得分越高表示多头信号越强得分越低表示空头信号越强。
- 同时计算多头和空头的累计得分 LongCout 和 ShortCout用于后续的入场和出场逻辑。
3. **交易信号生成**
- 当 Score 上穿 20 时,生成多头信号 LongSignal。
- 当 Score 下穿 -20 时,生成空头信号 ShortSignal。
4. **入场条件**
- 当多头信号 LongSignal 为真且当前价格高于过去 Ends 个周期的最高价 HHV并且当前没有多头持仓时买入。
- 当空头信号 ShortSignal 为真且当前价格低于过去 Ends 个周期的最低价 LLV并且当前没有空头持仓时卖出。
5. **跟踪止损逻辑**
- 根据持仓状态和市场波动性,动态调整跟踪止损点 DliqPoint 和 KliqPoint。
- 当多头持仓时,如果价格低于跟踪止损点 DliqPoint则卖出平仓。
- 当空头持仓时,如果价格高于跟踪止损点 KliqPoint则买入平仓。
6. **图形绘制**
- 使用 plt0 和 plt1 绘制多头和空头的跟踪止损点。
- 使用 plt2 绘制信号得分 Score。
#### 策略参数
- **Length**:计算周期,用于计算自适应高斯移动平均。
- **Ends**:计算结束点,用于计算信号得分。
- **X**:自适应系数,用于调整标准差。
- **TrailingStopRate**:跟踪止损率,用于计算跟踪止损点。
- **Fund**:投入保证金,用于计算交易手数。
#### 策略优势
- **自适应性**:通过动态调整标准差 Sigma策略能够适应不同市场环境下的波动性。
- **稳定性**:结合信号得分和跟踪止损逻辑,策略能够在不同市场条件下保持稳定的盈利能力。
- **灵活性**:策略支持多头和空头交易,能够在不同市场趋势下进行交易。
#### 策略应用
自适应高斯移动平均策略 (VIP16) 适用于多种交易品种和时间周期,特别适合追求稳定盈利的量化交易者。通过合理的参数设置和风险管理,该策略能够在不同市场环境下实现稳定的收益。
#### 风险提示
量化交易策略存在一定的风险,包括但不限于市场风险、模型风险和执行风险。建议用户在使用该策略前进行充分的历史回测和模拟交易,并根据自身风险承受能力进行调整。
#### 变量介绍
- **losslongX**:多头止损系数,用于动态调整多头持仓的跟踪止损点。该系数根据多头累计得分 totalL 进行更新,确保在多头信号较强时,止损点能够更紧密地跟随价格。
- **lossShortX**:空头止损系数,用于动态调整空头持仓的跟踪止损点。该系数根据空头累计得分 totalS 进行更新,确保在空头信号较强时,止损点能够更紧密地跟随价格。
这两个变量的引入使得策略能够根据市场信号的强弱动态调整止损点,从而更好地控制风险和保护利润。
---
由 Ai 生成的内容仅作为学习参考,不能保证正确性,不构成任何投资意见,风险自负。

View File

@@ -0,0 +1,273 @@
//------------------------------------------------------------------------
// <20><><EFBFBD><EFBFBD>: VIP17_duo
// <20><><EFBFBD><EFBFBD>: VIP17_duo
// <20><><EFBFBD><EFBFBD>: <20><>ʽӦ<CABD><D3A6>
// <20><><EFBFBD><EFBFBD>: <20>û<EFBFBD>Ӧ<EFBFBD><D3A6>
// <20><><EFBFBD><EFBFBD>: Void
//------------------------------------------------------------------------
Params
Numeric Fund(20000); // Ͷ<>뱣֤<EBB1A3><D6A4>
Vars
Numeric Lots(0); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Numeric totalScore(5); // <20><><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>Ŀǰ<C4BF><C7B0><EFBFBD>ǵ<EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>ܹ<EFBFBD>6<EFBFBD><36>ָ<EFBFBD>꼰6<EABCB0>֡<EFBFBD>
Numeric rpmPeriod(14); // RPM Period
Numeric bboPeriod(16); // BBO Period
Numeric macdFastPeriod(12); // MACD Fast Period
Numeric macdSlowPeriod(24); // MACD Slow Period
Numeric macdSignalPeriod(9); // MACD Signal Period
Numeric rsiPeriod(14); // RSI Period
Numeric cciPeriod(14); // CCI Period
Numeric stochasticKLength(14); // Stochastic %K Length
Numeric stochasticKSmoothing(1); // Stochastic %K Smoothing
Numeric stochasticDSmoothing(3); // Stochastic %D Smoothing
Numeric supertrendPeriod(10); // SUPERTREND Period
Numeric supertrendFactor(2); // SUPERTREND Factor
Series<Numeric> rpmValue; // RPM Value
Series<Numeric> bboValue; // BBO Value
Series<Numeric> macdValue; // MACD Value
Series<Numeric> macdSignal; // MACD Signal Line
Series<Numeric> macdHist; // MACD Histogram
Series<Numeric> rsiValue; // RSI Value
Series<Numeric> stochasticValue; // Stochastic Value
Series<Numeric> cciValue; // CCI Value
Series<Numeric> supertrendValue; // SUPERTREND Value
Series<Numeric> netChgAvg ;
Series<Numeric> totChgAvg ;
Series<Numeric> score;
Numeric EntryStrength(90); // <20><><EFBFBD><EFBFBD>ǿ<EFBFBD>ȵĽ<C8B5><C4BD><EFBFBD>ֵ
Numeric Length(5); // ǿ<><C7BF>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
Series<Numeric> CloseChange; // <20><><EFBFBD>̼۱䶯ֵ
Numeric i; // ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD>Ʊ<EFBFBD><C6B1><EFBFBD>
Numeric UpCloses; // <20><><EFBFBD>̼<EFBFBD><CCBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۼ<EFBFBD>ֵ
Numeric DnCloses; // <20><><EFBFBD>̼<EFBFBD><CCBC>µ<EFBFBD><C2B5>ۼ<EFBFBD>ֵ
Numeric SumChange; // <20><><EFBFBD>̼۱<DBB1>ۼ<EFBFBD>ֵ
Series<Numeric> MarketStrength; // <20>г<EFBFBD>ǿ<EFBFBD><C7BF>ָ<EFBFBD><D6B8>
Plot plt1; // <20><><EFBFBD>ڻ<EFBFBD>ͼ<EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD>
Events
OnInit()
{
Range[0:DataCount-1]
{
//=========<3D><><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>==============
AddDataFlag(Enum_Data_RolloverBackWard()); //<2F><><EFBFBD>ú<EFBFBD><C3BA><EFBFBD>Ȩ
AddDataFlag(Enum_Data_RolloverRealPrice()); //<2F><><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3><EFBFBD><EFBFBD>ʵ<EFBFBD>۸<EFBFBD>
AddDataFlag(Enum_Data_AutoSwapPosition()); //<2F><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
//AddDataFlag(Enum_Data_IgnoreSwapSignalCalc()); //<2F><><EFBFBD>ú<EFBFBD><C3BA>Ի<EFBFBD><D4BB><EFBFBD><EFBFBD>źż<C5BA><C5BC><EFBFBD>
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>ͼ
plt1.figure(0); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>
plt1.setOption("Score", "width", Enum_7Pix); // <20><>ָ<EFBFBD>ꡰMA1<41><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߿<EFBFBD><DFBF><EFBFBD><EFBFBD><EFBFBD>Ϊ3<CEAA><33><EFBFBD><EFBFBD>
plt1.setOption("Score","color",Blue);
}
OnBar(ArrayRef<Integer> indexs)
{
// <20><><EFBFBD><EFBFBD><E3BDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Lots = Max(1, Round(Fund/(O*ContractUnit*BigPointValue* MarginRatio/rollover), 0));
// <20><><EFBFBD><EFBFBD><EFBFBD>г<EFBFBD>ǿ<EFBFBD><C7BF>ָ<EFBFBD><D6B8>
CloseChange = Close - Close[1];
UpCloses = 0;
DnCloses = 0;
For i = 0 To Length-1
{
// <20><><EFBFBD>̼<EFBFBD><CCBC><EFBFBD><EFBFBD>Ǽ<EFBFBD><C7BC><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7>ۼ<EFBFBD>
If(CloseChange[i] > 0)
UpCloses = UpCloses + CloseChange[i];
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۼ<EFBFBD>
Else
DnCloses = DnCloses + CloseChange[i];
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD>
SumChange = Summation(CloseChange, Length);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD>ȣ<EFBFBD>0-100֮<30><D6AE>
If(SumChange >= 0)
{
MarketStrength = SumChange / UpCloses * 100;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>ǿ<EFBFBD>ȣ<EFBFBD>0-100֮<30><D6AE>
Else
{
MarketStrength = SumChange / Abs(DnCloses) * 100;
}
// <20><><EFBFBD><EFBFBD> MACD ֵ
Numeric emaFast = XAverage(Close, macdFastPeriod);
Numeric emaSlow = XAverage(Close, macdSlowPeriod);
macdValue = emaFast - emaSlow;
macdSignal = XAverage(macdValue, macdSignalPeriod);
macdHist = macdValue - macdSignal;
// <20><><EFBFBD><EFBFBD> RSI ֵ
Numeric SF = 1 / rsiPeriod;
Numeric change = Close - Close[1];
If(CurrentBar <= rsiPeriod - 1)
{
netChgAvg = (Close - Close[rsiPeriod]) / rsiPeriod;
totChgAvg = Average(Abs(Close - Close[1]), rsiPeriod);
}
Else
{
netChgAvg = netChgAvg[1] + SF * (change - netChgAvg[1]);
totChgAvg = totChgAvg[1] + SF * (Abs(change) - totChgAvg[1]);
}
If(totChgAvg <> 0)
{
rsiValue = 50 * (netChgAvg / totChgAvg + 1);
}
Else
{
rsiValue = 50;
}
// <20><><EFBFBD><EFBFBD> Stochastic ֵ
Numeric highestHigh = Highest(High, stochasticKLength);
Numeric lowestLow = Lowest(Low, stochasticKLength);
Numeric stochasticRaw = (Close - lowestLow) / (highestHigh - lowestLow) * 100;
stochasticValue = Average(stochasticRaw, stochasticKSmoothing);
// <20><><EFBFBD><EFBFBD> CCI ֵ
Numeric typicalPrice = (High + Low + Close) / 3;
Numeric smaTypicalPrice = Average(typicalPrice, cciPeriod);
Numeric meanDeviation = Summation(Abs(typicalPrice - smaTypicalPrice), cciPeriod) / cciPeriod;
If(meanDeviation <> 0)
{
cciValue = (typicalPrice - smaTypicalPrice) / (0.015 * meanDeviation);
}
Else
{
cciValue = 0;
}
// <20><><EFBFBD><EFBFBD> SUPERTREND ֵ
Numeric atr = AvgTrueRange(supertrendPeriod);
Numeric basicUpperBand = (High + Low) / 2 + supertrendFactor * atr;
Numeric basicLowerBand = (High + Low) / 2 - supertrendFactor * atr;
Numeric finalUpperBand = IIF(basicUpperBand < supertrendValue[1] || Close[1] > supertrendValue[1], basicUpperBand, supertrendValue[1]);
Numeric finalLowerBand = IIF(basicLowerBand > supertrendValue[1] || Close[1] < supertrendValue[1], basicLowerBand, supertrendValue[1]);
supertrendValue = IIF(Close > supertrendValue[1], finalLowerBand, finalUpperBand);
// <20><><EFBFBD>ö<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>
Bool macdCondition = macdValue > macdSignal;
Bool rsiCondition = rsiValue >50;
Bool stochasticCondition = stochasticValue > 50;
Bool cciCondition = cciValue >0;
Bool supertrendCondition = Close > supertrendValue;
Bool Marketbool = MarketStrength >= EntryStrength;
// <20><><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD>
score = 0;
If(macdCondition)
{
score = score + 1;
}
If(rsiCondition)
{
score = score + 1;
}
If(stochasticCondition)
{
score = score + 1;
}
If(cciCondition)
{
score = score + 1;
}
If(supertrendCondition)
{
score = score + 1;
}
if(Marketbool)
{
score = score + 1;
}
// <20>ڸ<EFBFBD>ͼ<EFBFBD><CDBC>ʾ<EFBFBD>÷<EFBFBD>
Commentary("Score: " + Text(score));
plt1.barv("Score",score);
// <20>ж<EFBFBD><D0B6>Ƿ<EFBFBD><C7B7><EFBFBD><EFB5BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
If(score == totalScore)
{
Commentary("All conditions met!");
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
If(score[1] >= totalScore And MarketPosition == 0 ) //
{
Buy(Lots, Open);
}
// ƽ<><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
If(score[1] == 0 And MarketPosition == 1)
{
Sell(0, Open);
}
// <20>ڸ<EFBFBD>ͼ<EFBFBD><CDBC>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD><EFBFBD>
If(macdCondition)
{
PlotAuto("MACD_Condition",1,1,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("MACD_Condition",1,1,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(rsiCondition)
{
PlotAuto("RSI_Condition",2,2,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("RSI_Condition",2,2,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(stochasticCondition)
{
PlotAuto("Stochastic_Condition", 3,3,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("Stochastic_Condition", 3,3,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(cciCondition)
{
PlotAuto("CCI_Condition", 4,4,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("CCI_Condition", 4,4,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(supertrendCondition)
{
PlotAuto("Supertrend_Condition", 5,5,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("Supertrend_Condition", 5,5,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(Marketbool)
{
PlotAuto("Marketbool", 6,6,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("Marketbool", 6,6,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
}
//------------------------------------------------------------------------
// <20><><EFBFBD><EFBFBD><EFBFBD>汾 2024/11/27 145803
// <20><>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD> songshu123
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> TradeBlazer Software<72><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>TradeBlazerƽ̨
// ÿһ<C3BF><EFBFBD><E6B1BE>TradeBlazer<65><72>ʽ<EFBFBD>޸ĺ<DEB8><C4BA><EFBFBD>д<EFBFBD><D0B4>Ȩ<EFBFBD><C8A8>
//------------------------------------------------------------------------

View File

@@ -0,0 +1,274 @@
//------------------------------------------------------------------------
// <20><><EFBFBD><EFBFBD>: vip17_kong
// <20><><EFBFBD><EFBFBD>: vip17_kong
// <20><><EFBFBD><EFBFBD>: <20><>ʽӦ<CABD><D3A6>
// <20><><EFBFBD><EFBFBD>: <20>û<EFBFBD>Ӧ<EFBFBD><D3A6>
// <20><><EFBFBD><EFBFBD>: Void
//------------------------------------------------------------------------
Params
Numeric Fund(20000); // Ͷ<>뱣֤<EBB1A3><D6A4>
Vars
Numeric Lots(0); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Numeric totalScore(5); // <20><><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>Ŀǰ<C4BF><C7B0><EFBFBD>ǵ<EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>ܹ<EFBFBD>6<EFBFBD><36>ָ<EFBFBD>꼰6<EABCB0>֡<EFBFBD>
Numeric rpmPeriod(14); // RPM Period
Numeric bboPeriod(16); // BBO Period
Numeric macdFastPeriod(12); // MACD Fast Period
Numeric macdSlowPeriod(24); // MACD Slow Period
Numeric macdSignalPeriod(9); // MACD Signal Period
Numeric rsiPeriod(14); // RSI Period
Numeric cciPeriod(14); // CCI Period
Numeric stochasticKLength(14); // Stochastic %K Length
Numeric stochasticKSmoothing(1); // Stochastic %K Smoothing
Numeric stochasticDSmoothing(3); // Stochastic %D Smoothing
Numeric supertrendPeriod(10); // SUPERTREND Period
Numeric supertrendFactor(2); // SUPERTREND Factor
Series<Numeric> rpmValue; // RPM Value
Series<Numeric> bboValue; // BBO Value
Series<Numeric> macdValue; // MACD Value
Series<Numeric> macdSignal; // MACD Signal Line
Series<Numeric> macdHist; // MACD Histogram
Series<Numeric> rsiValue; // RSI Value
Series<Numeric> stochasticValue; // Stochastic Value
Series<Numeric> cciValue; // CCI Value
Series<Numeric> supertrendValue; // SUPERTREND Value
Series<Numeric> netChgAvg ;
Series<Numeric> totChgAvg ;
Series<Numeric> score;
Numeric EntryStrength(90); // <20><><EFBFBD><EFBFBD>ǿ<EFBFBD>ȵĽ<C8B5><C4BD><EFBFBD>ֵ
Numeric Length(5); // ǿ<><C7BF>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
Series<Numeric> CloseChange; // <20><><EFBFBD>̼۱䶯ֵ
Numeric i; // ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD>Ʊ<EFBFBD><C6B1><EFBFBD>
Numeric UpCloses; // <20><><EFBFBD>̼<EFBFBD><CCBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۼ<EFBFBD>ֵ
Numeric DnCloses; // <20><><EFBFBD>̼<EFBFBD><CCBC>µ<EFBFBD><C2B5>ۼ<EFBFBD>ֵ
Numeric SumChange; // <20><><EFBFBD>̼۱<DBB1>ۼ<EFBFBD>ֵ
Series<Numeric> MarketStrength; // <20>г<EFBFBD>ǿ<EFBFBD><C7BF>ָ<EFBFBD><D6B8>
Plot plt1; // <20><><EFBFBD>ڻ<EFBFBD>ͼ<EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD>
Events
OnInit()
{
Range[0:DataCount-1]
{
//=========<3D><><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>==============
AddDataFlag(Enum_Data_RolloverBackWard()); //<2F><><EFBFBD>ú<EFBFBD><C3BA><EFBFBD>Ȩ
AddDataFlag(Enum_Data_RolloverRealPrice()); //<2F><><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3><EFBFBD><EFBFBD>ʵ<EFBFBD>۸<EFBFBD>
AddDataFlag(Enum_Data_AutoSwapPosition()); //<2F><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
//AddDataFlag(Enum_Data_IgnoreSwapSignalCalc()); //<2F><><EFBFBD>ú<EFBFBD><C3BA>Ի<EFBFBD><D4BB><EFBFBD><EFBFBD>źż<C5BA><C5BC><EFBFBD>
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>ͼ
plt1.figure(0); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>
plt1.setOption("Score", "width", Enum_7Pix); // <20><>ָ<EFBFBD>ꡰMA1<41><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߿<EFBFBD><DFBF><EFBFBD><EFBFBD><EFBFBD>Ϊ3<CEAA><33><EFBFBD><EFBFBD>
plt1.setOption("Score","color",Blue);
}
OnBar(ArrayRef<Integer> indexs)
{
// <20><><EFBFBD><EFBFBD><E3BDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Lots = Max(1, Round(Fund/(O*ContractUnit*BigPointValue* MarginRatio/rollover), 0));
// <20><><EFBFBD><EFBFBD><EFBFBD>г<EFBFBD>ǿ<EFBFBD><C7BF>ָ<EFBFBD><D6B8>
CloseChange = Close - Close[1];
UpCloses = 0;
DnCloses = 0;
For i = 0 To Length-1
{
// <20><><EFBFBD>̼<EFBFBD><CCBC><EFBFBD><EFBFBD>Ǽ<EFBFBD><C7BC><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7>ۼ<EFBFBD>
If(CloseChange[i] > 0)
UpCloses = UpCloses + CloseChange[i];
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۼ<EFBFBD>
Else
DnCloses = DnCloses + CloseChange[i];
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD>
SumChange = Summation(CloseChange, Length);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD>ȣ<EFBFBD>0-100֮<30><D6AE>
If(SumChange >= 0)
{
MarketStrength = SumChange / UpCloses * 100;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>ǿ<EFBFBD>ȣ<EFBFBD>0-100֮<30><D6AE>
Else
{
MarketStrength = SumChange / Abs(DnCloses) * 100;
}
// <20><><EFBFBD><EFBFBD> MACD ֵ
Numeric emaFast = XAverage(Close, macdFastPeriod);
Numeric emaSlow = XAverage(Close, macdSlowPeriod);
macdValue = emaFast - emaSlow;
macdSignal = XAverage(macdValue, macdSignalPeriod);
macdHist = macdValue - macdSignal;
// <20><><EFBFBD><EFBFBD> RSI ֵ
Numeric SF = 1 / rsiPeriod;
Numeric change = Close - Close[1];
If(CurrentBar <= rsiPeriod - 1)
{
netChgAvg = (Close - Close[rsiPeriod]) / rsiPeriod;
totChgAvg = Average(Abs(Close - Close[1]), rsiPeriod);
}
Else
{
netChgAvg = netChgAvg[1] + SF * (change - netChgAvg[1]);
totChgAvg = totChgAvg[1] + SF * (Abs(change) - totChgAvg[1]);
}
If(totChgAvg <> 0)
{
rsiValue = 50 * (netChgAvg / totChgAvg + 1);
}
Else
{
rsiValue = 50;
}
// <20><><EFBFBD><EFBFBD> Stochastic ֵ
Numeric highestHigh = Highest(High, stochasticKLength);
Numeric lowestLow = Lowest(Low, stochasticKLength);
Numeric stochasticRaw = (Close - lowestLow) / (highestHigh - lowestLow) * 100;
stochasticValue = Average(stochasticRaw, stochasticKSmoothing);
// <20><><EFBFBD><EFBFBD> CCI ֵ
Numeric typicalPrice = (High + Low + Close) / 3;
Numeric smaTypicalPrice = Average(typicalPrice, cciPeriod);
Numeric meanDeviation = Summation(Abs(typicalPrice - smaTypicalPrice), cciPeriod) / cciPeriod;
If(meanDeviation <> 0)
{
cciValue = (typicalPrice - smaTypicalPrice) / (0.015 * meanDeviation);
}
Else
{
cciValue = 0;
}
// <20><><EFBFBD><EFBFBD> SUPERTREND ֵ
Numeric atr = AvgTrueRange(supertrendPeriod);
Numeric basicUpperBand = (High + Low) / 2 + supertrendFactor * atr;
Numeric basicLowerBand = (High + Low) / 2 - supertrendFactor * atr;
Numeric finalUpperBand = IIF(basicUpperBand < supertrendValue[1] || Close[1] > supertrendValue[1], basicUpperBand, supertrendValue[1]);
Numeric finalLowerBand = IIF(basicLowerBand > supertrendValue[1] || Close[1] < supertrendValue[1], basicLowerBand, supertrendValue[1]);
supertrendValue = IIF(Close > supertrendValue[1], finalLowerBand, finalUpperBand);
// <20><><EFBFBD>ÿ<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>
Bool macdCondition = macdValue < macdSignal;
Bool rsiCondition = rsiValue <50;
Bool stochasticCondition = stochasticValue < 50;
Bool cciCondition = cciValue <0;
Bool supertrendCondition = Close < supertrendValue;
Bool Marketbool = MarketStrength >= EntryStrength;
// <20><><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD>
score = 0;
If(macdCondition)
{
score = score + 1;
}
If(rsiCondition)
{
score = score + 1;
}
If(stochasticCondition)
{
score = score + 1;
}
If(cciCondition)
{
score = score + 1;
}
If(supertrendCondition)
{
score = score + 1;
}
if(Marketbool)
{
score = score + 1;
}
// <20>ڸ<EFBFBD>ͼ<EFBFBD><CDBC>ʾ<EFBFBD>÷<EFBFBD>
Commentary("Score: " + Text(score));
plt1.barv("Score",score);
// <20>ж<EFBFBD><D0B6>Ƿ<EFBFBD><C7B7><EFBFBD><EFB5BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
If(score == totalScore)
{
Commentary("All conditions met!");
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
If(score[1] >= totalScore And MarketPosition == 0 ) //
{
SellShort(Lots, Open);
}
// ƽ<><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
If(score[1] == 0 And MarketPosition == -1)
{
BuyToCover(0, Open);
}
// <20>ڸ<EFBFBD>ͼ<EFBFBD><CDBC>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD><EFBFBD>
If(macdCondition)
{
PlotAuto("MACD_Condition",1,1,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("MACD_Condition",1,1,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(rsiCondition)
{
PlotAuto("RSI_Condition",2,2,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("RSI_Condition",2,2,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(stochasticCondition)
{
PlotAuto("Stochastic_Condition", 3,3,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("Stochastic_Condition", 3,3,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(cciCondition)
{
PlotAuto("CCI_Condition", 4,4,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("CCI_Condition", 4,4,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(supertrendCondition)
{
PlotAuto("Supertrend_Condition", 5,5,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("Supertrend_Condition", 5,5,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
If(Marketbool)
{
PlotAuto("Marketbool", 6,6,Green,Enum_Line,Enum_Solid,Enum_7Pix);
}
Else
{
PlotAuto("Marketbool", 6,6,Red,Enum_Line,Enum_Solid,Enum_7Pix);
}
}
//------------------------------------------------------------------------
// <20><><EFBFBD><EFBFBD><EFBFBD>汾 2024/11/27 150615
// <20><>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD> songshu123
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> TradeBlazer Software<72><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>TradeBlazerƽ̨
// ÿһ<C3BF><EFBFBD><E6B1BE>TradeBlazer<65><72>ʽ<EFBFBD>޸ĺ<DEB8><C4BA><EFBFBD>д<EFBFBD><D0B4>Ȩ<EFBFBD><C8A8>
//------------------------------------------------------------------------

View File

@@ -0,0 +1,210 @@
from vnpy_ctastrategy import (
CtaTemplate,
TargetPosTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
import pandas as pd
import numpy as np
import talib
class vip17_duo(CtaTemplate):
"""
VIP17多头策略
基于多个技术指标的多头策略,当满足一定数量的多头条件时开仓
"""
author = "松鼠Quant"
# 策略参数
total_score = 5 # 开仓分数阈值
entry_strength = 90 # 趋势强度的进场值
length = 5 # 强弱指标和通道计算的周期值
# 指标参数
rpm_period = 14 # RPM Period
bbo_period = 16 # BBO Period
macd_fast_period = 12 # MACD Fast Period
macd_slow_period = 24 # MACD Slow Period
macd_signal_period = 9 # MACD Signal Period
rsi_period = 14 # RSI Period
cci_period = 14 # CCI Period
stoch_k_period = 14 # Stochastic %K Length
stoch_k_smooth = 1 # Stochastic %K Smoothing
stoch_d_smooth = 3 # Stochastic %D Smoothing
supertrend_period = 10 # SUPERTREND Period
supertrend_factor = 2 # SUPERTREND Factor
parameters = ["total_score", "entry_strength", "length",
"macd_fast_period", "macd_slow_period", "macd_signal_period",
"rsi_period", "cci_period", "stoch_k_period"]
variables = ["current_score"]
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)
self.am = ArrayManager(size=100)
# 指标变量
self.current_score = 0
self.market_strength = 0
self.supertrend_value = 0
def on_init(self):
"""
策略初始化
"""
self.write_log("策略初始化")
self.load_bar(100)
def on_start(self):
"""
策略启动
"""
self.write_log("策略启动")
def on_stop(self):
"""
策略停止
"""
self.write_log("策略停止")
def on_tick(self, tick: TickData):
"""
Tick数据更新
"""
self.bg.update_tick(tick)
def calculate_market_strength(self):
"""计算市场强度指标"""
close_change = self.am.close_array[1:] - self.am.close_array[:-1]
up_closes = 0
dn_closes = 0
for i in range(self.length):
if close_change[-i-1] > 0:
up_closes += close_change[-i-1]
else:
dn_closes += close_change[-i-1]
sum_change = np.sum(close_change[-self.length:])
if sum_change >= 0:
self.market_strength = (sum_change / up_closes * 100) if up_closes != 0 else 0
else:
self.market_strength = (sum_change / abs(dn_closes) * 100) if dn_closes != 0 else 0
return self.market_strength >= self.entry_strength
def calculate_supertrend(self):
"""计算SuperTrend指标"""
atr = talib.ATR(self.am.high_array, self.am.low_array,
self.am.close_array, self.supertrend_period)
basic_upper = (self.am.high_array + self.am.low_array) / 2 + self.supertrend_factor * atr
basic_lower = (self.am.high_array + self.am.low_array) / 2 - self.supertrend_factor * atr
# 简化的SuperTrend计算
self.supertrend_value = basic_lower[-1]
return self.am.close_array[-1] > self.supertrend_value
def calculate_score(self):
"""
计算综合得分
"""
score = 0
# MACD条件 - 多头信号
# 使用talib直接计算MACD
macd, signal, hist = talib.MACD(
self.am.close_array,
fastperiod=self.macd_fast_period,
slowperiod=self.macd_slow_period,
signalperiod=self.macd_signal_period
)
if not np.isnan(macd[-1]) and not np.isnan(signal[-1]):
if macd[-1] > signal[-1]: # 多头信号MACD线在信号线上方
score += 1
# RSI条件 - 多头信号
rsi = talib.RSI(self.am.close_array, timeperiod=self.rsi_period)
if not np.isnan(rsi[-1]) and rsi[-1] > 50: # 多头信号RSI大于50
score += 1
# Stochastic条件 - 多头信号
k, d = talib.STOCH(
self.am.high_array,
self.am.low_array,
self.am.close_array,
fastk_period=self.stoch_k_period,
slowk_period=self.stoch_k_smooth,
slowd_period=self.stoch_d_smooth
)
if not np.isnan(k[-1]) and k[-1] > 50: # 多头信号K值大于50
score += 1
# CCI条件 - 多头信号
cci = talib.CCI(
self.am.high_array,
self.am.low_array,
self.am.close_array,
timeperiod=self.cci_period
)
if not np.isnan(cci[-1]) and cci[-1] > 0: # 多头信号CCI大于0
score += 1
# Supertrend条件
if self.calculate_supertrend():
score += 1
# 市场强度条件
if self.calculate_market_strength():
score += 1
return score
def on_bar(self, bar: BarData):
"""
K线更新回调
"""
self.am.update_bar(bar)
if not self.am.inited:
return
# 计算当前得分
self.current_score = self.calculate_score()
# 交易信号
if self.current_score >= self.total_score and not self.pos:
self.buy(bar.close_price + 5, 1)
elif self.current_score == 0 and self.pos > 0:
self.sell(bar.close_price - 5, abs(self.pos))
# 输出当前得分
self.put_event()
def on_trade(self, trade: TradeData):
"""
成交回调
"""
self.put_event()
def on_order(self, order: OrderData):
"""
委托回调
"""
pass
def on_stop_order(self, stop_order: StopOrder):
"""
停止单回调
"""
pass

View File

@@ -0,0 +1,208 @@
from vnpy_ctastrategy import (
CtaTemplate,
TargetPosTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
import pandas as pd
import numpy as np
import talib
class vip17_kong(CtaTemplate):
"""
VIP17空头策略
基于多个技术指标的空头策略,当满足一定数量的空头条件时开仓
"""
author = "松鼠Quant"
# 策略参数
total_score = 5 # 开仓分数阈值
entry_strength = 90 # 趋势强度的进场值
length = 5 # 强弱指标和通道计算的周期值
# 指标参数
rpm_period = 14 # RPM Period
bbo_period = 16 # BBO Period
macd_fast_period = 12 # MACD Fast Period
macd_slow_period = 24 # MACD Slow Period
macd_signal_period = 9 # MACD Signal Period
rsi_period = 14 # RSI Period
cci_period = 14 # CCI Period
stoch_k_period = 14 # Stochastic %K Length
stoch_k_smooth = 1 # Stochastic %K Smoothing
stoch_d_smooth = 3 # Stochastic %D Smoothing
supertrend_period = 10 # SUPERTREND Period
supertrend_factor = 2 # SUPERTREND Factor
parameters = ["total_score", "entry_strength", "length",
"macd_fast_period", "macd_slow_period", "macd_signal_period",
"rsi_period", "cci_period", "stoch_k_period"]
variables = ["current_score"]
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)
self.am = ArrayManager(size=100)
# 指标变量
self.current_score = 0
self.market_strength = 0
self.supertrend_value = 0
def on_init(self):
"""
策略初始化
"""
self.write_log("策略初始化")
self.load_bar(100)
def on_start(self):
"""
策略启动
"""
self.write_log("策略启动")
def on_stop(self):
"""
策略停止
"""
self.write_log("策略停止")
def on_tick(self, tick: TickData):
"""
Tick数据更新
"""
self.bg.update_tick(tick)
def calculate_market_strength(self):
"""计算市场强度指标"""
close_change = self.am.close_array[1:] - self.am.close_array[:-1]
up_closes = 0
dn_closes = 0
for i in range(self.length):
if close_change[-i-1] > 0:
up_closes += close_change[-i-1]
else:
dn_closes += close_change[-i-1]
sum_change = np.sum(close_change[-self.length:])
if sum_change >= 0:
self.market_strength = (sum_change / up_closes * 100) if up_closes != 0 else 0
else:
self.market_strength = (sum_change / abs(dn_closes) * 100) if dn_closes != 0 else 0
return self.market_strength <= -self.entry_strength # 改为判断下跌强度
def calculate_supertrend(self):
"""计算SuperTrend指标"""
atr = talib.ATR(self.am.high_array, self.am.low_array,
self.am.close_array, self.supertrend_period)
basic_upper = (self.am.high_array + self.am.low_array) / 2 + self.supertrend_factor * atr
basic_lower = (self.am.high_array + self.am.low_array) / 2 - self.supertrend_factor * atr
# 简化的SuperTrend计算
self.supertrend_value = basic_upper[-1] # 改为上轨
return self.am.close_array[-1] < self.supertrend_value # 改为判断价格低于上轨
def calculate_score(self):
"""
计算综合得分
"""
score = 0
# MACD条件 - 空头信号
# 使用talib直接计算MACD
macd, signal, hist = talib.MACD(
self.am.close_array,
fastperiod=self.macd_fast_period,
slowperiod=self.macd_slow_period,
signalperiod=self.macd_signal_period
)
if not np.isnan(macd[-1]) and not np.isnan(signal[-1]):
if macd[-1] < signal[-1]: # 空头信号
score += 1
# RSI条件 - 空头信号
rsi = talib.RSI(self.am.close_array, timeperiod=self.rsi_period)
if not np.isnan(rsi[-1]) and rsi[-1] < 50:
score += 1
# Stochastic条件 - 空头信号
k, d = talib.STOCH(
self.am.high_array,
self.am.low_array,
self.am.close_array,
fastk_period=self.stoch_k_period,
slowk_period=self.stoch_k_smooth,
slowd_period=self.stoch_d_smooth
)
if not np.isnan(k[-1]) and k[-1] < 50:
score += 1
# CCI条件 - 空头信号
cci = talib.CCI(
self.am.high_array,
self.am.low_array,
self.am.close_array,
timeperiod=self.cci_period
)
if not np.isnan(cci[-1]) and cci[-1] < 0:
score += 1
# Supertrend条件 - 空头信号
if self.calculate_supertrend():
score += 1
# 市场强度条件 - 空头信号
if self.calculate_market_strength():
score += 1
return score
def on_bar(self, bar: BarData):
"""
K线更新回调
"""
self.am.update_bar(bar)
if not self.am.inited:
return
# 计算当前得分
self.current_score = self.calculate_score()
# 交易信号
if self.current_score >= self.total_score and not self.pos:
self.short(bar.close_price - 5, 1) # 改为做空
elif self.current_score == 0 and self.pos < 0: # 改为判断空仓
self.cover(bar.close_price + 5, abs(self.pos)) # 改为平空
self.put_event()
def on_trade(self, trade: TradeData):
"""
成交回调
"""
self.put_event()
def on_order(self, order: OrderData):
"""
委托回调
"""
pass
def on_stop_order(self, stop_order: StopOrder):
"""
停止单回调
"""
pass

View File

@@ -0,0 +1,7 @@
ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>VIP15<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>.rar
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://pan.baidu.com/s/1liwdmvmGJ7wjHWVewZUUWA?pwd=7777 <20><>ȡ<EFBFBD><C8A1>: 7777
--<2D><><EFBFBD>԰ٶ<D4B0><D9B6><EFBFBD><EFBFBD>̳<EFBFBD><CCB3><EFBFBD><EFBFBD><EFBFBD>Աv7<76>ķ<EFBFBD><C4B7><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><EFBFBD><EFBFBD>ϵС<EFBFBD><EFBFBD><EFBFBD><EFBFBD>΢<EFBFBD>ţ<EFBFBD>viquant01
quant789.com<6F><6D><EFBFBD><EFBFBD>ʹ<EFBFBD>ò<EFBFBD><C3B2><EFBFBD>ѡȡ<D1A1><C8A1><EFBFBD><EFBFBD>

View File

@@ -0,0 +1,144 @@
from vnpy_ctastrategy import (
CtaTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
class AtrRsiStrategy(CtaTemplate):
""""""
author = "用Python的交易员"
atr_length = 22
atr_ma_length = 10
rsi_length = 5
rsi_entry = 16
trailing_percent = 0.8
fixed_size = 1
atr_value = 0
atr_ma = 0
rsi_value = 0
rsi_buy = 0
rsi_sell = 0
intra_trade_high = 0
intra_trade_low = 0
parameters = [
"atr_length",
"atr_ma_length",
"rsi_length",
"rsi_entry",
"trailing_percent",
"fixed_size",
]
variables = [
"atr_value",
"atr_ma",
"rsi_value",
"rsi_buy",
"rsi_sell",
"intra_trade_high",
"intra_trade_low",
]
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)
self.am = ArrayManager()
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.rsi_buy = 50 + self.rsi_entry
self.rsi_sell = 50 - self.rsi_entry
self.load_bar(10)
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.
"""
self.bg.update_tick(tick)
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
self.cancel_all()
am = self.am
am.update_bar(bar)
if not am.inited:
return
atr_array = am.atr(self.atr_length, array=True)
self.atr_value = atr_array[-1]
self.atr_ma = atr_array[-self.atr_ma_length :].mean()
self.rsi_value = am.rsi(self.rsi_length)
if self.pos == 0:
self.intra_trade_high = bar.high_price
self.intra_trade_low = bar.low_price
if self.atr_value > self.atr_ma:
if self.rsi_value > self.rsi_buy:
self.buy(bar.close_price + 5, self.fixed_size)
elif self.rsi_value < self.rsi_sell:
self.short(bar.close_price - 5, self.fixed_size)
elif self.pos > 0:
self.intra_trade_high = max(self.intra_trade_high, bar.high_price)
self.intra_trade_low = bar.low_price
long_stop = self.intra_trade_high * (1 - self.trailing_percent / 100)
self.sell(long_stop, abs(self.pos), stop=True)
elif self.pos < 0:
self.intra_trade_low = min(self.intra_trade_low, bar.low_price)
self.intra_trade_high = bar.high_price
short_stop = self.intra_trade_low * (1 + self.trailing_percent / 100)
self.cover(short_stop, abs(self.pos), stop=True)
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

View File

@@ -0,0 +1,114 @@
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 股票类交易手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, \
open_commission=0.0003, close_commission=0.0003,\
close_today_commission=0, min_commission=5), type='stock')
def handle_data(context, data):
#获取沪深300股票池
stock_set=get_index_stocks('000300.XSHG')
#此处可增加选股条件
q = query(
valuation.code, # 股票代码
).filter(
valuation.code.in_(stock_set),#只对设定股票池执行
)
#获取财务数据,指定日期为回测当天
current_date=context.current_dt.strftime('%Y-%m-%d')
fdf = get_fundamentals(q,current_date)
#取前50只股
fdf=fdf.head(100)
#获取股票列表
get_stocks=list(fdf['code'])
# 去除ST*ST
st=get_extras('is_st',get_stocks,current_date,current_date, df=True)
st=st.loc[current_date]
get_stocks=list(st[st==False].index)
#考虑5天的历史数据
num=5
#轨线用前面20天数据计算
days=20
#每只股票可用资金为当前资金除以50
cash=context.portfolio.available_cash/100
#获取所有股票前num+days天收盘价数据
price=history(num+days,'1d','close',get_stocks,skip_paused=True)
where_are_nan = np.isnan(price)
where_are_inf = np.isinf(price)
price[where_are_nan] = 0
price[where_are_inf] = 0
#循环每只股
for security in get_stocks:
#用数组保存均值大小为num
mid=np.arange(num)
#标准差
std=np.arange(num)
#定义数组大小
close_data=np.arange(num*days).reshape(num,days)
for i in range(0,num):
for j in range(0,days):
close_data[i][j]=price[security][i+j]
#中轨线即均值为days天收盘价数据平均
mid[i]=np.mean(close_data[i])
#计算标准差
std[i]=np.std(close_data[i])
#上轨线=中轨线+两倍的标准差
up=mid[num-1]+2*std[num-1]
#下轨线
down=mid[num-1]-2*std[num-1]
#保存num天数据判断开口收口或平口
boll=0
for i in range(0,num-1):
if std[i]>std[i+1]:
boll=boll+1
else:
boll=boll-1
#判断目前股票是否停牌
paused=data[security].paused
#取得当前股票价格
current_price=data[security].price
#如果连续num天开口
if boll==-4:
#如果当前价格超过昨日的上轨且价格高于均线
if current_price>up and current_price>mid[num-1]:
#计算可以买多少股票
num_of_shares=int(cash/current_price)
#如果可以买的数量超过0并且股票未停牌
if num_of_shares>0 and paused==False:
#购买股票
order(security,+num_of_shares)
#如果当前价格跌破了昨日的下轨且价格低于均线
elif current_price<down and current_price<mid[num-1]:
#如果股票未停牌
if paused==False:
#将股票卖空
order_target(security,0)
#如果连续num天收口
if boll==4:
#股价超过上轨且价格低于均线时卖
if current_price>up and current_price<mid[num-1]:
if paused==False:
order_target(security,0)
#跌破下轨且价格高于均线时买
elif current_price<down and current_price>mid[num-1]:
num_of_shares=int(cash/current_price)
if num_of_shares>0 and paused==False:
order(security,+num_of_shares)
#连续平口
if boll in range(-1,1):
#价格在中轨线上且昨日均价高于三天前
if current_price>mid[num-1] and mid[num-1]>mid[num-3]:
num_of_shares=int(cash/current_price)
if num_of_shares>0 and paused==False:
order(security,+num_of_shares)
if current_price<mid[num-1] and mid[num-1]<mid[num-3]:
if paused==False:
order_target(security,0)

View File

@@ -0,0 +1,97 @@
# coding: utf-8
# In[ ]:
# 导入函数库
import jqdata
import pandas as pd
import numpy as np
# 初始化函数,设定基准等等
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
#获取沪深300股票池
stock_set=get_index_stocks('000300.XSHG')
#此处可增加选股条件
q = query(
valuation.code, # 股票代码
).filter(
valuation.code.in_(stock_set),#只对设定股票池执行
)
fdf = get_fundamentals(q)
#取前50只股
fdf=fdf.head(50)
#获取股票列表
stock_list=list(fdf['code'])
trend={}
for security in stock_list:
trend[security]='None'
def handle_data(context, data):
N = 20 # 计算TR时的N
M = 49 # 计算MATRIX时的M
num=3
length_of_data = N+M+num # 取closeprice的天数为了足够计算MATRIX、TRIX
cash=context.portfolio.available_cash/50
for security in stock_list:
close_price=attribute_history(security,length_of_data,'1d',('close'),skip_paused=True)
where_are_nan = np.isnan(close_price)
where_are_inf = np.isinf(close_price)
close_price[where_are_nan] = 0
close_price[where_are_inf] = 0
MA5=close_price['close'][-5:].mean()
MA10=close_price['close'][-10:].mean()
ma5=close_price['close'][-6:-1].mean()
ma10=close_price['close'][-11:-1].mean()
price_array={}
for i in range(0,M+num):
price_array[i]=close_price['close'][i:i+N]
#TR=收盘价的N日指数移动平均
TR={}
for i in range(0,M+num):
TR[i]=np.mean(price_array[i])
#TRIX=(TR-昨日TR)/昨日TR*100
TRIX={}
for i in range(1,M+num):
if TR[i]==0:
TRIX[i]=0
continue
TRIX[i]=(TR[i]-TR[i-1])/TR[i]*100
#MATRIX=TRIX的M日简单移动平均
MATRIX={}
for i in range(0,num):
TRIX_sum=0
for j in range(1,M):
TRIX_sum=TRIX_sum+TRIX[i+j]
MATRIX[i]=TRIX_sum/M
current_price=data[security].price
length=0
for i in range(0,num-1):
if TRIX[M+i]>MATRIX[i]:
length=length+1
else:
length=length-1
if length>0 and MATRIX[num-1]>MATRIX[0]:
trend[security]='up'
elif length<0 and MATRIX[num-1]<MATRIX[0]:
trend[security]='down'
if trend[security]=='up':
order_value(security,cash)
elif trend[security]=='down' and security in context.portfolio.positions:
if MA5<MA10:
order_target(security,0)
elif MA5>MA10 and ma5<ma10 :
order_value(security,cash)

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,378 @@
from typing import List, Dict
from datetime import datetime
from vnpy_portfoliostrategy import (
StrategyEngine,
StrategyTemplate,
TickData,
BarData,
TradeData,
ArrayManager,
)
from vnpy.trader.utility import Interval
from vnpy_portfoliostrategy.utility import PortfolioBarGenerator
import numpy as np
import talib as ta
#使用portfoliostrategy模块编写的交易策略无参数优化请自行调试优化参数。
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
class VIP14(StrategyTemplate):
""""""
author = "松鼠quant"
N = 2
M = 5
X = 5
TRS=5
fixed_size=1
am_1=0
am_2=0
current_bar=0
parameters = [
"N",
"M",
"X",
"fixed_size",
"TRS"
]
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.KG=0
self.high_after_entry=0
self.low_after_entry=0
self.dliq_point=0
self.kliq_point=0
self.curbar_h = np.zeros(100) # 例如,初始化为长度为 100 的数组
self.curbar_l = np.zeros(100)
# 初始化 hd 属性
self.hd = np.zeros(100) # 例如,初始化为长度为 100 的数组
self.ld = np.zeros(100) # 例如,初始化为长度为 100 的数组
self.targets: Dict[str, int] = {}
self.last_tick_time: datetime = None
# Obtain contract info
self.ams: Dict[str, ArrayManager] = {}
for vt_symbol in self.vt_symbols:
self.ams[vt_symbol] = ArrayManager(100)
self.targets[vt_symbol] = 0
self.pbg = PortfolioBarGenerator(self.on_bars, 2, self.on_2hour_bars, Interval.HOUR)
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.load_bars(10)
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.
"""
self.pbg.update_tick(tick)
def on_bars(self, bars: Dict[str, BarData]):
"""
Callback of new bars data update.
"""
self.pbg.update_bars(bars)
def on_2hour_bars(self, bars: Dict[str, BarData]):
""""""
self.cancel_all()
# 初始化
nx = 0
# 获取合约的数据
for vt_symbol, bar in bars.items():
nx += 1
# 更新 ArrayManager
am: ArrayManager = self.ams[vt_symbol]
am.update_bar(bar)
#print(vt_symbol)
# 如果 ArrayManager 还未初始化完毕,则跳过
if not am.inited:
return
# 将第一个和第二个合约的 ArrayManager 分别保存下来
if nx == 1:
self.am_1 = am
elif nx == 2:
self.am_2 = am
am_1=self.am_1
am_2=self.am_2
self.current_bar=self.current_bar+1 #Bar线计数
# 计算相关指标
c_jb = am_1.close_array / am_2.close_array # 计算价比
copen = am_1.open_array / am_2.open_array # 计算开比
chigh = np.maximum(np.maximum(am_1.high_array / am_2.high_array, copen), c_jb)
clow = np.minimum(np.minimum(am_1.low_array / am_2.low_array, copen), c_jb)
# 计算多个指标的序列
var1 = self.highest(chigh, self.N) - self.lowest(clow, self.N)
var2 = self.highest(chigh, self.N) - c_jb[-self.N:]
var3 = c_jb[-self.N:] - self.lowest(clow, self.N)
var4 = var2 / var1 * 100 - 70
var5 = (c_jb[-self.N:] - self.lowest(clow, self.N)) / var1 * 100
var6 = (2 * c_jb + chigh + clow) / 4
var7 = self.sma(var3 / var1 * 100, 3, 1)
var8 = self.lowest(clow, self.M)
var9 = self.sma(var7, 3, 1) - self.sma(var4, 9, 1)
vara = self.highest(chigh, self.M)
bd1 = self.xaverage((var6[-self.M:] - var8) / (vara - var8) * 100, self.M)
bd2 = self.xaverage(bd1, self.X)
ma1 = self.xaverage(c_jb, self.X)
# 检查金叉 (BD1 从小于 BD2 变为大于 BD2)
dk_up = bd1[-1] > bd2[-1] and bd1[-2] <= bd2[-1]
# 检查死叉 (BD1 从大于 BD2 变为小于 BD2)
kk_dn = bd1[-1] < bd2[-1] and bd1[-2] >= bd2[-1]
# 确保 dk_up 和 kk_dn 不为空
if dk_up:
self.curbar_h = self.current_bar # 在最后一次金叉发生时更新 curbar_h
period = max(self.curbar_h - self.curbar_l, self.M)
# 确保 period 不超过 chigh 的长度
if len(chigh) >= period:
Highup = max(chigh[-period:-1])
else:
Highup = max(chigh[-self.M:-1]) # 如果 period 超出范围,则取整个序列的最大值
if kk_dn:
self.curbar_l = self.current_bar # 在最后一次死叉发生时更新 curbar_l
period = max(self.curbar_l - self.curbar_h, self.M)
# 确保 period 不超过 clow 的长度
if len(clow) >= period:
Lowdown = min(clow[-period:-1])
else:
Lowdown = min(clow[-self.M:-1]) # 如果 period 超出范围,则取整个序列的最小值
#print(f'bd1[-1]{bd1[-1] },bd2[-1] {bd2[-1]},chigh[-1]{chigh[-1]},Highup{Highup},c_jb[-1]{c_jb[-1]},ma1[-1]{ma1[-1]}')
# 开仓条件
cond_dk = (bd1[-1] > bd2[-1]) & (chigh[-1] >= Highup) & (c_jb[-1] > ma1[-1])
cond_kk = (bd1[-1] < bd2[-1]) & (clow[-1] <= Lowdown) & (c_jb[-1] < ma1[-1])
self.KG = np.where(cond_dk, 1, np.where(cond_kk, -1, 0))
#print(self.KG)
#开仓部分
nx=0
for vt_symbol, bar in bars.items():
nx+=1
am: ArrayManager = self.ams[vt_symbol]
if not am.inited:
return
price = bar.close_price
current_pos = self.get_pos(vt_symbol)
#print(nx,current_pos,self.KG)
#数据源1
if nx==1:
#开多
if self.KG>0 :
if current_pos<0:
self.cover(vt_symbol, price, self.fixed_size)
self.buy(vt_symbol, price, self.fixed_size)
self.low_after_entry = clow[-1]
if current_pos==0:
self.buy(vt_symbol, price, self.fixed_size)
self.low_after_entry = clow[-1]
#开空
if self.KG<0 :
if current_pos > 0:
self.sell(vt_symbol, price, self.fixed_size)
self.short(vt_symbol, price, self.fixed_size)
self.high_after_entry = chigh[-1]
if current_pos == 0:
self.short(vt_symbol, price, self.fixed_size)
self.high_after_entry = chigh[-1]
#数据源2
elif nx==2:
#开多
if self.KG>0:
if current_pos < 0:
self.cover(vt_symbol, price, self.fixed_size)
self.short(vt_symbol, price, self.fixed_size)
self.high_after_entry = chigh[-1]
if current_pos == 0:
self.short(vt_symbol, price, self.fixed_size)
self.high_after_entry = chigh[-1]
#开空
if self.KG<0 and current_pos >= 0 :
if current_pos > 0 :
self.sell(vt_symbol, price, self.fixed_size)
self.buy(vt_symbol, price, self.fixed_size)
self.low_after_entry = clow[-1]
if current_pos == 0 :
self.buy(vt_symbol, price, self.fixed_size)
self.low_after_entry = clow[-1]
#移动出场
if self.KG == 0:
self.high_after_entry = chigh[-1]
self.low_after_entry = clow[-1]
elif self.KG != 0:
self.high_after_entry = min(self.high_after_entry, chigh[-1])
self.low_after_entry = max(self.low_after_entry, clow[-1])
# Calculate liquidation points
if self.KG > 0:
self.dliq_point = self.low_after_entry - (copen[-1] * self.TRS / 1000)
elif self.KG < 0:
self.kliq_point = self.high_after_entry + (copen[-1] * self.TRS / 1000)
nx=0
# print("多头",c_jb[-1],self.dliq_point)
# print("空头",c_jb[-1],self.kliq_point)
for vt_symbol, bar in bars.items():
nx+=1
am: ArrayManager = self.ams[vt_symbol]
if not am.inited:
return
price = bar.close_price
current_pos = self.get_pos(vt_symbol)
#数据源1
if nx==1:
if self.KG > 0 and c_jb[-1]<= self.dliq_point and self.dliq_point > 0 and current_pos>0:
self.sell(vt_symbol, price, current_pos)
if self.KG < 0 and c_jb[-1] >= self.kliq_point and self.kliq_point > 0 and current_pos<0:
self.cover(vt_symbol, price, current_pos)
#数据源2
if nx==2:
if self.KG > 0 and c_jb[-1]<= self.dliq_point and self.dliq_point > 0 and current_pos<0:
self.cover(vt_symbol, price, current_pos)
if self.KG < 0 and c_jb[-1] >= self.kliq_point and self.kliq_point > 0 and current_pos>0:
self.sell(vt_symbol, price, current_pos)
self.put_event()
def highest(self, data, period):
"""
计算序列最后 period 个元素中的最高值,返回一个序列
:param data: 数据序列
:param period: 周期
:return: 最后 period 个元素中的最高值序列
"""
result = []
start_index = max(0, len(data) - period)
for i in range(start_index, len(data)):
result.append(max(data[max(0, i - period + 1):i + 1]))
return np.array(result)
def lowest(self, data, period):
"""
计算序列最后 period 个元素中的最小值,返回一个序列
:param data: 数据序列
:param period: 周期
:return: 最后 period 个元素中的最小值序列
"""
result = []
start_index = max(0, len(data) - period)
for i in range(start_index, len(data)):
result.append(min(data[max(0, i - period + 1):i + 1]))
return np.array(result)
def sma(self, data, period, weight=1):
"""
计算简单移动平均SMA的序列仅计算最后 period 个元素
:param data: 数据序列
:param period: 周期
:param weight: 权重
:return: SMA序列
"""
if len(data) < period:
return np.convolve(data, np.ones((len(data),))/len(data), mode='valid')
else:
return np.convolve(data[-period:], np.ones((period,))/period, mode='valid')
def xaverage(self, data, period):
"""
计算加权平均WMA的序列
:param data: 数据序列
:param period: 周期
:return: WMA序列
"""
if len(data) < period:
weights = np.arange(1, len(data) + 1)
return np.convolve(data, weights/weights.sum(), mode='full')[-len(data):]
else:
weights = np.arange(1, period + 1)
return np.convolve(data[-period:], weights/weights.sum(), mode='full')[-period:]
def HHV(self, data, period):
"""
计算给定数据序列中最后 period 个元素的最大值
:param data: 数据序列
:param period: 周期
:return: 最后 period 个元素的最大值
"""
if len(data) == 0:
return None # 如果数据为空,返回 None 或者抛出异常
if period > len(data):
period = len(data) # 如果 period 超出数据长度,则取数据长度
return max(data[-period:])
def LLV(self, data, period):
"""
计算给定数据序列中最后 period 个元素的最小值
:param data: 数据序列
:param period: 周期
:return: 最后 period 个元素的最小值
"""
if len(data) == 0:
return None # 如果数据为空,返回 None 或者抛出异常
if period > len(data):
period = len(data) # 如果 period 超出数据长度,则取数据长度
return min(data[-period:])

View File

@@ -0,0 +1,171 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"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 AdvancedSpreadStrategy_dualthrust2 import AdvancedSpreadStrategy"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"设置回测的参数。参数及其含义如下 1. vt_symbol ==> 产品名称 2. interval ==> 周期 3. start ==> 开始时间 4. rate ==> 手续费 5. slippage ==> 滑点 6. size ==> 合约乘数 7. pricetick ==> 价格跳动 8. capital ==> 回测资本 9. end ==> 截止时间 10. mode ==> 回测的模式一共有两种BacktestingMode.BAR和BacktestingMode.TICK 11. inverse ==> 周期"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# 创建回测引擎\n",
"engine = BacktestingEngine()\n",
"\n",
"engine.set_parameters(\n",
" interval=Interval.MINUTE,\n",
" start=datetime(2024, 7, 1),\n",
" end=datetime(2024, 8, 30),\n",
" rate=0,\n",
" slippage=0.6 + (16 / 100),\n",
" capital= 1000000\n",
")\n",
"\n",
"\n",
"setting = {\n",
" # \"aroon_window\": 5,\n",
" \"k1\":0.3,\n",
" \"k2\": 0.9,\n",
" \"percent_add\": 0,\n",
" \"otm_level\": 0\n",
"}\n",
"engine.add_strategy(AdvancedSpreadStrategy, setting)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
" 72%|███████▏ | 44/61 [02:21<00:55, 3.28s/it]"
]
}
],
"source": [
"# 历史数据回放\n",
"engine.run_backtesting()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"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": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"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,201 @@
from datetime import time
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):
"""基于Dual Thrust信号做空符合价差的策略"""
author: str = "用Python的交易员"
option_portfolio: str = Parameter("MO") # 期权产品代码
underlying_symbol: str = Parameter("IMJQ00.CFFEX") # 标的合约代码
k1: float = Parameter(0.3) # 多头系数
k2: float = Parameter(0.9) # 空头系数
exit_time: time = Parameter(time(14, 55)) # 平仓时间
percent_add: float = Parameter(0.002) # 委托超价比例
otm_level: int = Parameter(0) # 做空期权档位
leg1_ratio: int = Parameter(4) # 顺势腿的比例
leg2_ratio: int = Parameter(1) # 逆势腿的比例
dual_thrust_signal: int = Variable(0) # 当前信号多空1多头-1空头0无信号
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: DualThrustFactor = DualThrustFactor(
self.underlying_symbol, self.k1, self.k2, self.exit_time
)
# 加载标的历史数据初始化
bars: list[BarData] = self.load_bars(self.underlying_symbol, 100, 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.dual_thrust_signal = data.get("dual_thrust_signal", 0)
def on_stop(self) -> None:
"""策略停止"""
self.write_log("策略停止")
data: dict = {"dual_thrust_signal": self.dual_thrust_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
# 获取Dual Thrust信号
signal: int = self.factor.get_signal()
# 固定交易手数为1
trading_size: int = 1
# 根据信号开仓
if signal != self.dual_thrust_signal:
self.clear_targets()
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:
if signal == 1: # 多头信号做空Put顺势腿和Call逆势腿
self.set_target(put.vt_symbol, -trading_size * self.leg1_ratio)
self.set_target(call.vt_symbol, -trading_size * self.leg2_ratio)
elif signal == -1: # 空头信号做空Call顺势腿和Put逆势腿
self.set_target(call.vt_symbol, -trading_size * self.leg1_ratio)
self.set_target(put.vt_symbol, -trading_size * self.leg2_ratio)
# 平仓逻辑在exit_time前平仓
if underlying_bar.datetime.time() >= self.exit_time:
self.clear_targets()
self.dual_thrust_signal = signal
self.execute_trading(price_data, self.percent_add)
self.put_event()
class DualThrustFactor:
"""标的物Dual Thrust因子基于价格区间输出多空信号"""
def __init__(self, vt_symbol: str, k1: float, k2: float, exit_time: time) -> None:
self.vt_symbol: str = vt_symbol
self.k1: float = k1
self.k2: float = k2
self.exit_time: time = exit_time
self.bars = []
self.day_open: float = 0
self.day_high: float = 0
self.day_low: float = 0
self.day_range: float = 0
self.long_entry: float = 0
self.short_entry: float = 0
self.signal: int = 0 # 1多头-1空头0无信号
self.bg: BarGenerator = BarGenerator(self.update_bar, 1, self.update_window_bar)
self.am: ArrayManager = ArrayManager(40) # 缓存足够的历史数据
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.bars.append(bar)
if len(self.bars) <= 2:
return
else:
self.bars.pop(0)
last_bar = self.bars[-2]
if len(self.bars) == 0 or last_bar.datetime.date() != bar.datetime.date():
if len(self.bars) >= 1:
# 计算前一交易日的波动范围
prev_high = self.am.high[-1]
prev_low = self.am.low[-1]
prev_close = self.am.close[-1]
self.day_range = max(prev_high - prev_low, prev_high - prev_close, prev_close - prev_low)
# 重置当日参数
self.day_open = bar.open_price
self.day_high = bar.high_price
self.day_low = bar.low_price
else:
# 更新当日最高最低价
self.day_high = max(self.day_high, bar.high_price)
self.day_low = min(self.day_low, bar.low_price)
self.am.update_bar(bar)
# 计算入场价
if self.day_range > 0:
self.long_entry = self.day_open + self.k1 * self.day_range
self.short_entry = self.day_open - self.k2 * self.day_range
# 生成信号
if bar.close_price > self.long_entry:
self.signal = 1
elif bar.close_price < self.short_entry:
self.signal = -1
else:
self.signal = 0
def get_signal(self) -> int:
"""获取当前多空信号"""
return self.signal

View File

@@ -0,0 +1,245 @@
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,
)
from datetime import time
class AdvancedSpreadStrategy(StrategyTemplate):
"""基于DualThrust信号做空符合价差的策略"""
author: str = "用Python的交易员"
option_portfolio: str = Parameter("MO") # 期权产品代码
underlying_symbol: str = Parameter("IMJQ00.CFFEX") # 标的合约代码
k1: float = Parameter(0.3) # DualThrust参数k1
k2: float = Parameter(0.9) # DualThrust参数k2
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) # 逆势腿的比例
dt_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: DualThrustFactor = DualThrustFactor(self.underlying_symbol, self.k1, self.k2)
# 加载标的历史数据初始化
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.dt_signal = data.get("dt_signal", 0)
def on_stop(self) -> None:
"""策略停止"""
self.write_log("策略停止")
data: dict = {"dt_signal": self.dt_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
# 获取当前DualThrust多空信号
dt_signal: int = self.factor.get_signal()
# 如果DualThrust多头信号且尚未做多
if dt_signal > 0 and self.dt_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 = 1 # 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)
# 如果DualThrust空头信号且尚未做空
elif dt_signal < 0 and self.dt_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 = 1 #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)
# 缓存DualThrust多空信号
self.dt_signal = dt_signal
# 执行具体的委托交易
self.execute_trading(price_data, self.percent_add)
# 推送UI事件更新
self.put_event()
class DualThrustFactor:
"""标的物DualThrust因子基于DualThrust输出多空信号"""
def __init__(self, vt_symbol: str, k1: float, k2: float) -> None:
"""构造函数"""
self.vt_symbol: str = vt_symbol
self.k1: float = k1
self.k2: float = k2
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
self.am: ArrayManager = ArrayManager(10)
self.day_open = 0
self.day_high = 0
self.day_low = 0
self.day_range = 0
self.long_entry = 0
self.short_entry = 0
self.exit_time = time(hour=14, minute=55)
self.long_entered = False
self.short_entered = False
self.signal: int = 0
self.bars: list[BarData] = [] # 手动维护最近两根K线
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
# 维护最近两根K线
self.bars.append(bar)
if len(self.bars) > 2:
self.bars.pop(0)
# 确保至少有两根K线用于日期比较
if len(self.bars) < 2:
return
last_bar = self.bars[-2]
# bar = self.bars[-1]
# 检查是否新的一天
if last_bar.datetime.date() != bar.datetime.date():
if self.day_high:
self.day_range = self.day_high - self.day_low
self.long_entry = bar.open_price + self.k1 * self.day_range
self.short_entry = bar.open_price - self.k2 * self.day_range
self.day_open = bar.open_price
self.day_high = bar.high_price
self.day_low = bar.low_price
self.long_entered = False
self.short_entered = False
else:
self.day_high = max(self.day_high, bar.high_price)
self.day_low = min(self.day_low, bar.low_price)
if not self.day_range:
return
# 生成信号逻辑
if bar.datetime.time() < self.exit_time:
if bar.close_price > self.day_open:
self.signal = 1
else:
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(14)
else:
return 0

View File

@@ -0,0 +1,215 @@
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
class TurtleSignalStrategy:
def __init__(self, vt_symbol: str, entry_window: int, exit_window: int, atr_window: int) -> None:
"""构造函数"""
self.vt_symbol: str = vt_symbol
self.entry_window: int = entry_window
self.exit_window: int = exit_window
self.atr_window: int = atr_window
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
self.am: ArrayManager = ArrayManager(slow_window + 10)
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,315 @@
'''逐行解释代码:
1.导入所需的模块和库,包括 time、table来自 matplotlib.pyplot、pandas、numpy、numba 和 operator。
2.定义了一个名为 process 的函数,用于处理买卖盘的字典数据。
3.定义了一个名为 data 的函数,用于读取并处理 tick 数据,生成分钟级别的 bar 数据。
4.定义了一个名为 orderflow_df_new 的函数,用于处理 tick 数据和分钟级别的 bar 数据,生成订单流数据。
5.定义了一个名为 GetOrderFlow_dj 的函数,用于计算订单流的指标(堆积)。
6.定义了一个名为 back_data 的函数,用于保存回测数据。
7.在 if __name__ == "__main__": 下,首先调用 data() 函数获取 tick 数据和分钟级别的 bar 数据。
然后调用 orderflow_df_new() 函数,传入 tick 数据和 bar 数据,生成订单流数据 ofdata。
打印输出 ofdata。
8.调用 back_data() 函数,将订单流数据保存为回测数据。
打印输出 "done",表示程序执行完毕。
总体而言,该代码的功能是从 tick 数据中生成分钟级别的 bar 数据,然后根据 bar 数据计算订单流,并将订单流数据保存为回测数据。
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# 使用前注意事项:
1、修改read_csv对应的文件地址
2、修改resample对应的转化周期
3、修改folder_path、to_csv对应的保存路径
'''
import time
from matplotlib.pyplot import table
from datetime import timedelta,datetime
import pandas as pd
import numpy as np
from numba import *
from numba import cuda
import operator
import os
import chardet
def process(bidDict,askDict):
bidDictResult,askDictResult = {},{}
sList = sorted(set(list(bidDict.keys()) + list(askDict.keys())))
#print('bidDict:',list(bidDict.keys()))
#print('askDict:',list(askDict.keys()))
#print('sList:',sList)
#240884432
for s in sList:
if s in bidDict:
bidDictResult[s] = bidDict[s]
else:
bidDictResult[s] = 0
if s in askDict:
askDictResult[s] = askDict[s]
else:
askDictResult[s] = 0
return bidDictResult,askDictResult
def dataload(data,cycle):
#日期修正
# data['业务日期'] = data['业务日期'].dt.strftime('%Y-%m-%d')
# data['datetime'] = data['业务日期'] + ' '+data['最后修改时间'].dt.time.astype(str) + '.' + data['最后修改毫秒'].astype(str)
# # 将 'datetime' 列的数据类型更改为 datetime 格式
data['datetime'] = pd.to_datetime(data['datetime'], errors='coerce', format='%Y-%m-%d %H:%M:%S.%f')
# 如果需要,可以将 datetime 列格式化为字符串
#data['formatted_date'] = data['datetime'].dt.strftime('%Y-%m-%d %H:%M:%S.%f')
#计算瞬时成交量
# data['volume'] = data['数量'] - data['数量'].shift(1)
data['volume'] = data['volume'].fillna(0)
#整理好要用的tick数据元素
tickdata =pd.DataFrame({'datetime':data['datetime'],'symbol':data['symbol'],'lastprice':data['lastprice'],
'volume':data['volume'],'bid_p':data['bid_p'],'bid_v':data['bid_v'],'ask_p':data['ask_p'],'ask_v':data['ask_v']})
#tickdata['datetime'] = pd.to_datetime(tickdata['datetime'])
tickdata['open'] = tickdata['lastprice']
tickdata['high'] = tickdata['lastprice']
tickdata['low'] = tickdata['lastprice']
tickdata['close'] = tickdata['lastprice']
tickdata['starttime'] = tickdata['datetime']
# # 找到满足条件的行的索引
# condition = tickdata['datetime'].dt.time == pd.to_datetime('22:59:59').time()
# indexes_to_update = tickdata.index[condition]
# # 遍历索引,将不一致的日期更新为上一行的日期
# for idx in indexes_to_update:
# if idx > 0:
# tickdata.at[idx, 'datetime'] = tickdata.at[idx - 1, 'datetime'].replace(hour=22, minute=59, second=59)
# 确保日期列按升序排序
tickdata.sort_values(by='datetime', inplace=True)
# rule = '1T
bardata = tickdata.resample(on = 'datetime',rule = cycle,label = 'right',closed = 'right').agg({'starttime':'first','symbol':'last','open':'first','high':'max','low':'min','close':'last','volume':'sum'}).reset_index(drop = False)
#240884432
bardata =bardata.dropna().reset_index(drop = True)
return tickdata,bardata
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
def orderflow_df_new(df_tick,df_min):
df_of=pd.DataFrame({})
t1 = time.time()
startArray = pd.to_datetime(df_min['starttime']).values
voluememin= df_min['volume'].values
highs=df_min['high'].values
lows=df_min['low'].values
opens=df_min['open'].values
closes=df_min['close'].values
endArray = pd.to_datetime(df_min['datetime']).values
tTickArray = pd.to_datetime(df_tick['datetime']).values
bp1TickArray = df_tick['bid_p'].values
ap1TickArray = df_tick['ask_p'].values
lastTickArray = df_tick['lastprice'].values
volumeTickArray = df_tick['volume'].values
symbolarray = df_tick['symbol'].values
indexFinal = 0
for index,tEnd in enumerate(endArray):
start = startArray[index]
bidDict = {}
askDict = {}
bar_vol=voluememin[index]
bar_close=closes[index]
bar_open=opens[index]
bar_low=lows[index]
bar_high=highs[index]
bar_symbol=symbolarray[index]
dt=endArray[index]
for indexTick in range(indexFinal,len(df_tick)):
if tTickArray[indexTick] > tEnd:
break
elif (tTickArray[indexTick] >= start) & (tTickArray[indexTick] <= tEnd):
if indexTick==0:
Bp = round(bp1TickArray[indexTick],2)
Ap = round(ap1TickArray[indexTick],2)
else:
Bp = round(bp1TickArray[indexTick - 1],2)
Ap = round(ap1TickArray[indexTick - 1],2)
LastPrice = round(lastTickArray[indexTick],2)
Volume = volumeTickArray[indexTick]
if LastPrice >= Ap:
if LastPrice in askDict.keys():
askDict[LastPrice] += Volume
else:
askDict[LastPrice] = Volume
if LastPrice <= Bp:
if LastPrice in bidDict.keys():
bidDict[LastPrice] += Volume
else:
bidDict[LastPrice] = Volume
indexFinal = indexTick
bidDictResult,askDictResult = process(bidDict,askDict)
bidDictResult=dict(sorted(bidDictResult.items(),key=operator.itemgetter(0)))
askDictResult=dict(sorted(askDictResult.items(),key=operator.itemgetter(0)))
prinslist=list(bidDictResult.keys())
asklist=list(askDictResult.values())
bidlist=list(bidDictResult.values())
delta=(sum(askDictResult.values()) - sum(bidDictResult.values()))
df=pd.DataFrame({'price':pd.Series([prinslist]),'Ask':pd.Series([asklist]),'Bid':pd.Series([bidlist])})
df['symbol']=bar_symbol
df['datetime']=dt
df['delta']=str(delta)
df['close']=bar_close
df['open']=bar_open
df['high']=bar_high
df['low']=bar_low
df['volume']=bar_vol
# 过滤'volume'列小于等于0的行
df = df[df['volume'] > 0]
# 重新排序DataFrame按照'datetime'列进行升序排序
df = df.sort_values(by='datetime', ascending=True)
# 重新设置索引,以便索引能够正确对齐
df = df.reset_index(drop=True)
#df['ticktime']=tTickArray[indexTick]
df['dj']=GetOrderFlow_dj(df)
#print(df)
df_of = pd.concat([df_of, df], ignore_index=True)
print(time.time() - t1)
return df_of
def GetOrderFlow_dj(kData):
itemAskBG=['rgb(0,255,255)', 'rgb(255,0,255)', "rgb(255,182,193)"] # 买盘背景色
itemBidBG=['rgb(173,255,47)', 'rgb(255,127,80)', "rgb(32,178,170)"] # 卖盘背景色
Config={
'Value1':3,
'Value2':3,
'Value3':3,
'Value4':True,
}
aryData=kData
djcout=0
for index,row in aryData.iterrows():
kItem=aryData.iloc[index]
high=kItem['high']
low=kItem['low']
close=kItem['close']
open=kItem['open']
dtime=kItem['datetime']
price_s=kItem['price']
Ask_s=kItem['Ask']
Bid_s=kItem['Bid']
delta=kItem['delta']
price_s=price_s
Ask_s=Ask_s
Bid_s=Bid_s
gj=0
xq=0
gxx=0
xxx=0
for i in np.arange (0, len(price_s),1) :
duiji={
'price':0,
'time':0,
'longshort':0,
'cout':0,
'color':'blue'
}
if i==0 :
delta=delta
order= {
"Price":price_s[i],
"Bid":{ "Value":Bid_s[i]},
"Ask":{ "Value":Ask_s[i]}
}
if i>=0 and i<len(price_s)-1:
if (order["Bid"]["Value"]>Ask_s[i+1]*int(Config['Value1'])):
order["Bid"]["Color"]=itemAskBG[1]
gxx+=1
gj+=1
if gj>=int(Config['Value2']) and Config['Value4']==True:
duiji['price']=price_s[i]
duiji['time']=dtime
duiji['longshort']=-1
duiji['cout']=gj
duiji['color']='rgba(0,139,0,0.45)'#绿色
if float(duiji['price'])>0:
djcout+=-1
else :
gj=0
if i>=1 and i<=len(price_s)-1:
if (order["Ask"]["Value"]>Bid_s[i-1]*int(Config['Value1'])):
xq+=1
xxx+=1
order["Ask"]["Color"]=itemBidBG[1]
if xq>=int(Config['Value2']) and Config['Value4']==True:
duiji['price']=price_s[i]
duiji['time']=dtime
duiji['longshort']=1
duiji['cout']=xq
duiji['color']='rgba(255,0,0,0.45)' #红色
if float(duiji['price'])>0:
djcout+=1
else :
xq=0
return djcout
def back_data(df,csv_path):
# 创建新的DataFrame并填充需要的列
new_df = pd.DataFrame()
new_df['datetime'] = pd.to_datetime(df['datetime'], format='%Y/%m/%d %H:%M')
new_df['close'] = df['close']
new_df['open'] = df['open']
new_df['high'] = df['high']
new_df['low'] = df['low']
new_df['volume'] = df['volume']
new_df['sig'] = df['dj']
new_df['symbol'] = df['symbol']
new_df['delta'] = df['delta']
new_df.to_csv(csv_path,index=False)
#new_df.to_csv(f'{sym}back_ofdata_dj.csv',index=False)
def ofdata_dj(file, cycle):
print("file:", file)
csv_df = pd.DataFrame()
dir = os.getcwd()
fileNum_errors = 0
try:
# 读取csv文件并使用第一行为列标题编译不通过可以改为gbk
csv_df = pd.read_csv(file,encoding='GBK',parse_dates=['datetime'])
except:
file_path = os.path.join(dir, file)
fileNum_errors += 1
with open(file_path, 'rb') as file:
data = file.read()
# 使用chardet检测编码
detected_encoding = chardet.detect(data)['encoding']
# print("%s当前文件不为gbk格式,其文件格式为%s,需要转换为gbk格式,错误总数为%s"%(file,detected_encoding,fileNum_errors))
print("%s:%s当前文件不为gbk格式,其文件格式为%s,需要转换为gbk格式,错误总数为%s"%(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),file_path,detected_encoding,fileNum_errors))
with open('output_error.txt', 'a') as f:
print("%s:%s当前文件不为gbk格式,其文件格式为%s,需要转换为gbk格式,错误总数为%s"%(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),file_path,detected_encoding,fileNum_errors), file = f)
# print(csv_df)
tick,bar=dataload(csv_df,cycle)
ofdata = orderflow_df_new(tick,bar)
print(ofdata)
code_value = csv_df.loc[0, 'main_contract']# csv_df['main_contract'].keys
return code_value, ofdata

View File

@@ -0,0 +1,319 @@
'''逐行解释代码:
1.导入所需的模块和库,包括 time、table来自 matplotlib.pyplot、pandas、numpy、numba 和 operator。
2.定义了一个名为 process 的函数,用于处理买卖盘的字典数据。
3.定义了一个名为 data 的函数,用于读取并处理 tick 数据,生成分钟级别的 bar 数据。
4.定义了一个名为 orderflow_df_new 的函数,用于处理 tick 数据和分钟级别的 bar 数据,生成订单流数据。
5.定义了一个名为 GetOrderFlow_dj 的函数,用于计算订单流的指标(堆积)。
6.定义了一个名为 back_data 的函数,用于保存回测数据。
7.在 if __name__ == "__main__": 下,首先调用 data() 函数获取 tick 数据和分钟级别的 bar 数据。
然后调用 orderflow_df_new() 函数,传入 tick 数据和 bar 数据,生成订单流数据 ofdata。
打印输出 ofdata。
8.调用 back_data() 函数,将订单流数据保存为回测数据。
打印输出 "done",表示程序执行完毕。
总体而言,该代码的功能是从 tick 数据中生成分钟级别的 bar 数据,然后根据 bar 数据计算订单流,并将订单流数据保存为回测数据。
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# 使用前注意事项:
1、修改read_csv对应的文件地址
2、修改resample对应的转化周期
3、修改folder_path、to_csv对应的保存路径
'''
import time
from matplotlib.pyplot import table
from datetime import timedelta
import pandas as pd
import numpy as np
from numba import *
from numba import cuda
import operator
import os
def process(bidDict,askDict):
bidDictResult,askDictResult = {},{}
sList = sorted(set(list(bidDict.keys()) + list(askDict.keys())))
#print('bidDict:',list(bidDict.keys()))
#print('askDict:',list(askDict.keys()))
#print('sList:',sList)
#240884432
for s in sList:
if s in bidDict:
bidDictResult[s] = bidDict[s]
else:
bidDictResult[s] = 0
if s in askDict:
askDictResult[s] = askDict[s]
else:
askDictResult[s] = 0
return bidDictResult,askDictResult
def dataload(data):
#日期修正
# data['业务日期'] = data['业务日期'].dt.strftime('%Y-%m-%d')
# data['datetime'] = data['业务日期'] + ' '+data['最后修改时间'].dt.time.astype(str) + '.' + data['最后修改毫秒'].astype(str)
# # 将 'datetime' 列的数据类型更改为 datetime 格式
data['datetime'] = pd.to_datetime(data['datetime'], errors='coerce', format='%Y-%m-%d %H:%M:%S.%f')
# 如果需要,可以将 datetime 列格式化为字符串
#data['formatted_date'] = data['datetime'].dt.strftime('%Y-%m-%d %H:%M:%S.%f')
#计算瞬时成交量
# data['volume'] = data['数量'] - data['数量'].shift(1)
data['volume'] = data['volume'].fillna(0)
#整理好要用的tick数据元素
tickdata =pd.DataFrame({'datetime':data['datetime'],'symbol':data['symbol'],'lastprice':data['lastprice'],
'volume':data['volume'],'bid_p':data['bid_p'],'bid_v':data['bid_v'],'ask_p':data['ask_p'],'ask_v':data['ask_v']})
#tickdata['datetime'] = pd.to_datetime(tickdata['datetime'])
tickdata['open'] = tickdata['lastprice']
tickdata['high'] = tickdata['lastprice']
tickdata['low'] = tickdata['lastprice']
tickdata['close'] = tickdata['lastprice']
tickdata['starttime'] = tickdata['datetime']
# # 找到满足条件的行的索引
# condition = tickdata['datetime'].dt.time == pd.to_datetime('22:59:59').time()
# indexes_to_update = tickdata.index[condition]
# # 遍历索引,将不一致的日期更新为上一行的日期
# for idx in indexes_to_update:
# if idx > 0:
# tickdata.at[idx, 'datetime'] = tickdata.at[idx - 1, 'datetime'].replace(hour=22, minute=59, second=59)
# 确保日期列按升序排序
tickdata.sort_values(by='datetime', inplace=True)
bardata = tickdata.resample(on = 'datetime',rule = '1T',label = 'right',closed = 'right').agg({'starttime':'first','symbol':'last','open':'first','high':'max','low':'min','close':'last','volume':'sum'}).reset_index(drop = False)
#240884432
bardata =bardata.dropna().reset_index(drop = True)
return tickdata,bardata
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
def orderflow_df_new(df_tick,df_min):
df_of=pd.DataFrame({})
t1 = time.time()
startArray = pd.to_datetime(df_min['starttime']).values
voluememin= df_min['volume'].values
highs=df_min['high'].values
lows=df_min['low'].values
opens=df_min['open'].values
closes=df_min['close'].values
endArray = pd.to_datetime(df_min['datetime']).values
tTickArray = pd.to_datetime(df_tick['datetime']).values
bp1TickArray = df_tick['bid_p'].values
ap1TickArray = df_tick['ask_p'].values
lastTickArray = df_tick['lastprice'].values
volumeTickArray = df_tick['volume'].values
symbolarray = df_tick['symbol'].values
indexFinal = 0
for index,tEnd in enumerate(endArray):
start = startArray[index]
bidDict = {}
askDict = {}
bar_vol=voluememin[index]
bar_close=closes[index]
bar_open=opens[index]
bar_low=lows[index]
bar_high=highs[index]
bar_symbol=symbolarray[index]
dt=endArray[index]
for indexTick in range(indexFinal,len(df_tick)):
if tTickArray[indexTick] > tEnd:
break
elif (tTickArray[indexTick] >= start) & (tTickArray[indexTick] <= tEnd):
if indexTick==0:
Bp = round(bp1TickArray[indexTick],2)
Ap = round(ap1TickArray[indexTick],2)
else:
Bp = round(bp1TickArray[indexTick - 1],2)
Ap = round(ap1TickArray[indexTick - 1],2)
LastPrice = round(lastTickArray[indexTick],2)
Volume = volumeTickArray[indexTick]
if LastPrice >= Ap:
if LastPrice in askDict.keys():
askDict[LastPrice] += Volume
else:
askDict[LastPrice] = Volume
if LastPrice <= Bp:
if LastPrice in bidDict.keys():
bidDict[LastPrice] += Volume
else:
bidDict[LastPrice] = Volume
indexFinal = indexTick
bidDictResult,askDictResult = process(bidDict,askDict)
bidDictResult=dict(sorted(bidDictResult.items(),key=operator.itemgetter(0)))
askDictResult=dict(sorted(askDictResult.items(),key=operator.itemgetter(0)))
prinslist=list(bidDictResult.keys())
asklist=list(askDictResult.values())
bidlist=list(bidDictResult.values())
delta=(sum(askDictResult.values()) - sum(bidDictResult.values()))
df=pd.DataFrame({'price':pd.Series([prinslist]),'Ask':pd.Series([asklist]),'Bid':pd.Series([bidlist])})
df['symbol']=bar_symbol
df['datetime']=dt
df['delta']=str(delta)
df['close']=bar_close
df['open']=bar_open
df['high']=bar_high
df['low']=bar_low
df['volume']=bar_vol
# 过滤'volume'列小于等于0的行
df = df[df['volume'] > 0]
# 重新排序DataFrame按照'datetime'列进行升序排序
df = df.sort_values(by='datetime', ascending=True)
# 重新设置索引,以便索引能够正确对齐
df = df.reset_index(drop=True)
#df['ticktime']=tTickArray[indexTick]
df['dj']=GetOrderFlow_dj(df)
#print(df)
df_of = pd.concat([df_of, df], ignore_index=True)
print(time.time() - t1)
return df_of
def GetOrderFlow_dj(kData):
itemAskBG=['rgb(0,255,255)', 'rgb(255,0,255)', "rgb(255,182,193)"] # 买盘背景色
itemBidBG=['rgb(173,255,47)', 'rgb(255,127,80)', "rgb(32,178,170)"] # 卖盘背景色
Config={
'Value1':3,
'Value2':3,
'Value3':3,
'Value4':True,
}
aryData=kData
djcout=0
for index,row in aryData.iterrows():
kItem=aryData.iloc[index]
high=kItem['high']
low=kItem['low']
close=kItem['close']
open=kItem['open']
dtime=kItem['datetime']
price_s=kItem['price']
Ask_s=kItem['Ask']
Bid_s=kItem['Bid']
delta=kItem['delta']
price_s=price_s
Ask_s=Ask_s
Bid_s=Bid_s
gj=0
xq=0
gxx=0
xxx=0
for i in np.arange (0, len(price_s),1) :
duiji={
'price':0,
'time':0,
'longshort':0,
'cout':0,
'color':'blue'
}
if i==0 :
delta=delta
order= {
"Price":price_s[i],
"Bid":{ "Value":Bid_s[i]},
"Ask":{ "Value":Ask_s[i]}
}
if i>=0 and i<len(price_s)-1:
if (order["Bid"]["Value"]>Ask_s[i+1]*int(Config['Value1'])):
order["Bid"]["Color"]=itemAskBG[1]
gxx+=1
gj+=1
if gj>=int(Config['Value2']) and Config['Value4']==True:
duiji['price']=price_s[i]
duiji['time']=dtime
duiji['longshort']=-1
duiji['cout']=gj
duiji['color']='rgba(0,139,0,0.45)'#绿色
if float(duiji['price'])>0:
djcout+=-1
else :
gj=0
if i>=1 and i<=len(price_s)-1:
if (order["Ask"]["Value"]>Bid_s[i-1]*int(Config['Value1'])):
xq+=1
xxx+=1
order["Ask"]["Color"]=itemBidBG[1]
if xq>=int(Config['Value2']) and Config['Value4']==True:
duiji['price']=price_s[i]
duiji['time']=dtime
duiji['longshort']=1
duiji['cout']=xq
duiji['color']='rgba(255,0,0,0.45)' #红色
if float(duiji['price'])>0:
djcout+=1
else :
xq=0
return djcout
def back_data(df):
# 创建新的DataFrame并填充需要的列
new_df = pd.DataFrame()
new_df['datetime'] = pd.to_datetime(df['datetime'], format='%Y/%m/%d %H:%M')
new_df['close'] = df['close']
new_df['open'] = df['open']
new_df['high'] = df['high']
new_df['low'] = df['low']
new_df['volume'] = df['volume']
new_df['sig'] = df['dj']
new_df['symbol'] = df['symbol']
new_df['delta'] = df['delta']
new_df.to_csv(f'./rb888_rs_2022_back_ofdata_dj.csv',index=False)
#new_df.to_csv(f'{sym}back_ofdata_dj.csv',index=False)
if __name__ == "__main__":
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
data=pd.read_csv('D:/data_transfer/data_rs_merged/上期所/rb888/rb888_rs_2022.csv',encoding='GBK',parse_dates=['datetime']) # ['业务日期','最后修改时间']
print(data)
tick,bar=dataload(data)
ofdata = orderflow_df_new(tick,bar)
print(ofdata)
#保存orderflow数据
folder_path = 'D:/of_data/tick生成的OF数据/data_rs_merged/上期所/rb888/'
if not os.path.exists(folder_path):
# os.mkdir(folder_path)
os.makedirs(folder_path)
# 获取当前工作目录
current_directory = os.getcwd()
print("当前工作目录:", current_directory)
# 设置新的工作目录
os.chdir(folder_path)
# 验证新的工作目录
updated_directory = os.getcwd()
print("已更改为新的工作目录:", updated_directory)
ofdata.to_csv('./rb888_rs_2022_ofdata_dj.csv')
#保存回测数据
back_data(ofdata)
print('done')

Some files were not shown because too many files have changed in this diff Show More