功能包

前言

  相比普通的k线数据,tick级别的数据量极其庞大,几十TB的硬盘说满就满!对一些机构来说与其花费大量的成本去维护一套tick数据,不如试试直接使用wh9软件来开发模型。

  wh9除了提供基本的每笔成交、五档委托价、委托量数据以外,还提供报价列表中资金流向、开平仓信息、速涨、振幅、内外盘比例等文华特色抬头历史数据。各品种任意交易日的tick数据可直接调用,为高频模型回测提供充分的验证样本。

优势

  • 资金流向、开平仓、速涨、振幅、内外盘比例等文华统计数据,助力研发更多高频策略。
  • 提供任意交易日的TICK数据可供高频模型回测。
  • 大商所和郑商所品种提供每秒最多4笔的高频TICK数据。

前言

  高频交易策略不再需要真金白银的实盘测试,国内率先支持虚拟撮合的回测平台帮你验证模型好坏!

  wh9的虚拟撮合机制,既考虑到了委托价等于对手价时,对手盘挂单量不足,部分成交的情况,同时,当委托价等于排队价时,还会计算挂单成交比例,按比例撮合成交,完美虚拟真实交易过程。

  可视化的盘口算法模型回测平台,能够同时展示tick数据变化、持仓信息、挂单详情、以及权益曲线变化过程,并提供360度视角的多维度回测报告。

优势

  • 提供可视化的高频模型回测平台,虚拟撮合支持部分成交。
  • 360度视角的多维度回测报告,提供全面的回测信息。

前言

  算法交易运行池是高频策略和算法交易策略的运行平台。

  可视化的运行平台,提供tick图监控页面,不放过任何一个交易细节。

  可比肩C++程序的运行速度,保证每一笔委托能够快速发出,降低成交滑点,提高交易效率。

优势

  • 可视化的算法模型运行平台,提供tick图监控页面;
  • 比肩C++程序的运行速度。

前言

  手动炒单下单慢、滑点大!白盘、夜盘两班倒,精力跟不上?wh9高频策略量化来帮忙,计算机代替人工进行炒单,不放过任何一个交易机会!

  wh9的高频策略量化提供了类C语言的编写平台,自由度高,运行速度快。不仅可以引用盘口的成交数据,五档数据,还能引用报价列表中速涨、振幅、内外盘比例、资金流向等特色抬头数据,能够把你的各种盘感写成盘口算法模型。

优势

  • 模型中可以引用盘口数据和报价列表的特色抬头数据。
  • 类c语言的语法,支持各种复杂策略,帮助把你的盘感写成盘口算法模型。

前言

  期权市场合约众多,各种波动套利影响因素多、算法复杂,即使出现了套利机会,人工也很难捕捉到。而且很多期权合约交易不活跃,即使价格满足套利条件,也很难确保成交。

  使用期权算法交易,可对全市场的期权合约报价进行实时监控,当出现套利机会时,算法交易还可以根据当前盘口的挂单状态,自动调整下单手数和委托价格,提高交易成功率。

优势

  • 提供期权行情函数,可直接引用波动率等数据。
  • 全市场实时监控,自动捕获期权各种套利机会。
  • 支持对期权交易过程精细控制,提高交易成功率。

案例

案例一:期权定价模型

1、什么是期权定价公式

Black-Scholes-Merton期权定价模型(Black-Scholes-Merton Option Pricing Model),即布莱克—斯克尔斯期权定价模型。

B-S-M定价公式:C=S·N(d1)-X·exp(-r·T)·N(d2)

其中:

d1=[ln(S/X)+(r+σ^2/2)T]/(σ√T) d2=d1-σ·√T

C—期权初始合理价格 X—期权执行价格

S—所交易金融资产现价T—期权有效期

r—连续复利计无风险利率

σ—股票连续复利(对数)回报率的年度波动率(标准差)

N(d1),N(d2)—正态分布变量的累积概率分布函数,在此应当说明两点:

第一,该模型中无风险利率必须是连续复利形式。一个简单的或不连续的无风险利率(设为r0)一般是一年计息一次,而r要求为连续复利利率。r0必须转化为r方能代入上式计算。

两者换算关系为:r=LN(1+r0)或r0=exp(r)-1例如r0=0.06,则r=LN(1+0.06)=0.0583,即100以583%的连续复利投资第二年将获106,该结果与直接用r0=0.06计算的答案一致。

第二,期权有效期T的相对数表示,即期权有效天数与一年365天的比值。如果期权有效期为100天,则T=100/365=0.274。


2、年化波动率及BS公式函数计算

①计算年化波动率:

记录收盘价:CallOptions.PutOptions

计算对数Ln(今日收盘价/昨日收盘价)

计算N天的标准差:如N天标准差=STD()

计算N天的波动率:N天的标准差*SQRT(252)

计算年化的波动率:N天波动率/SQRT(2N)

②推导理论价格计算案例

例如:某股票市价为3.84元,无风险利率为6%,年波动率为15%,求工商银行行权价为3.6元、期限为半年的欧式认购期权和认沽期权价格,其中:期限内不支付红利。

此例中S=3.84,K=3.6,r=0.06,σ=0.15,T=0.5。

计算过程可分为三步:

第一步,先计算出和。






第二步,计算和。由标准正态分布表可查的



则可得



第三步,将上述结果及已知条件代入B-S公式,股票欧式认购期权价格为:



欧式认沽期权价格为:




3、B-S-M模型失效或者可能误差的原因:

①模型对平值期权的估价令人满意,特别是对剩余有效期限超过两月,且不支付红利者效果更好一点。

②对于高度增值或减值的期权,模型的估价有较大偏差,会高估减值期权而低估增值期权。

③对临近到期日的期权的估价存在一定的误差。

④离散度过高或过低的情况下,会低估低离散度的买入期权,高估高离散度的买方期权。

⑤模型基于对市场部分情况的假设条件过于严苛,这与现实情况有所差别,可能会影响到模型的可靠性。


4、根据以上推导过程,编写策略模型计算期权理论价格,形成套利策略如下:

Data
	CODC0:"m2209-C-4200"; //看涨期权
	CODP0:"m2209-P-4200"; //看跌期权
	CODC1:"m2209-C-4150"; //看涨期权
	CODP1:"m2209-P-4150"; //看跌期权
	CODC2:"m2209-C-4100"; //看涨期权
	CODP2:"m2209-P-4100"; //看跌期权
	CODC3:"m2209-C-4050"; //看涨期权
	CODP3:"m2209-P-4050"; //看跌期权
	CODC4:"m2209-C-4000"; //看涨期权
	CODP4:"m2209-P-4000"; //看跌期权
	COD:"m2209"; //标的期货
Vars
	StringArray CODC; //看涨期权
	StringArray CODP; //看跌期权
	String CODF; //标的期货
	Numeric CDN; //期权合约数量
	Numeric N; //下单手数
	Numeric X; //循环变量
	Numeric R; //无风险收益率
	Numeric D; //日期间隔
	Numeric P; //条件比例
	Numeric TKN; //数据区长度
	Numeric TOD; //当前日期
	Numeric NEWPF; //F最新价
	Numeric HVLF; //F价格波动率
	Numeric RLPF,FLPF; //F涨跌停价
	Numeric BIDPF,ASKPF; //F买卖一价
	Numeric BRPF,SRPF; //F多空头可用持仓
	Numeric OPFLG; //模型处理标志
	Var_TickData TKD; //数据区
	NumericArray STP; //行权价
	NumericArray LNP; //自然对数
	NumericArray NEWPC; //C最新价
	NumericArray NEWPP; //P最新价
	NumericArray EPDC; //C行权日期
	NumericArray EPDP; //P行权日期
	NumericArray HVLC; //C历史波动率
	NumericArray HVLP; //P历史波动率
	NumericArray THPC; //C理论价格
	NumericArray THPP; //P理论价格
	NumericArray RTS; //距行权日剩余天数
	NumericArray D1,D2; //中间值
	NumericArray STRC; //C隐含波动率
	NumericArray STRP; //P隐含波动率
	NumericArray RLPC,FLPC; //C涨跌停价
	NumericArray RLPP,FLPP; //P涨跌停价
	NumericArray BIDPC,ASKPC; //C买卖一价
	NumericArray BIDPP,ASKPP; //P买卖一价
	NumericArray BRPC,SRPC; //C多空头可用持仓
	NumericArray BRPP,SRPP; //P多空头可用持仓
	NumericArray BKDFLGC,SKDFLGC; //C开仓处理标志
	NumericArray BPDFLGC,SPDFLGC; //C平仓处理标志
	NumericArray BKDFLGP,SKDFLGP; //P开仓处理标志
	NumericArray BPDFLGP,SPDFLGP; //P平仓处理标志
	NumericArray BKDFLGF,SKDFLGF; //F开仓处理标志
	NumericArray BPDFLGF,SPDFLGF; //F平仓处理标志
	Global_NumericArray BCFLG; //多头处理标志
	Global_NumericArray SCFLG; //空头处理标志
	Global_NumericArray BKIDC,SKIDC; //C开仓委托
	Global_NumericArray BPIDC,SPIDC; //C平仓委托
	Global_NumericArray BKIDP,SKIDP; //P开仓委托
	Global_NumericArray BPIDP,SPIDP; //P平仓委托
	Global_NumericArray BKIDF,SKIDF; //F开仓委托
	Global_NumericArray BPIDF,SPIDF; //F平仓委托
	Global_NumericArray BKFLGC,SKFLGC; //C开仓标志
	Global_NumericArray BPFLGC,SPFLGC; //C平仓标志
	Global_NumericArray BKFLGP,SKFLGP; //P开仓标志
	Global_NumericArray BPFLGP,SPFLGP; //P平仓标志
	Global_NumericArray BKFLGF,SKFLGF; //F开仓标志
	Global_NumericArray BPFLGF,SPFLGF; //F平仓标志
	Global_NumericArray BKMC,SKMC; //C开仓委托手数
	Global_NumericArray BPMC,SPMC; //C平仓委托手数
	Global_NumericArray BKMP,SKMP; //P开仓委托手数
	Global_NumericArray BPMP,SPMP; //P平仓委托手数
	Global_NumericArray BKMF,SKMF; //F开仓委托手数
	Global_NumericArray BPMF,SPMF; //F平仓委托手数
	Global_NumericArray BKPC,SKPC; //C开仓委托价格
	Global_NumericArray BPPC,SPPC; //C平仓委托价格
	Global_NumericArray BKPP,SKPP; //P开仓委托价格
	Global_NumericArray BPPP,SPPP; //P平仓委托价格
	Global_NumericArray BKPF,SKPF; //F开仓委托价格
	Global_NumericArray BPPF,SPPF; //F平仓委托价格
Begin
	//------------------------处理开启------------------------//
	If(1) //处理开启
	{
		CODC[0] = "m2209-C-4200"; //看涨期权
		CODP[0] = "m2209-P-4200"; //看跌期权
		CODC[1] = "m2209-C-4150"; //看涨期权
		CODP[1] = "m2209-P-4150"; //看跌期权
		CODC[2] = "m2209-C-4100"; //看涨期权
		CODP[2] = "m2209-P-4100"; //看跌期权
		CODC[3] = "m2209-C-4050"; //看涨期权
		CODP[3] = "m2209-P-4050"; //看跌期权
		CODC[4] = "m2209-C-4000"; //看涨期权
		CODP[4] = "m2209-P-4000"; //看跌期权
		CDN = GetStringArraySize(CODC); //期权合约数量
		CODF = "m2209"; //标的期货
		OPFLG = 1; //开启模型处理
		If(CODF.A_IsExchangeOpen() != 1) //如果非开盘状态
		{
			OPFLG = 2; //关闭模型处理
		}
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(CODC[X].A_IsExchangeOpen() != 1 || CODP[X].A_IsExchangeOpen() != 1) //如果非开盘状态
			{
				OPFLG = 2; //关闭模型处理
			}
		}
	}
	//------------------------变量赋值------------------------//
	If(OPFLG == 1) //变量赋值
	{
		N = 10; //下单手数
		R = 1; //无风险收益率
		D = 5; //日期间隔
		P = 0.5; //条件比例
		TOD = CurrentDate(); //当前日期
		NEWPF = CODF.Price("New"); //F最新价
		BIDPF = CODF.Price("Bid1"); //F买一价
		ASKPF = CODF.Price("Ask1"); //F卖一价
		RLPF = CODF.Price("RiseLimit"); //F涨停价
		FLPF = CODF.Price("FallLimit"); //F跌停价
		BIDPF = IIF(BIDPF == 0 && NEWPF == FLPF,FLPF,BIDPF); //F买一价
		ASKPF = IIF(ASKPF == 0 && NEWPF == RLPF,RLPF,ASKPF); //F卖一价
		BRPF = CODF.F_BuyRemainPosition(); //F多头可用持仓
		SRPF = CODF.F_SellRemainPosition(); //F空头可用持仓
		BRPF = Min(BRPF,CODF.A_BuyRemainPosition()); //F多头可用持仓
		SRPF = Min(SRPF,CODF.A_SellRemainPosition()); //F空头可用持仓
		For X = 0 To CDN - 1 //遍历期权合约
		{
			NEWPC[X] = CODC[X].Price("New"); //C最新价
			NEWPP[X] = CODP[X].Price("New"); //P最新价
			BIDPC[X] = CODC[X].Price("Bid1"); //C买一价
			ASKPC[X] = CODC[X].Price("Ask1"); //C卖一价
			BIDPP[X] = CODP[X].Price("Bid1"); //P买一价
			ASKPP[X] = CODP[X].Price("Ask1"); //P卖一价
			RLPC[X] = CODC[X].Price("RiseLimit"); //C涨停价
			FLPC[X] = CODC[X].Price("FallLimit"); //C跌停价
			RLPP[X] = CODP[X].Price("RiseLimit"); //P涨停价
			FLPP[X] = CODP[X].Price("FallLimit"); //P跌停价
			BIDPC[X] = IIF(BIDPC[X] == 0 && NEWPC[X] == FLPC[X],FLPC[X],BIDPC[X]); //C买一价
			ASKPC[X] = IIF(ASKPC[X] == 0 && NEWPC[X] == RLPC[X],RLPC[X],ASKPC[X]); //C卖一价
			BIDPP[X] = IIF(BIDPP[X] == 0 && NEWPP[X] == FLPP[X],FLPP[X],BIDPP[X]); //P买一价
			ASKPP[X] = IIF(ASKPP[X] == 0 && NEWPP[X] == RLPP[X],RLPP[X],ASKPP[X]); //P卖一价
			STP[X] = CODC[X].Price("StrikePrice"); //行权价
			STRC[X] = CODC[X].Price("Stdderiation"); //C隐含波动率
			STRP[X] = CODP[X].Price("Stdderiation"); //P隐含波动率
			HVLC[X] = CODC[X].Price("HistoricalVolatility"); //C历史波动率
			HVLP[X] = CODP[X].Price("HistoricalVolatility"); //P历史波动率
			EPDC[X] = CODC[X].Price("ExpirationDate"); //C行权日期
			EPDP[X] = CODP[X].Price("ExpirationDate"); //P行权日期
			RTS[X] = DateDiff(TOD,EPDC[X] ); //距行权日剩余天数
			BRPC[X] = CODC[X].F_BuyRemainPosition(); //C多头可用持仓
			SRPC[X] = CODC[X].F_SellRemainPosition(); //C空头可用持仓
			BRPP[X] = CODP[X].F_BuyRemainPosition(); //P多头可用持仓
			SRPP[X] = CODP[X].F_SellRemainPosition(); //P空头可用持仓
			BRPC[X] = Min(BRPC[X],CODC[X].A_BuyRemainPosition()); //C多头可用持仓
			SRPC[X] = Min(SRPC[X],CODC[X].A_SellRemainPosition()); //C空头可用持仓
			BRPP[X] = Min(BRPP[X],CODP[X].A_BuyRemainPosition()); //P多头可用持仓
			SRPP[X] = Min(SRPP[X],CODP[X].A_SellRemainPosition()); //P空头可用持仓
		}
	}
	//------------------------数据取值------------------------//
	If(OPFLG == 1) //数据取值
	{
		TKD = Def_TickData(CODF,1,11); //数据区
		If(TKD.State == 1) //如果数据区有效
		{
			TKN = TKD.Num; //数据区长度
			For X = 1 To TKN - 1 //遍历数据区
			{
				LNP[X - 1] = Ln(TKD[X].TickPrice / TKD[X - 1].TickPrice); //自然对数
			}
			HVLF = StandardDevArray(LNP,2) * Sqrt(252); //F价格波动率
			For X = 0 To CDN - 1 //遍历期权合约
			{
				D1[X] = (Ln(NEWPF / STP[X]) + (R / 10 + 0.5 * Power(HVLF,2)) * RTS[X]) / (HVLF * Power(RTS[X],0.5)); //期权理论价格中间值
				D2[X] = D1[X] - HVLF * Power(RTS[X],0.5); //期权理论价格中间值
				THPC[X] = NEWPF * NormalSCDensity(D1[X]) - STP[X] * Exp(-1 * (R / 10) * RTS[X]) * NormalSCDensity(D2[X]); //根据B-S-M公式计算看涨期权理论价格
				THPP[X] = STP[X] * Exp(-1 * (R / 10) * RTS[X]) * (1 - NormalSCDensity(D2[X])) - NEWPF * (1 - NormalSCDensity(D1[X])); //根据B-S-M公式计算看跌期权理论价格
			}
		}
		Else //如果数据区无效
		{
			OPFLG = 2; //关闭模型处理
		}
	}
	//------------------------成交判断------------------------//
	If(OPFLG == 1) //成交判断
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(BKFLGF[X] == 1) //如果有F买开委托
			{
				If(F_OrderStatus(BKIDF[X]) == Enum_Filled) //如果F买开委托成交
				{
					Commentary("【多头开仓:F买开委托" + Text(X + 1) + "成交!】");
					BKFLGF[X] = 0; //F买开标志归0
				}
				Else If(F_OrderStatus(BKIDF[X]) == Enum_Deleted) //如果F买开委托废单
				{
					Commentary("【多头开仓:F买开委托" + Text(X + 1) + "废单!】");
					BKFLGF[X] = 0; //F买开标志归0
				}
			}
			If(BKFLGP[X] == 1) //如果有P买开委托
			{
				If(F_OrderStatus(BKIDP[X]) == Enum_Filled) //如果P买开委托成交
				{
					Commentary("【多头开仓:P买开委托" + Text(X + 1) + "成交!】");
					BKFLGP[X] = 0; //P买开标志归0
				}
				Else If(F_OrderStatus(BKIDP[X]) == Enum_Deleted) //如果P买开委托废单
				{
					Commentary("【多头开仓:P买开委托" + Text(X + 1) + "废单!】");
					BKFLGP[X] = 0; //P买开标志归0
				}
			}
			If(SPFLGF[X] == 1) //如果有F卖平委托
			{
				If(F_OrderStatus(SPIDF[X]) == Enum_Filled) //如果F卖平委托成交
				{
					Commentary("【多头平仓:F卖平委托" + Text(X + 1) + "成交!】");
					SPFLGF[X] = 0; //F卖平标志归0
				}
				Else If(F_OrderStatus(SPIDF[X]) == Enum_Deleted) //如果F卖平委托废单
				{
					Commentary("【多头平仓:F卖平委托" + Text(X + 1) + "废单!】");
					SPFLGF[X] = 0; //F卖平标志归0
				}
			}
			If(SPFLGP[X] == 1) //如果有P卖平委托
			{
				If(F_OrderStatus(SPIDP[X]) == Enum_Filled) //如果P卖平委托成交
				{
					Commentary("【多头平仓:P卖平委托" + Text(X + 1) + "成交!】");
					SPFLGP[X] = 0; //P卖平标志归0
				}
				Else If(F_OrderStatus(SPIDP[X]) == Enum_Deleted) //如果P卖平委托废单
				{
					Commentary("【多头平仓:P卖平委托" + Text(X + 1) + "废单!】");
					SPFLGP[X] = 0; //P卖平标志归0
				}
			}
			If(SKFLGF[X] == 1) //如果有F卖开委托
			{
				If(F_OrderStatus(SKIDF[X]) == Enum_Filled) //如果F卖开委托成交
				{
					Commentary("【空头开仓:F卖开委托" + Text(X + 1) + "成交!】");
					SKFLGF[X] = 0; //F卖开标志归0
				}
				Else If(F_OrderStatus(SKIDF[X]) == Enum_Deleted) //如果F卖开委托废单
				{
					Commentary("【空头开仓:F卖开委托" + Text(X + 1) + "废单!】");
					SKFLGF[X] = 0; //F卖开标志归0
				}
			}
			If(BKFLGC[X] == 1) //如果有C买开委托
			{
				If(F_OrderStatus(BKIDC[X]) == Enum_Filled) //如果C买开委托成交
				{
					Commentary("【空头开仓:C买开委托" + Text(X + 1) + "成交!】");
					BKFLGC[X] = 0; //C买开标志归0
				}
				Else If(F_OrderStatus(BKIDC[X]) == Enum_Deleted) //如果C买开委托废单
				{
					Commentary("【空头开仓:C买开委托" + Text(X + 1) + "废单!】");
					BKFLGC[X] = 0; //C买开标志归0
				}
			}
			If(BPFLGF[X] == 1) //如果有F买平委托
			{
				If(F_OrderStatus(BPIDF[X]) == Enum_Filled) //如果F买平委托成交
				{
					Commentary("【空头平仓:F买平委托" + Text(X + 1) + "成交!】");
					BPFLGF[X] = 0; //F买平标志归0
				}
				Else If(F_OrderStatus(BPIDF[X]) == Enum_Deleted) //如果F买平委托废单
				{
					Commentary("【空头平仓:F买平委托" + Text(X + 1) + "废单!】");
					BPFLGF[X] = 0; //F买平标志归0
				}
			}
			If(SPFLGC[X] == 1) //如果有C卖平委托
			{
				If(F_OrderStatus(SPIDC[X]) == Enum_Filled) //如果C卖平委托成交
				{
					Commentary("【空头平仓:C卖平委托" + Text(X + 1) + "成交!】");
					SPFLGC[X] = 0; //C卖平标志归0
				}
				Else If(F_OrderStatus(SPIDC[X]) == Enum_Deleted) //如果C卖平委托废单
				{
					Commentary("【空头平仓:C卖平委托" + Text(X + 1) + "废单!】");
					SPFLGC[X] = 0; //C卖平标志归0
				}
			}
		}
	}
	//------------------------多空处理------------------------//
	If(OPFLG == 1) //多空处理
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(BKFLGF[X] == 0 && SPFLGF[X] == 0 && BKFLGP[X] == 0 && SPFLGP[X] == 0 &&
				SKFLGF[X] == 0 && BPFLGF[X] == 0 && BKFLGC[X] == 0 && SPFLGC[X] == 0) //如果没有开平仓委托
			{
				If(DateDiff(TOD,EPDC[X]) > D && DateDiff(TOD,EPDP[X]) > D) //如果满足开仓条件
				{
					If(BCFLG[X] == 0) //如果未执行多头开仓
					{
						If(THPP[X] > P * NEWPP[X] && STRP[X] > HVLP[X]) //如果满足多头开仓条件
						{
							BKDFLGF[X] = 1; //开启F买开处理
							BKDFLGP[X] = 1; //开启P买开处理
							BCFLG[X] = 1; //已执行多头开仓
						}
					}
					If(SCFLG[X] == 0) //如果未执行空头开仓
					{
						If(NEWPC[X] < P * THPC[X] && STRC[X] < HVLC[X]) //如果满足空头开仓条件
						{
							SKDFLGF[X] = 1; //开启F卖开处理
							BKDFLGC[X] = 1; //开启C买开处理
							SCFLG[X] = 1; //已执行空头开仓
						}
					}
				}
				Else If(DateDiff(TOD,EPDC[X]) <= D || DateDiff(TOD,EPDP[X]) <= D) //如果满足平仓条件
				{
					If(BCFLG[X] == 1) //如果已执行多头开仓
					{
						SPDFLGF[X] = 1; //开启F卖平处理
						SPDFLGP[X] = 1; //开启P卖平处理
						BCFLG[X] = 0; //多头处理标志归0
					}
					If(SCFLG[X] == 1) //如果已执行空头开仓
					{
						BPDFLGF[X] = 1; //开启F买平处理
						SPDFLGC[X] = 1; //开启C卖平处理
						SCFLG[X] = 0; //空头处理标志归0
					}
				}
			}
		}
	}
	//------------------------委托处理------------------------//
	If(OPFLG == 1) //委托处理
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(BKDFLGF[X] == 1) //如果已开启F买开处理
			{
				If(BKFLGF[X] == 0) //如果没有F买开委托
				{
					BKMF[X] = N; //F买开委托手数
					BKPF[X] = ASKPF; //F买开委托价格
					Commentary("【多头开仓:F买开委托" + Text(X + 1) + "发出!】");
					BKIDF[X] = CODF.A_SendOrder(Enum_Buy,Enum_Entry,BKMF[X],BKPF[X]); //发出F买开委托
					BKFLGF[X] = 1; //已发出F买开委托
				}
			}
			If(BKDFLGP[X] == 1) //如果已开启P买开处理
			{
				If(BKFLGP[X] == 0) //如果没有P买开委托
				{
					BKMP[X] = N; //P买开委托手数
					BKPP[X] = ASKPP[X]; //P买开委托价格
					Commentary("【多头开仓:P买开委托" + Text(X + 1) + "发出!】");
					BKIDP[X] = CODP[X].A_SendOrder(Enum_Buy,Enum_Entry,BKMP[X],BKPP[X]); //发出P买开委托
					BKFLGP[X] = 1; //已发出P买开委托
				}
			}
			If(SPDFLGF[X] == 1) //如果已开启F卖平处理
			{
				If(SPFLGF[X] == 0) //如果没有F卖平委托
				{
					If(BRPF >= N) //如果F多头可用持仓达到N手
					{
						SPMF[X] = N; //F卖平委托手数
						SPPF[X] = BIDPF; //F卖平委托价格
						Commentary("【多头平仓:F卖平委托" + Text(X + 1) + "发出!】");
						SPIDF[X] = CODF.A_SendOrder(Enum_Sell,Enum_Exit,SPMF[X],SPPF[X]); //发出F卖平委托
						SPFLGF[X] = 1; //已发出F卖平委托
					}
				}
			}
			If(SPDFLGP[X] == 1) //如果已开启P卖平处理
			{
				If(SPFLGP[X] == 0) //如果没有P卖平委托
				{
					If(BRPP[X] >= N) //如果有P多头可用持仓达到N手
					{
						SPMP[X] = N; //P卖平委托手数
						SPPP[X] = BIDPP[X]; //P卖平委托价格
						Commentary("【多头平仓:P卖平委托" + Text(X + 1) + "发出!】");
						SPIDP[X] = CODP[X].A_SendOrder(Enum_Sell,Enum_Exit,SPMP[X],SPPP[X]); //发出P卖平委托
						SPFLGP[X] = 1; //已发出P卖平委托
					}
				}
			}
			If(SKDFLGF[X] == 1) //如果已开启F卖开处理
			{
				If(SKFLGF[X] == 0) //如果没有F卖开委托
				{
					SKMF[X] = N; //F卖开委托手数
					SKPF[X] = BIDPF; //F卖开委托价格
					Commentary("【空头开仓:F卖开委托" + Text(X + 1) + "发出!】");
					SKIDF[X] = CODF.A_SendOrder(Enum_Sell,Enum_Entry,SKMF[X],SKPF[X]); //发出F卖开委托
					SKFLGF[X] = 1; //已发出F卖开委托
				}
			}
			If(BKDFLGC[X] == 1) //如果已开启C买开处理
			{
				If(BKFLGC[X] == 0) //如果没有C买开委托
				{
					BKMC[X] = N; //C买开委托手数
					BKPC[X] = ASKPC[X]; //C买开委托价格
					Commentary("【空头开仓:C买开委托" + Text(X + 1) + "发出!】");
					BKIDC[X] = CODC[X].A_SendOrder(Enum_Buy,Enum_Entry,BKMC[X],BKPC[X]); //发出C买开委托
					BKFLGC[X] = 1; //已发出C买开委托
				}
			}
			If(BPDFLGF[X] == 1) //如果已开启F买平处理
			{
				If(BPFLGF[X] == 0) //如果没有F买平委托
				{
					If(SRPF >= N) //如果F空头可用持仓达到N手
					{
						BPMF[X] = N; //F买平委托手数
						BPPF[X] = ASKPF; //F买平委托价格
						Commentary("【空头平仓:F买平委托" + Text(X + 1) + "发出!】");
						BPIDF[X] = CODF.A_SendOrder(Enum_Buy,Enum_Exit,BPMF[X],BPPF[X]); //发出F买平委托
						BPFLGF[X] = 1; //已发出A买平委托
					}
				}
			}
			If(SPDFLGC[X] == 1) //如果已开启C卖平处理
			{
				If(SPFLGC[X] == 0) //如果没有C卖平委托
				{
					If(BRPC[X] >= N) //如果C多头可用持仓达到N手
					{
						SPMC[X] = N; //C卖平委托手数
						SPPC[X] = BIDPC[X]; //C卖平委托价格
						Commentary("【空头平仓:C卖平委托" + Text(X + 1) + "发出!】");
						SPIDC[X] = CODC[X].A_SendOrder(Enum_Sell,Enum_Exit,SPMC[X],SPPC[X]); //发出C卖平委托
						SPFLGC[X] = 1; //已发出C卖平委托
					}
				}
			}
		}
	}
End
								

案例二:买卖权平价套利

①什么是买卖权平价关系?

买卖权平价关系是指具有相同的到期日与执行价格的金融工具,其卖权与买权价格间必然存在的基本关系。如果两者不相同,则存在套利的空间。

欧式期权的平价关系可以表示为:

其中,C为看涨期权的当期的理论价格,P为看跌期权当期的理论价格,1年期无风险利率为r,行权价为K,为某股票现在的价格。


②根据买卖权平价关系推导套利条件

在上述理论的基础上,Tucker根据股指期货和股指期权之间的价格关系阐述了期货与期权的平价关系,并运用这一均衡关系来发现市场的套利机会并验证市场效率。

该理论假设:1)期权为欧式期权。2)税收、手续费等交易成本不计。3)借贷利率相等。

在t时刻,期货和期权的平价关系可表示为:

F为t时刻期货价格,T为期权到期日,C、P分别是看涨看跌期权的价格,r为无风险利率,贴现因子以年化无风险利率计算,通常考虑一个月内(1/12),其数值接近于1,进而上述关系可简化为:

由上式可以推导出套利开仓条件:


策略
C-P>F-K 看涨期权价格被高估,看跌期权价格被低估 卖出看涨期权,买入看跌期权
C-P<F-K 看涨期权价格被低估,看跌期权价格被高估 买入看涨期权,卖出看跌期权

③将上述策略编写为策略模型

Data
	CODC0:"m2209-C-4200"; //看涨期权
	CODP0:"m2209-P-4200"; //看跌期权
	CODC1:"m2209-C-4150"; //看涨期权
	CODP1:"m2209-P-4150"; //看跌期权
	CODC2:"m2209-C-4100"; //看涨期权
	CODP2:"m2209-P-4100"; //看跌期权
	CODC3:"m2209-C-4050"; //看涨期权
	CODP3:"m2209-P-4050"; //看跌期权
	CODC4:"m2209-C-4000"; //看涨期权
	CODP4:"m2209-P-4000"; //看跌期权
	COD:"m2209"; //标的期货
Vars
	StringArray CODC; //看涨期权
	StringArray CODP; //看跌期权
	String CODF; //标的期货
	Numeric CDN; //期权合约数量
	Numeric N; //下单手数
	Numeric X; //循环变量
	Numeric T; //时间间隔
	Numeric D; //日期间隔
	Numeric TOD; //当前日期
	Numeric NOW; //当前时间
	Numeric NEWPF; //F最新价
	Numeric OPFLG; //模型处理标志
	NumericArray STP; //行权价
	NumericArray NEWPC; //C最新价
	NumericArray NEWPP; //P最新价
	NumericArray EPDC; //C行权日期
	NumericArray EPDP; //P行权日期
	NumericArray RTSC; //C距行权日剩余天数
	NumericArray RTSP; //P距行权日剩余天数
	NumericArray RLPC,FLPC; //C涨跌停价
	NumericArray RLPP,FLPP; //P涨跌停价
	NumericArray BIDPC,ASKPC; //C买卖一价
	NumericArray BIDPP,ASKPP; //P买卖一价
	NumericArray BRPC,SRPC; //C多空头可用持仓
	NumericArray BRPP,SRPP; //P多空头可用持仓
	NumericArray BKDFLGC,SKDFLGC; //C开仓处理标志
	NumericArray BPDFLGC,SPDFLGC; //C开仓处理标志
	NumericArray BKDFLGP,SKDFLGP; //P开仓处理标志
	NumericArray BPDFLGP,SPDFLGP; //P开仓处理标志
	Global_NumericArray KCFLG; //开仓处理标志
	Global_NumericArray KPFLG; //开平处理标志
	Global_NumericArray BKIDC,SKIDC; //C开仓委托
	Global_NumericArray BPIDC,SPIDC; //C平仓委托
	Global_NumericArray BKIDP,SKIDP; //P开仓委托
	Global_NumericArray BPIDP,SPIDP; //P平仓委托
	Global_NumericArray BKFLGC,SKFLGC; //C开仓标志
	Global_NumericArray BPFLGC,SPFLGC; //C平仓标志
	Global_NumericArray BKFLGP,SKFLGP; //P开仓标志
	Global_NumericArray BPFLGP,SPFLGP; //P平仓标志
	Global_NumericArray BKDELC,SKDELC; //C开仓撤单标志
	Global_NumericArray BKDELP,SKDELP; //P开仓撤单标志
	Global_NumericArray BKMC,SKMC; //C开仓委托手数
	Global_NumericArray BPMC,SPMC; //C平仓委托手数
	Global_NumericArray BKMP,SKMP; //P开仓委托手数
	Global_NumericArray BPMP,SPMP; //P平仓委托手数
	Global_NumericArray BKPC,SKPC; //C开仓委托价格
	Global_NumericArray BPPC,SPPC; //C平仓委托价格
	Global_NumericArray BKPP,SKPP; //P开仓委托价格
	Global_NumericArray BPPP,SPPP; //P平仓委托价格
	Global_NumericArray BKTC,SKTC; //C开仓委托时间
	Global_NumericArray BKTP,SKTP; //P开仓委托时间
Begin
	//------------------------处理开启------------------------//
	If(1) //处理开启
	{
		CODC[0] = "m2209-C-4200"; //看涨期权
		CODP[0] = "m2209-P-4200"; //看跌期权
		CODC[1] = "m2209-C-4150"; //看涨期权
		CODP[1] = "m2209-P-4150"; //看跌期权
		CODC[2] = "m2209-C-4100"; //看涨期权
		CODP[2] = "m2209-P-4100"; //看跌期权
		CODC[3] = "m2209-C-4050"; //看涨期权
		CODP[3] = "m2209-P-4050"; //看跌期权
		CODC[4] = "m2209-C-4000"; //看涨期权
		CODP[4] = "m2209-P-4000"; //看跌期权
		CDN = GetStringArraySize(CODC); //期权合约数量
		CODF = "m2209"; //标的期货
		OPFLG = 1; //开启模型处理
		If(CODF.A_IsExchangeOpen() != 1) //如果非开盘状态
		{
			OPFLG = 2; //关闭模型处理
		}
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(CODC[X].A_IsExchangeOpen() != 1 || CODP[X].A_IsExchangeOpen() != 1) //如果非开盘状态
			{
				OPFLG = 2; //关闭模型处理
			}
		}
	}
	//------------------------变量赋值------------------------//
	If(OPFLG == 1) //变量赋值
	{
		N = 1; //下单手数
		T = 15; //时间间隔
		D = 5; //日期间隔
		TOD = CurrentDate(); //当前日期
		NOW = CurrentTime(); //当前时间
		NEWPF = CODF.Price("New"); //F最新价
		For X = 0 To CDN - 1 //遍历期权合约
		{
			NEWPC[X] = CODC[X].Price("New"); //C最新价
			NEWPP[X] = CODP[X].Price("New"); //P最新价
			BIDPC[X] = CODC[X].Price("Bid1"); //C买一价
			ASKPC[X] = CODC[X].Price("Ask1"); //C卖一价
			BIDPP[X] = CODP[X].Price("Bid1"); //P买一价
			ASKPP[X] = CODP[X].Price("Ask1"); //P卖一价
			RLPC[X] = CODC[X].Price("RiseLimit"); //C涨停价
			FLPC[X] = CODC[X].Price("FallLimit"); //C跌停价
			RLPP[X] = CODP[X].Price("RiseLimit"); //P涨停价
			FLPP[X] = CODP[X].Price("FallLimit"); //P跌停价
			BIDPC[X] = IIF(BIDPC[X] == 0 && NEWPC[X] == FLPC[X],FLPC[X],BIDPC[X]); //C买一价
			ASKPC[X] = IIF(ASKPC[X] == 0 && NEWPC[X] == RLPC[X],RLPC[X],ASKPC[X]); //C卖一价
			BIDPP[X] = IIF(BIDPP[X] == 0 && NEWPP[X] == FLPP[X],FLPP[X],BIDPP[X]); //P买一价
			ASKPP[X] = IIF(ASKPP[X] == 0 && NEWPP[X] == RLPP[X],RLPP[X],ASKPP[X]); //P卖一价
			STP[X] = CODC[X].Price("StrikePrice"); //行权价
			EPDC[X] = CODC[X].Price("ExpirationDate"); //C行权日期
			EPDP[X] = CODP[X].Price("ExpirationDate"); //P行权日期
			RTSC[X] = DateDiff(TOD,EPDC[X] ); //C距行权日剩余天数
			RTSP[X] = DateDiff(TOD,EPDP[X] ); //P距行权日剩余天数
			BRPC[X] = CODC[X].F_BuyRemainPosition(); //C多头可用持仓
			SRPC[X] = CODC[X].F_SellRemainPosition(); //C空头可用持仓
			BRPP[X] = CODP[X].F_BuyRemainPosition(); //P多头可用持仓
			SRPP[X] = CODP[X].F_SellRemainPosition(); //P空头可用持仓
			BRPC[X] = Min(BRPC[X],CODC[X].A_BuyRemainPosition()); //C多头可用持仓
			SRPC[X] = Min(SRPC[X],CODC[X].A_SellRemainPosition()); //C空头可用持仓
			BRPP[X] = Min(BRPP[X],CODP[X].A_BuyRemainPosition()); //P多头可用持仓
			SRPP[X] = Min(SRPP[X],CODP[X].A_SellRemainPosition()); //P空头可用持仓
		}
	}
	//------------------------成交判断------------------------//
	If(OPFLG == 1) //成交判断
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(BKFLGC[X] == 1) //如果有C买开委托
			{
				If(F_OrderStatus(BKIDC[X]) == Enum_Filled) //如果C买开委托成交
				{
					Commentary("【多头开仓:C买开委托" + Text(X + 1) + "成交!】");
					BKFLGC[X] = 0; //C买开标志归0
					BKDELC[X] = 0; //C买开撤单标志归0
				}
				Else If(F_OrderStatus(BKIDC[X]) == Enum_Canceled) //如果C买开委托已撤
				{
					Commentary("【多头开仓:C买开委托" + Text(X + 1) + "已撤!】");
					If(F_OrderFilledLot(BKIDC[X]) > 0) //如果C买开委托部分成交
					{
						BKMC[X] = BKMC[X] - F_OrderFilledLot(BKIDC[X]); //C买开委托手数
					}
					If(BKMC[X] > 0) //如果C买开委托手数大于0
					{
						BKPC[X] = RLPC[X]; //C买开委托价格
						Commentary("【多头开仓:C买开委托" + Text(X + 1) + "发出!】");
						BKIDC[X] = CODC[X].A_SendOrder(Enum_Buy,Enum_Entry,BKMC[X],BKPC[X]); //发出C买开委托
					}
					BKDELC[X] = 0; //C买开撤单标志归0
				}
				Else If(F_OrderStatus(BKIDC[X]) == Enum_Declared || F_OrderStatus(BKIDC[X]) == Enum_FillPart) //如果C买开委托挂单
				{
					If(BKDELC[X] == 0) //如果未撤单
					{
						If(TimeDiff(BKTC[X],NOW) >= T && BKPC[X] != RLPC[X]) //如果时间间隔T秒
						{
							Commentary("【多头开仓:C买开委托" + Text(X + 1) + "撤单!】");
							CODC[X].A_DeleteOrder(F_OrderContractNo(BKIDC[X])); //撤掉C买开委托挂单
							BKDELC[X] = 1; //已发出撤掉C买开委托挂单
						}
					}
				}
				Else If(F_OrderStatus(BKIDC[X]) == Enum_Deleted) //如果C买开委托废单
				{
					Commentary("【多头开仓:C买开委托" + Text(X + 1) + "废单!】");
					BKFLGC[X] = 0; //C买开标志归0
				}
			}
			If(SPFLGC[X] == 1) //如果有C卖平委托
			{
				If(F_OrderStatus(SPIDC[X]) == Enum_Filled) //如果C卖平委托成交
				{
					Commentary("【多头平仓:C卖平委托" + Text(X + 1) + "成交!】");
					SPFLGC[X] = 0; //C卖平标志归0
				}
				Else If(F_OrderStatus(SPIDC[X]) == Enum_Deleted) //如果C卖平委托废单
				{
					Commentary("【多头平仓:C卖平委托" + Text(X + 1) + "废单!】");
					SPFLGC[X] = 0; //C卖平标志归0
				}
			}
			If(SKFLGC[X] == 1) //如果有C卖开委托
			{
				If(F_OrderStatus(SKIDC[X]) == Enum_Filled) //如果C卖开委托成交
				{
					Commentary("【空头开仓:C卖开委托" + Text(X + 1) + "成交!】");
					SKFLGC[X] = 0; //C卖开标志归0
					SKDELC[X] = 0; //C卖开撤单标志归0
				}
				Else If(F_OrderStatus(SKIDC[X]) == Enum_Canceled) //如果C卖开委托已撤
				{
					Commentary("【空头开仓:C卖开委托" + Text(X + 1) + "已撤!】");
					If(F_OrderFilledLot(SKIDC[X]) > 0) //如果C卖开委托部分成交
					{
						SKMC[X] = SKMC[X] - F_OrderFilledLot(SKIDC[X]); //C卖开委托手数
					}
					If(SKMC[X] > 0) //如果C卖开委托手数大于0
					{
						SKPC[X] = FLPC[X]; //C卖开委托价格
						Commentary("【空头开仓:C卖开委托" + Text(X + 1) + "发出!】");
						SKIDC[X] = CODC[X].A_SendOrder(Enum_Sell,Enum_Entry,SKMC[X],SKPC[X]); //发出C卖开委托
					}
					SKDELC[X] = 0; //C卖开撤单标志归0
				}
				Else If(F_OrderStatus(SKIDC[X]) == Enum_Declared || F_OrderStatus(SKIDC[X]) == Enum_FillPart) //如果C卖开委托挂单
				{
					If(SKDELC[X] == 0) //如果未撤单
					{
						If(TimeDiff(SKTC[X],NOW) >= T && SKPC[X] != FLPC[X]) //如果时间间隔T秒
						{
							Commentary("【空头开仓:C卖开委托" + Text(X + 1) + "撤单!】");
							CODC[X].A_DeleteOrder(F_OrderContractNo(SKIDC[X])); //撤掉C卖开委托挂单
							SKDELC[X] = 1; //已发出撤掉C卖开委托挂单
						}
					}
				}
				Else If(F_OrderStatus(SKIDC[X]) == Enum_Deleted) //如果C卖开委托废单
				{
					Commentary("【空头开仓:C卖开委托" + Text(X + 1) + "废单!】");
					SKFLGC[X] = 0; //C卖开标志归0
				}
			}
			If(BPFLGC[X] == 1) //如果有C买平委托
			{
				If(F_OrderStatus(BPIDC[X]) == Enum_Filled) //如果C买平委托成交
				{
					Commentary("【空头平仓:C买平委托" + Text(X + 1) + "成交!】");
					BPFLGC[X] = 0; //C买平标志归0
				}
				Else If(F_OrderStatus(BPIDC[X]) == Enum_Deleted) //如果C买平委托废单
				{
					Commentary("【空头平仓:C买平委托" + Text(X + 1) + "废单!】");
					BPFLGC[X] = 0; //C买平标志归0
				}
			}
			If(BKFLGP[X] == 1) //如果有P买开委托
			{
				If(F_OrderStatus(BKIDP[X]) == Enum_Filled) //如果P买开委托成交
				{
					Commentary("【多头开仓:P买开委托" + Text(X + 1) + "成交!】");
					BKFLGP[X] = 0; //P买开标志归0
					BKDELP[X] = 0; //P买开撤单标志归0
				}
				Else If(F_OrderStatus(BKIDP[X]) == Enum_Canceled) //如果P买开委托已撤
				{
					Commentary("【多头开仓:P买开委托" + Text(X + 1) + "已撤!】");
					If(F_OrderFilledLot(BKIDP[X]) > 0) //如果P买开委托部分成交
					{
						BKMP[X] = BKMP[X] - F_OrderFilledLot(BKIDP[X]); //P买开委托手数
					}
					If(BKMP[X] > 0) //如果P买开委托手数大于0
					{
						BKPP[X] = RLPP[X]; //P买开委托价格
						Commentary("【多头开仓:P买开委托" + Text(X + 1) + "发出!】");
						BKIDP[X] = CODP[X].A_SendOrder(Enum_Buy,Enum_Entry,BKMP[X],BKPP[X]); //发出P买开委托
					}
					BKDELP[X] = 0; //P买开撤单标志归0
				}
				Else If(F_OrderStatus(BKIDP[X]) == Enum_Declared || F_OrderStatus(BKIDP[X]) == Enum_FillPart) //如果P买开委托挂单
				{
					If(BKDELP[X] == 0) //如果未撤单
					{
						If(TimeDiff(BKTP[X],NOW) >= T && BKPP[X] != RLPP[X]) //如果时间间隔T秒
						{
							Commentary("【多头开仓:P买开委托" + Text(X + 1) + "撤单!】");
							CODP[X].A_DeleteOrder(F_OrderContractNo(BKIDP[X])); //撤掉P买开委托挂单
							BKDELP[X] = 1; //已发出撤掉P买开委托挂单
						}
					}
				}
				Else If(F_OrderStatus(BKIDP[X]) == Enum_Deleted) //如果P买开委托废单
				{
					Commentary("【多头开仓:P买开委托" + Text(X + 1) + "废单!】");
					BKFLGP[X] = 0; //P买开标志归0
				}
			}
			If(SPFLGP[X] == 1) //如果有P卖平委托
			{
				If(F_OrderStatus(SPIDP[X]) == Enum_Filled) //如果P卖平委托成交
				{
					Commentary("【多头平仓:P卖平委托" + Text(X + 1) + "成交!】");
					SPFLGP[X] = 0; //P卖平标志归0
				}
				Else If(F_OrderStatus(SPIDP[X]) == Enum_Deleted) //如果P卖平委托废单
				{
					Commentary("【多头平仓:P卖平委托" + Text(X + 1) + "废单!】");
					SPFLGP[X] = 0; //P卖平标志归0
				}
			}
			If(SKFLGP[X] == 1) //如果有P卖开委托
			{
				If(F_OrderStatus(SKIDP[X]) == Enum_Filled) //如果P卖开委托成交
				{
					Commentary("【空头开仓:P卖开委托" + Text(X + 1) + "成交!】");
					SKFLGP[X] = 0; //P卖开标志归0
					SKDELP[X] = 0; //P卖开撤单标志归0
				}
				Else If(F_OrderStatus(SKIDP[X]) == Enum_Canceled) //如果P卖开委托已撤
				{
					Commentary("【空头开仓:P卖开委托" + Text(X + 1) + "已撤!】");
					If(F_OrderFilledLot(SKIDP[X]) > 0) //如果P卖开委托部分成交
					{
						SKMP[X] = SKMP[X] - F_OrderFilledLot(SKIDP[X]); //P卖开委托手数
					}
					If(SKMP[X] > 0) //如果P卖开委托手数大于0
					{
						SKPP[X] = FLPP[X]; //P卖开委托价格
						Commentary("【空头开仓:P卖开委托" + Text(X + 1) + "发出!】");
						SKIDP[X] = CODP[X].A_SendOrder(Enum_Sell,Enum_Entry,SKMP[X],SKPP[X]); //发出P卖开委托
					}
					SKDELP[X] = 0; //P卖开撤单标志归0
				}
				Else If(F_OrderStatus(SKIDP[X]) == Enum_Declared || F_OrderStatus(SKIDP[X]) == Enum_FillPart) //如果P卖开委托挂单
				{
					If(SKDELP[X] == 0) //如果未撤单
					{
						If(TimeDiff(SKTP[X],NOW) >= T && SKPP[X] != FLPP[X]) //如果时间间隔T秒
						{
							Commentary("【空头开仓:P卖开委托" + Text(X + 1) + "撤单!】");
							CODP[X].A_DeleteOrder(F_OrderContractNo(SKIDP[X])); //撤掉P卖开委托挂单
							SKDELP[X] = 1; //已发出撤掉P卖开委托挂单
						}
					}
				}
				Else If(F_OrderStatus(SKIDP[X]) == Enum_Deleted) //如果P卖开委托废单
				{
					Commentary("【空头开仓:P卖开委托" + Text(X + 1) + "废单!】");
					SKFLGP[X] = 0; //P卖开标志归0
				}
			}
			If(BPFLGP[X] == 1) //如果有P买平委托
			{
				If(F_OrderStatus(BPIDP[X]) == Enum_Filled) //如果P买平委托成交
				{
					Commentary("【空头平仓:P买平委托" + Text(X + 1) + "成交!】");
					BPFLGP[X] = 0; //P买平标志归0
				}
				Else If(F_OrderStatus(BPIDP[X]) == Enum_Deleted) //如果P买平委托废单
				{
					Commentary("【空头平仓:P买平委托" + Text(X + 1) + "废单!】");
					BPFLGP[X] = 0; //P买平标志归0
				}
			}
		}
	}
	//------------------------开平处理------------------------//
	If(OPFLG == 1) //开平处理
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(BKFLGC[X] == 0 && SPFLGC[X] == 0 && SKFLGC[X] == 0 && BPFLGC[X] == 0 &&
				BKFLGP[X] == 0 && SPFLGP[X] == 0 && SKFLGP[X] == 0 && BPFLGP[X] == 0) //如果没有开平仓委托
			{
				If(RTSC[X] > D && RTSC[X] > D) //如果满足开平仓条件
				{
					If(KCFLG[X] == 0) //如果未执行平仓处理
					{
						If(KPFLG[X] == 0 || KPFLG[X] == 2) //如果未执行开平处理1
						{
							If(NEWPC[X] - NEWPP[X] > NEWPF - STP[X]) //如果满足平仓条件
							{
								SPDFLGC[X] = 1; //开启C卖平处理
								BPDFLGP[X] = 1; //开启P买平处理
								KPFLG[X] = 1; //已执行开平处理1
								KCFLG[X] = 1; //已执行平仓处理
							}
						}
						If(KPFLG[X] == 0 || KPFLG[X] == 1) //如果未执行开平处理2
						{
							If(NEWPC[X] - NEWPP[X] < NEWPF - STP[X]) //如果满足平仓条件
							{
								BPDFLGC[X] = 1; //开启C买平处理
								SPDFLGP[X] = 1; //开启P卖平处理
								KPFLG[X] = 2; //已执行开平处理2
								KCFLG[X] = 1; //已执行平仓处理
							}
						}
					}
					Else If(KCFLG[X] == 1) //如果已执行平仓处理
					{
						If(KPFLG[X] == 1) //如果已执行开平处理1
						{
							SKDFLGC[X] = 1; //开启C卖开处理
							BKDFLGP[X] = 1; //开启P买开处理
						}
						Else If(KPFLG[X] == 2) //如果已执行开平处理2
						{
							BKDFLGC[X] = 1; //开启C买开处理
							SKDFLGP[X] = 1; //开启P卖开处理
						}
						KCFLG[X] = 0; //开仓处理标志归0
					}
				}
				Else If(RTSC[X] <= D || RTSP[X] <= D) //如果满足清仓条件
				{
					If(KPFLG[X] == 1) //如果已执行开平处理1
					{
						BPDFLGC[X] = 1; //开启C买平处理
						SPDFLGP[X] = 1; //开启P卖平处理
						KCFLG[X] = 0; //开仓处理标志归0
						KPFLG[X] = 0; //开平处理标志归0
					}
					Else If(KPFLG[X] == 2) //如果已执行开平处理2
					{
						SPDFLGC[X] = 1; //开启C卖平处理
						BPDFLGP[X] = 1; //开启P买平处理
						KCFLG[X] = 0; //开仓处理标志归0
						KPFLG[X] = 0; //开平处理标志归0
					}
				}
			}
		}
	}
	//------------------------委托处理------------------------//
	If(OPFLG == 1) //委托处理
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(BKDFLGC[X] == 1) //如果已开启C买开处理
			{
				If(BKFLGC[X] == 0) //如果没有C买开委托
				{
					BKMC[X] = N; //C买开委托手数
					BKPC[X] = ASKPC[X]; //C买开委托价格
					Commentary("【多头开仓:C买开委托" + Text(X + 1) + "发出!】");
					BKIDC[X] = CODC[X].A_SendOrder(Enum_Buy,Enum_Entry,BKMC[X],BKPC[X]); //发出C买开委托
					BKTC[X] = NOW; //C买开委托时间
					BKFLGC[X] = 1; //已发出C买开委托
				}
			}
			If(SPDFLGC[X] == 1) //如果已开启C卖平处理
			{
				If(SPFLGC[X] == 0) //如果没有C卖平委托
				{
					If(BRPC[X] >= N) //如果C多头可用持仓达到N手
					{
						SPMC[X] = N; //C卖平委托手数
						SPPC[X] = BIDPC[X]; //C卖平委托价格
						Commentary("【多头平仓:C卖平委托" + Text(X + 1) + "发出!】");
						SPIDC[X] = CODC[X].A_SendOrder(Enum_Sell,Enum_Exit,SPMC[X],SPPC[X]); //发出C卖平委托
						SPFLGC[X] = 1; //已发出C卖平委托
					}
				}
			}
			If(SKDFLGC[X] == 1) //如果已开启C卖开处理
			{
				If(SKFLGC[X] == 0) //如果没有C卖开委托
				{
					SKMC[X] = N; //C卖开委托手数
					SKPC[X] = BIDPC[X]; //C卖开委托价格
					Commentary("【空头开仓:C卖开委托" + Text(X + 1) + "发出!】");
					SKIDC[X] = CODC[X].A_SendOrder(Enum_Sell,Enum_Entry,SKMC[X],SKPC[X]); //发出C卖开委托
					SKTC[X] = NOW; //C卖开委托时间
					SKFLGC[X] = 1; //已发出C卖开委托
				}
			}
			If(BPDFLGC[X] == 1) //如果已开启C买平处理
			{
				If(BPFLGC[X] == 0) //如果没有C买平委托
				{
					If(SRPC[X] >= N) //如果C空头可用持仓达到N手
					{
						BPMC[X] = N; //C买平委托手数
						BPPC[X] = ASKPC[X]; //C买平委托价格
						Commentary("【空头平仓:C买平委托" + Text(X + 1) + "发出!】");
						BPIDC[X] = CODC[X].A_SendOrder(Enum_Buy,Enum_Exit,BPMC[X],BPPC[X]); //发出C买平委托
						BPFLGC[X] = 1; //已发出C买平委托
					}
				}
			}
			If(BKDFLGP[X] == 1) //如果已开启P买开处理
			{
				If(BKFLGP[X] == 0) //如果没有P买开委托
				{
					BKMP[X] = N; //P买开委托手数
					BKPP[X] = ASKPP[X]; //P买开委托价格
					Commentary("【多头开仓:P买开委托" + Text(X + 1) + "发出!】");
					BKIDP[X] = CODP[X].A_SendOrder(Enum_Buy,Enum_Entry,BKMP[X],BKPP[X]); //发出P买开委托
					BKTP[X] = NOW; //P买开委托时间
					BKFLGP[X] = 1; //已发出P买开委托
				}
			}
			If(SPDFLGP[X] == 1) //如果已开启P卖平处理
			{
				If(SPFLGP[X] == 0) //如果没有P卖平委托
				{
					If(BRPP[X] >= N) //如果P多头可用持仓达到N手
					{
						SPMP[X] = N; //P卖平委托手数
						SPPP[X] = BIDPP[X]; //P卖平委托价格
						Commentary("【多头平仓:P卖平委托" + Text(X + 1) + "发出!】");
						SPIDP[X] = CODP[X].A_SendOrder(Enum_Sell,Enum_Exit,SPMP[X],SPPP[X]); //发出P卖平委托
						SPFLGP[X] = 1; //已发出P卖平委托
					}
				}
			}
			If(SKDFLGP[X] == 1) //如果已开启P卖开处理
			{
				If(SKFLGP[X] == 0) //如果没有P卖开委托
				{
					SKMP[X] = N; //P卖开委托手数
					SKPP[X] = BIDPP[X]; //P卖开委托价格
					Commentary("【空头开仓:P卖开委托" + Text(X + 1) + "发出!】");
					SKIDP[X] = CODP[X].A_SendOrder(Enum_Sell,Enum_Entry,SKMP[X],SKPP[X]); //发出P卖开委托
					SKTP[X] = NOW; //P卖开委托时间
					SKFLGP[X] = 1; //已发出P卖开委托
				}
			}
			If(BPDFLGP[X] == 1) //如果已开启P买平处理
			{
				If(BPFLGP[X] == 0) //如果没有P买平委托
				{
					If(SRPP[X] >= N) //如果P空头可用持仓达到N手
					{
						BPMP[X] = N; //P买平委托手数
						BPPP[X] = ASKPP[X]; //P买平委托价格
						Commentary("【空头平仓:P买平委托" + Text(X + 1) + "发出!】");
						BPIDP[X] = CODP[X].A_SendOrder(Enum_Buy,Enum_Exit,BPMP[X],BPPP[X]); //发出P买平委托
						BPFLGP[X] = 1; //已发出P买平委托
					}
				}
			}
		}
	}
End
											

案例三:日历价差套利

①日历价差套利策略简介

日历价差是指买进到期日较远的期权,同时又卖出相同行权价格、相同数量但到期日较近的期权,赚取两个不同期权隐含波动率的差价或者其它期权定价参数的差价,以获得利润的期权套利交易策略。


②推导套利条件

1)、开仓策略:

X=V(近月隐含波动率)-V (历史波动率)+V (近月隐含波动率 )-V(远月隐含波动率) X>0,通过卖出一份近月看涨期权,同时买出一份远月看涨期权,建立日历价差组合。

2)、平仓策略:

考虑到该组合并没有对冲标的物价格变动的风险,在近月期权到期前几天,组合的Gamma风险值可能比较大,标的物价格的变化会大幅增加收益的波动率。因此,策略采取在当月合约到期前8天进行平仓。


③将上述策略编写为策略模型

Data
	CODA0:"c2209-C-3160"; //近月合约
	CODB0:"c2211-C-3160"; //远月合约
	CODA1:"c2209-C-3120"; //近月合约
	CODB1:"c2211-C-3120"; //远月合约
	CODA2:"c2209-C-3080"; //近月合约
	CODB2:"c2211-C-3080"; //远月合约
	CODA3:"c2209-C-3040"; //近月合约
	CODB3:"c2211-C-3040"; //远月合约
	CODA4:"c2209-C-3000"; //近月合约
	CODB4:"c2211-C-3000"; //远月合约
	COD:"c2209"; //标的期货
Vars
	StringArray CODA; //看涨期权
	StringArray CODB; //看跌期权
	String CODF; //标的期货
	Numeric CDN; //期权合约数量
	Numeric N; //下单手数
	Numeric Length; //周期
	Numeric X; //循环变量
	Numeric D; //日期间隔
	Numeric TKN; //数据区长度
	Numeric TOD; //当前日期
	Numeric HVLF; //F价格波动率
	Numeric OPFLG; //模型处理标志
	Var_TickData TKD; //数据区
	NumericArray LNP; //自然对数
	NumericArray EPDA; //行权日期
	NumericArray RTS; //距行权日剩余天数
	NumericArray STRA; //近月合约隐含波动率
	NumericArray STRB; //远月合约隐含波动率
	NumericArray PRC; //隐含波动率综合价差
	NumericArray NEWPA; //A最新价
	NumericArray NEWPB; //B最新价
	NumericArray RLPA,FLPA; //A涨跌停价
	NumericArray RLPB,FLPB; //B涨跌停价
	NumericArray BIDPA,ASKPA; //A买卖一价
	NumericArray BIDPB,ASKPB; //B买卖一价
	NumericArray BRPA,SRPA; //A多空头可用持仓
	NumericArray BRPB,SRPB; //B多空头可用持仓
	NumericArray BKDFLG; //买开处理标志
	NumericArray SKDFLG; //卖开处理标志
	NumericArray BPDFLG; //买平处理标志
	NumericArray SPDFLG; //卖平处理标志
	Global_NumericArray BCFLG; //多头处理标志
	Global_NumericArray SCFLG; //空头处理标志
	Global_NumericArray BKIDA,SKIDA; //A开仓委托
	Global_NumericArray BKIDB,SKIDB; //B开仓委托
	Global_NumericArray BPIDA,SPIDA; //A平仓委托
	Global_NumericArray BPIDB,SPIDB; //B平仓委托
	Global_NumericArray BKFLGA,SKFLGA; //A开仓标志
	Global_NumericArray BKFLGB,SKFLGB; //B开仓标志
	Global_NumericArray BPFLGA,SPFLGA; //A平仓标志
	Global_NumericArray BPFLGB,SPFLGB; //B平仓标志
	Global_NumericArray BKMA,SKMA; //A开仓委托手数
	Global_NumericArray BKMB,SKMB; //B开仓委托手数
	Global_NumericArray BPMA,SPMA; //A平仓委托手数
	Global_NumericArray BPMB,SPMB; //B平仓委托手数
	Global_NumericArray BKPA,SKPA; //A开仓委托价格
	Global_NumericArray BKPB,SKPB; //B开仓委托价格
	Global_NumericArray BPPA,SPPA; //A平仓委托价格
	Global_NumericArray BPPB,SPPB; //B平仓委托价格
Begin
	//------------------------处理开启------------------------//
	If(1) //处理开启
	{
		CODA[0] = "c2209-C-3160"; //近月合约
		CODB[0] = "c2211-C-3160"; //远月合约 
		CODA[1] = "c2209-C-3120"; //近月合约
		CODB[1] = "c2211-C-3120"; //远月合约 
		CODA[2] = "c2209-C-3080"; //近月合约
		CODB[2] = "c2211-C-3080"; //远月合约 
		CODA[3] = "c2209-C-3040"; //近月合约
		CODB[3] = "c2211-C-3040"; //远月合约 
		CODA[4] = "c2209-C-3000"; //近月合约
		CODB[4] = "c2211-C-3000"; //远月合约 
		CDN = GetStringArraySize(CODA); //期权合约数量
		CODF = "c2209"; //标的期货
		OPFLG = 1; //开启模型处理
		If(CODF.A_IsExchangeOpen() != 1) //如果非开盘状态
		{
			OPFLG = 2; //关闭模型处理
		}
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(CODA[X].A_IsExchangeOpen() != 1 || CODB[X].A_IsExchangeOpen() != 1) //如果非开盘状态
			{
				OPFLG = 2; //关闭模型处理
			}
		}
	}
	//------------------------变量赋值------------------------//
	If(OPFLG == 1) //变量赋值
	{
		N = 10; //下单手数
		Length = 5; //周期
		D = 5; //日期间隔
		TOD = CurrentDate(); //当前日期
		For X = 0 To CDN - 1 //遍历期权合约
		{
			NEWPA[X] = CODA[X].Price("New"); //A最新价
			NEWPB[X] = CODB[X].Price("New"); //B最新价
			BIDPA[X] = CODA[X].Price("Bid1"); //A买一价
			ASKPA[X] = CODA[X].Price("Ask1"); //A卖一价
			BIDPB[X] = CODB[X].Price("Bid1"); //B买一价
			ASKPB[X] = CODB[X].Price("Ask1"); //B卖一价
			RLPA[X] = CODA[X].Price("RiseLimit"); //A涨停价
			FLPA[X] = CODA[X].Price("FallLimit"); //A跌停价
			RLPB[X] = CODB[X].Price("RiseLimit"); //B涨停价
			FLPB[X] = CODB[X].Price("FallLimit"); //B跌停价
			BIDPA[X] = IIF(BIDPA[X] == 0 && NEWPA[X] == FLPA[X],FLPA[X],BIDPA[X]); //A买一价
			ASKPA[X] = IIF(ASKPA[X] == 0 && NEWPA[X] == RLPA[X],RLPA[X],ASKPA[X]); //A卖一价
			BIDPB[X] = IIF(BIDPB[X] == 0 && NEWPB[X] == FLPB[X],FLPB[X],BIDPB[X]); //B买一价
			ASKPB[X] = IIF(ASKPB[X] == 0 && NEWPB[X] == RLPB[X],RLPB[X],ASKPB[X]); //B卖一价
			STRA[X] = CODA[X].Price("Stdderiation"); //A隐含波动率
			STRB[X] = CODB[X].Price("Stdderiation"); //B隐含波动率
			EPDA[X] = CODA[X].Price("ExpirationDate"); //A行权日期
			RTS[X] = DateDiff(TOD,EPDA[X] ); //距行权日剩余天数
			BRPA[X] = CODA[X].F_BuyRemainPosition(); //A多头可用持仓
			SRPA[X] = CODA[X].F_SellRemainPosition(); //A空头可用持仓
			BRPB[X] = CODB[X].F_BuyRemainPosition(); //B多头可用持仓
			SRPB[X] = CODB[X].F_SellRemainPosition(); //B空头可用持仓
			BRPA[X] = Min(BRPA[X],CODA[X].A_BuyRemainPosition()); //A多头可用持仓
			SRPA[X] = Min(SRPA[X],CODA[X].A_SellRemainPosition()); //A空头可用持仓
			BRPB[X] = Min(BRPB[X],CODB[X].A_BuyRemainPosition()); //B多头可用持仓
			SRPB[X] = Min(SRPB[X],CODB[X].A_SellRemainPosition()); //B空头可用持仓
		}
	}
	//------------------------数据取值------------------------//
	If(OPFLG == 1) //数据取值
	{
		TKD = Def_TickData(CODF,1,6); //数据区
		If(TKD.State == 1) //如果数据区有效
		{
			TKN = TKD.Num; //数据区长度
			For X = 1 To TKN - 1 //遍历数据区
			{
				LNP[X - 1] = Ln(TKD[X].TickPrice / TKD[X - 1].TickPrice); //自然对数
			}
			HVLF = StandardDevArray(LNP,2) * Sqrt(252) ; //F价格波动率
			For X = 0 To CDN - 1 //遍历期权合约
			{
				PRC[X] = STRA[X] - HVLF + STRA[X] - STRB[X]; //隐含波动率综合价差
			}
		}
		Else //如果数据区无效
		{
			OPFLG = 2; //关闭模型处理
		}
	}
	//------------------------成交判断------------------------//
	If(OPFLG == 1) //成交判断
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(SKFLGA[X] == 1) //如果有A卖开委托
			{
				If(F_OrderStatus(SKIDA[X]) == Enum_Filled) //如果A卖开委托成交
				{
					Commentary("【空头开仓:A卖开委托" + Text(X + 1) + "成交!】");
					SKFLGA[X] = 0; //A卖开标志归0
				}
				Else If(F_OrderStatus(SKIDA[X]) == Enum_Deleted) //如果A卖开委托废单
				{
					Commentary("【空头开仓:A卖开委托" + Text(X + 1) + "废单!】");
					SKFLGA[X] = 0; //A卖开标志归0
				}
			}
			If(BKFLGB[X] == 1) //如果有B买开委托
			{
				If(F_OrderStatus(BKIDB[X]) == Enum_Filled) //如果B买开委托成交
				{
					Commentary("【空头开仓:B买开委托" + Text(X + 1) + "成交!】");
					BKFLGB[X] = 0; //B买开标志归0
				}
				Else If(F_OrderStatus(BKIDB[X]) == Enum_Deleted) //如果B买开委托废单
				{
					Commentary("【空头开仓:B买开委托" + Text(X + 1) + "废单!】");
					BKFLGB[X] = 0; //B买开标志归0
				}
			}
			If(BPFLGA[X] == 1) //如果有A买平委托
			{
				If(F_OrderStatus(BPIDA[X]) == Enum_Filled) //如果A买平委托成交
				{
					Commentary("【空头平仓:A买平委托" + Text(X + 1) + "成交!】");
					BPFLGA[X] = 0; //A买平标志归0
				}
				Else If(F_OrderStatus(BPIDA[X]) == Enum_Deleted) //如果A买平委托废单
				{
					Commentary("【空头平仓:A买平委托" + Text(X + 1) + "废单!】");
					BPFLGA[X] = 0; //A买平标志归0
				}
			}
			If(SPFLGB[X] == 1) //如果有B卖平委托
			{
				If(F_OrderStatus(SPIDB[X]) == Enum_Filled) //如果B卖平委托成交
				{
					Commentary("【空头平仓:B卖平委托" + Text(X + 1) + "成交!】");
					SPFLGB[X] = 0; //B卖平标志归0
				}
				Else If(F_OrderStatus(SPIDB[X]) == Enum_Deleted) //如果B卖平委托废单
				{
					Commentary("【空头平仓:B卖平委托" + Text(X + 1) + "废单!】");
					SPFLGB[X] = 0; //B卖平标志归0
				}
			}
		}
	}
	//------------------------空头处理------------------------//
	If(OPFLG == 1) //空头处理
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(SKFLGA[X] == 0 && BKFLGB[X] == 0 && BPFLGA[X] == 0 && SPFLGB[X] == 0) //如果没有开平仓委托
			{
				If(SCFLG[X] == 0) //如果未执行空头开仓
				{
					If(PRC[X] > 0 && RTS[X] > D) //如果满足空头开仓条件
					{
						SKDFLG[X] = 1; //开启卖开处理
						SCFLG[X] = 1; //已执行空头开仓
					}
				}
				Else If(SCFLG[X] == 1) //如果已执行空头开仓
				{
					If(RTS[X] <= D) //如果满足空头平仓条件
					{
						BPDFLG[X] = 1; //开启买平处理
						SCFLG[X] = 0; //空头处理标志归0
					}
				}
			}
		}
	}
	//------------------------委托处理------------------------//
	If(OPFLG == 1) //委托处理
	{
		For X = 0 To CDN - 1 //遍历期权合约
		{
			If(SKDFLG[X] == 1) //如果已开启卖开处理
			{
				If(SKFLGA[X] == 0 && BKFLGB[X] == 0) //如果没有开仓委托
				{
					SKMA[X] = N; //A卖开委托手数
					SKPA[X] = BIDPA[X]; //A卖开委托价格
					Commentary("【空头开仓:A卖开委托" + Text(X + 1) + "发出!】");
					SKIDA[X] = CODA[X].A_SendOrder(Enum_Sell,Enum_Entry,SKMA[X],SKPA[X]); //发出A卖开委托
					SKFLGA[X] = 1; //已发出A卖开委托
					BKMB[X] = N; //B买开委托手数
					BKPB[X] = ASKPB[X]; //B买开委托价格
					Commentary("【空头开仓:B买开委托" + Text(X + 1) + "发出!】");
					BKIDB[X] = CODB[X].A_SendOrder(Enum_Buy,Enum_Entry,BKMB[X],BKPB[X]); //发出B买开委托
					BKFLGB[X] = 1; //已发出B买开委托
				}
			}
			If(BPDFLG[X] == 1) //如果已开启买平处理
			{
				If(BPFLGA[X] == 0 && SPFLGB[X] == 0) //如果没有平仓委托
				{
					If(SRPA[X] >= N) //如果A空头可用持仓达到N手
					{
						BPMA[X] = N; //A买平委托手数
						BPPA[X] = ASKPA[X]; //A买平委托价格
						Commentary("【空头平仓:A买平委托" + Text(X + 1) + "发出!】");
						BPIDA[X] = CODA[X].A_SendOrder(Enum_Buy,Enum_Exit,BPMA[X],BPPA[X]); //发出A买平委托
						BPFLGA[X] = 1; //已发出A买平委托
					}
					If(BRPB[X] >= N) //如果B多头可用持仓达到N手
					{
						SPMB[X] = N; //B卖平委托手数
						SPPB[X] = BIDPB[X]; //B卖平委托价格
						Commentary("【空头平仓:B卖平委托" + Text(X + 1) + "发出!】");
						SPIDB[X] = CODB[X].A_SendOrder(Enum_Sell,Enum_Exit,SPMB[X],SPPB[X]); //发出B卖平委托
						SPFLGB[X] = 1; //已发出B卖平委托
					}
				}
			}
		}
	}
End
											 

前言

  机构量化交易资金管理规模大,单笔委托手数太大,直接下单会产生较大冲击成本。这时需要算法交易来帮忙!

wh9支持趋势模型中写入智能拆单算法代码,使用算法交易策略控制交易过程,根据盘口情况智能拆单,不仅能够提高交易效率,降低冲击成本,还能隐匿机构交易行为,防止下单对趋势产生影响。

优势

  • 算法交易精细控制交易过程,提高交易效率,降低冲击成本。
  • 智能分批,隐匿交易行为,防止破坏趋势。
  • 比肩C++程序的运行速度。

案例

案例一:策略模型+智能分批算法

随着量化交易资金规模逐渐增大,单笔委托手数太大,直接下单会产生较大冲击成本。

对量化交易策略附加智能分批算法,使用算法交易策略控制交易过程,可在下单时由系统自动拆分成合适的小单进行分批委托,起到降低冲击成本的作用。


例如:

当出现买入信号时,我们可以使用对手盘的挂单量计算每批手数,每次委托手数为对手盘挂单量的20%,委托发出3秒后撤掉未成交挂单,并按照新的价格重新委托,直到全部成交。同时设定10个最小变动价位的成交范围,超出范围自动撤单并停止后续交易。


源码如下:
Data
   COD:"cu2005"; //合约编码
Vars
   Numeric N; //下单手数
   Numeric KN; //单笔限制手数
   Numeric M; //价位倍数
   Numeric T; //时间间隔
   Numeric P; //数值比例
   Numeric NOW; //当前时间
   Numeric NEWP; //最新价
   Numeric ASKP; //卖一价
   Numeric ASKV; //卖一量
   Numeric MINP; //最小变动价位
   Numeric OPFLG; //模型处理标志
   Global_Numeric BCFLG; //多头处理标志
   Global_Numeric BKDFLG; //买开处理标志
   Global_Numeric BKID; //买开委托
   Global_Numeric BKFLG; //买开标志
   Global_Numeric BKDEL; //买开撤单标志
   Global_Numeric BKSM; //买开委托总手数
   Global_Numeric BKNP; //买开最新价
   Global_Numeric BKM; //买开委托手数
   Global_Numeric BKP; //买开委托价格
   Global_Numeric BKT; //买开委托时间
Begin
//------------------------处理开启------------------------//
If(A_IsExchangeOpen() == 1) //如果是开盘状态
{
   OPFLG = 1; //开启模型处理
}
//------------------------变量赋值------------------------//
If(OPFLG == 1) //变量赋值
{
   N = 5000; //下单手数
   KN = 20; //单笔限制手数
   M = 10; //价位倍数
   T = 3; //时间间隔
   P = 0.2; //数值比例
   NOW = CurrentTime(); //当前时间
   NEWP = Price("New"); //最新价
   ASKP = Price("Ask1"); //卖一价
   ASKV = Price("AskVol1"); //卖一量
   MINP = Price("MinPrice"); //最小变动价位
}
//------------------------成交判断------------------------//
If(OPFLG == 1) //成交判断
{
   If(BKFLG == 1) //如果有买开委托
   {
      If(F_OrderStatus(BKID) == Enum_Filled) //如果买开委托成交
      {
         Commentary("【多头开仓:买开委托成交!】");
         If(BKSM == 0) //如果没有剩余买开手数
         {
            Commentary("【多头开仓:买开委托完成!】");
            BCFLG = 3; //已完成多头开仓
         }
         BKFLG = 0; //买开标志归0
         BKDEL = 0; //买开撤单标志归0
      }
      Else If(F_OrderStatus(BKID) == Enum_Canceled) //如果买开委托已撤
      {
         Commentary("【多头开仓:买开委托已撤!】");
         If(BKDEL == 1) //如果是追价撤单
         {
            If(F_OrderFilledLot(BKID) > 0) //如果买开委托部分成交
            {
               BKM = BKM - F_OrderFilledLot(BKID); //买开委托手数
            }
            If(BKM > 0) //如果买开委托手数大于0
            {
               BKP = ASKP; //买开委托价格
               Commentary("【多头开仓:买开委托追价!】");
               BKID = A_SendOrder(Enum_Buy,Enum_Entry,BKM,BKP); //发出买开委托
               BKT = NOW; //买开委托时间
            }
            }
            Else If(BKDEL == 2 || BKDEL == 3 || BKDEL == 4) //如果是多头开仓撤单
            {
               BKFLG = 0; //买开标志归0
            }
            BKDEL = 0; //买开撤单标志归0
      }
      Else If(F_OrderStatus(BKID) == Enum_Declared || F_OrderStatus(BKID) == Enum_FillPart) //如果买开委托挂单
      {
            If(BKDEL == 0) //如果未撤单
            {
            If(TimeDiff(BKT,NOW) >= T) //如果时间间隔T秒
            {
               Commentary("【多头开仓:买开委托撤单!】");
               F_DeleteOrder(F_OrderContractNo(BKID)); //撤掉买开委托挂单
               BKDEL = 1; //已发出撤掉买开委托挂单
               }
            }
            Else If(BKDEL == 3) //如果是多头开仓撤单
            {
            Commentary("【多头开仓:买开委托撤单!】");
            F_DeleteOrder(F_OrderContractNo(BKID)); //撤掉买开委托挂单
            BKDEL = 4; //多头开仓撤掉买开委托挂单
         }
      }
   }
}
//------------------------多头处理-----------------------//
If(OPFLG == 1) //多头处理
{
   If(BCFLG == 0) //如果未执行多头开仓
   {
      BKSM = N; //买开总手数
      BKNP = NEWP; //买开最新价
      BKDFLG = 1; //开启买开处理
      BCFLG = 1; //已发出多头开仓
   }
   Else If(BCFLG == 1) //如果已发出多头开仓
   {
      If(Abs(NEWP - BKNP) > M * MINP) //如果滑点超过M个价位
      {
         Commentary("【多头开仓:滑点超过" + Text(M) + "点!】");
         If(BKFLG == 1) //如果有买开委托
         {
            If(BKDEL == 0) //如果未撤单
            {
               If(F_OrderStatus(BKID) == Enum_Declared || F_OrderStatus(BKID) == Enum_FillPart) //如果买开委托挂单
               {
               Commentary("【多头开仓:买开委托撤单!】");
               F_DeleteOrder(F_OrderContractNo(BKID)); //撤掉买开委托挂单
               BKDEL = 2; //多头开仓撤掉买开委托挂单
               }
               Else //如果买开委托未挂单
               {
                  BKDEL = 3; //多头开仓撤掉买开委托挂单
               }
            }
            Else //如果已发出撤单
            {
               BKDEL = 3; //多头开仓撤掉买开委托挂单
            }
         }
         BKDFLG = 0; //买开处理标志归0
            BCFLG = 2; //已发出多头撤单
      }
   }
   If(BCFLG == 2) //如果已发出多头撤单

   {
      If(BKFLG == 0) //如果没有买开委托
      {
         Commentary("【多头开仓:买开委托取消!】");
         BCFLG = 3; //已完成多头开仓
      }
   }
}
//------------------------委托处理------------------------//
If(OPFLG == 1) //委托处理
{
   If(BKDFLG == 1) //如果已开启买开处理
   {
      If(BKFLG == 0) //如果没有买开委托
      {
         BKM = Min1(Floor(P * ASKV),KN,BKSM); //买开委托手数
         If(BKM > 0) //如果买开委托手数大于0
         {
            BKP = ASKP; //买开委托价格
            Commentary("【多头开仓:买开委托发出!】");
            BKID = A_SendOrder(Enum_Buy,Enum_Entry,BKM,BKP); //发出买开委托
            BKSM = BKSM - BKM; //买开总手数
            BKT = NOW; //买开委托时间
            BKFLG = 1; //已发出买开委托
         }
         If(BKSM == 0) //如果没有剩余买开手数
         {
            BKDFLG = 0; //买开处理标志归0
         }
      }
   }
}
End

前言

  随着资金规模的增大,传统的手动委托方式,委托速度慢、误操作多、成交滑点大、止损不及时的劣势会越来越明显。

  算法交易通过对期货账号交易信息的获取,实现了替代手动控制交易过程的功能。通过对持仓信息、挂单信息,成交回报,委托回报等信息的监控,实现了对交易过程的精细化控制,再配合算法交易委托速度快,对市场变化反应迅速等特点,可进一步减少成交滑点,降低交易风险。

  算法交易也支持同时对多个交易账号进行委托控制,解决了手动交易无法同时管理多个账号批量委托的问题。

优势

  • 人机结合,提高成交效率,降低成交滑点。
  • 可实现智能分批,追价,自动锁仓等复杂策略。
  • 支持多账号下单,自动管理多个账号批量委托。

案例

案例一:手动下单+智能分批算法

对于大资金客户,是否有下单单量大,唯恐惊扰行情趋势的困扰?是否有欲拉动行情却缕缕付出了大量成本的困扰?这里我们以此为例通过手动下单调用算法交易的方式介绍两个案例来解决你的困扰。


策略1:通过算法根据买卖量,自动拆分大单


交易思路解析:

1、取得手动下单的合约、手数、买卖方向、开平方向;自设委托价格。

2、如果为开仓:

(1)如果为买入开仓:

分批买入,取盘口卖一量*1/2与剩余下单手数比较,取数量较小值根据盘口卖一价买入,第一批成交后,再委托第二批,直至完全成交后退出算法。

(2)如果为卖出开仓:

分批卖出,取盘口买一量*1/2与剩余下单手数比较,取数量较小值根据盘口买一价卖出,第一批成交后,再委托第二批,直至完全成交后退出算法。

3、如果为平仓:

(1)如果为买入平仓:

分批处理同买入开仓。

(2)如果为卖出平仓:

分批处理同卖出开仓。


源码实现:

Vars
Global_String AID; //账号
Global_String COD; //合约编码
Numeric P; //数值比例
Numeric SH; //上海合约标志
Numeric BSF; //买卖方向
Numeric EEF; //开平方向
Numeric BIDP,ASKP; //买卖一价
Numeric BIDV,ASKV; //买卖一量
Numeric BRP0,BRP1,BRP; //多头可用持仓
Numeric SRP0,SRP1,SRP; //空头可用持仓
Numeric OPFLG; //模型处理标志
Global_Numeric VLM; //交易手数
Global_Numeric KPFLG; //委托处理标志
Global_Numeric BKDFLG; //买开处理标志
Global_Numeric SKDFLG; //卖开处理标志
Global_Numeric BPDFLG; //买平处理标志
Global_Numeric SPDFLG; //卖平处理标志
Global_Numeric BKID,SKID; //开仓委托
Global_Numeric BKFLG,SKFLG; //开仓标志
Global_Numeric BKM,SKM; //开仓委托手数
Global_Numeric BKP,SKP; //开仓委托价格
Global_Numeric BPID0,BPID1,BPID; //买平委托
Global_Numeric SPID0,SPID1,SPID; //卖平委托
Global_Numeric BPFLG0,BPFLG1,BPFLG; //买平标志
Global_Numeric SPFLG0,SPFLG1,SPFLG; //卖平标志
Global_Numeric BPM0,BPM1,BPM; //买平委托手数
Global_Numeric SPM0,SPM1,SPM; //卖平委托手数
Global_Numeric BPP0,BPP1,BPP; //买平委托价格
Global_Numeric SPP0,SPP1,SPP; //卖平委托价格
Begin
//------------------------委托获取------------------------//
If(1) //委托获取
{
If(KPFLG == 0) //如果未开启委托处理
{
AID = M_GetTradeAccount(0); //账号
COD = M_GetTradeContract(); //合约编码
BSF = M_GetTradeBuySell(); //买卖方向
EEF = M_GetTradeEntryExit(); //开平方向
VLM = M_GetTradeVol(); //交易手数
If(VLM > 0 && COD.A_IsExchangeOpen() == 1) //如果交易手数大于0,且当前状态是开盘
{
If(BSF == Enum_Buy && EEF == Enum_Entry) //如果是买开方向
{
   Commentary("【" + COD + "做多:手动买开" + Text(VLM) + "手!】");
   BKDFLG = 1; //开启买开处理
}
Else If(BSF == Enum_Sell && EEF == Enum_Exit) //如果是卖平方向
{
   Commentary("【" + COD + "平多:手动卖平" + Text(VLM) + "手!】");
   SPDFLG = 1; //开启卖平处理
}
Else If(BSF == Enum_Sell && EEF == Enum_ExitToday) //如果是卖平今方向
{
   Commentary("【" + COD + "平今多:手动卖平" + Text(VLM) + "手!】");
   SPDFLG = 2; //开启卖平今仓处理
}
Else If(BSF == Enum_Sell && EEF == Enum_Entry) //如果是卖开方向
{
   Commentary("【" + COD + "做空:手动卖开" + Text(VLM) + "手!】");
   SKDFLG = 1; //开启卖开处理
}
Else If(BSF == Enum_Buy && EEF == Enum_Exit) //如果是买平方向
{
   Commentary("【" + COD + "平空:手动买平" + Text(VLM) + "手!】");
   BPDFLG = 1; //开启买平处理
}
Else If(BSF == Enum_Buy && EEF == Enum_ExitToday) //如果是买平今方向
{
   Commentary("【" + COD + "平今空:手动买平" + Text(VLM) + "手!】");
   BPDFLG = 2; //开启买平今仓处理
}
KPFLG = 1; //开启委托处理
}
}
If(KPFLG == 1 && COD.A_IsExchangeOpen() == 1) //如果已开启委托处理,且当前状态是开盘
{
OPFLG = 1; //开启模型处理
}
}
//------------------------变量赋值------------------------//
If(OPFLG == 1) //变量赋值
{
P = 0.5; //数值比例
BIDP = COD.Price("Bid1"); //买一价
ASKP = COD.Price("Ask1"); //卖一价
BIDV = COD.Price("BidVol1"); //买一量
ASKV = COD.Price("AskVol1"); //卖一量
SH = COD.A_IsSHCode(); //上海合约标志
BRP = COD.A_BuyRemainPosition(); //多头可用持仓
SRP = COD.A_SellRemainPosition(); //空头可用持仓
If(SH == 1) //如果是上期所合约
{
BRP0 = COD.A_TodayBuyRemainPosition(); //多头今仓可用持仓
SRP0 = COD.A_TodaySellRemainPosition(); //空头今仓可用持仓
BRP1 = BRP - BRP0; //多头老仓可用持仓
SRP1 = SRP - SRP0; //空头老仓可用持仓
}
}
//------------------------成交判断------------------------//
If(OPFLG == 1) //成交判断
{
If(BKFLG == 1) //如果有买开委托
{
If(F_OrderStatus(BKID) == Enum_Filled) //如果买开委托成交
{
Commentary("【" + COD + "做多:买开委托成交!】");
VLM = VLM - BKM; //交易手数
BKFLG = 0; //买开标志归0
}
}
If(SH == 1) //如果是上期所合约
{
If(SPFLG0 == 1) //如果有卖平今仓委托
{
If(F_OrderStatus(SPID0) == Enum_Filled) //如果卖平今仓委托成交
{
   Commentary("【" + COD + "平多:卖平今仓委托成交!】");
   VLM = VLM - SPM0; //交易手数
   SPFLG0 = 0; //卖平今仓标志归0
}
}
If(SPFLG1 == 1) //如果有卖平老仓委托
{
If(F_OrderStatus(SPID1) == Enum_Filled) //如果卖平老仓委托成交
{
   Commentary("【" + COD + "平多:卖平老仓委托成交!】");
   VLM = VLM - SPM1; //交易手数
   SPFLG1 = 0; //卖平老仓标志归0
}
}
}
Else //如果非上期所合约
{
If(SPFLG == 1) //如果有卖平委托
{
If(F_OrderStatus(SPID) == Enum_Filled) //如果卖平委托成交
{
   Commentary("【" + COD + "平多:卖平委托成交!】");
   VLM = VLM - SPM; //交易手数
   SPFLG = 0; //卖平标志归0
}
}
}
If(SKFLG == 1) //如果有卖开委托
{
If(F_OrderStatus(SKID) == Enum_Filled) //如果卖开委托成交
{
Commentary("【" + COD + "做空:卖开委托成交!】");
VLM = VLM - SKM; //交易手数
SKFLG = 0; //卖开标志归0
}
}
If(SH == 1) //如果是上期所合约
{
If(BPFLG0 == 1) //如果有买平今仓委托
{
If(F_OrderStatus(BPID0) == Enum_Filled) //如果买平今仓委托成交
{
   Commentary("【" + COD + "平空:买平今仓委托成交!】");
   VLM = VLM - BPM0; //交易手数
   BPFLG0 = 0; //买平今仓标志归0
}
}
If(BPFLG1 == 1) //如果有买平老仓委托
{
If(F_OrderStatus(BPID1) == Enum_Filled) //如果买平老仓委托成交
{
   Commentary("【" + COD + "平空:买平老仓委托成交!】");
   VLM = VLM - BPM1; //交易手数
   BPFLG1 = 0; //买平老仓标志归0
}
}
}
Else //如果非上期所合约
{
If(BPFLG == 1) //如果有买平委托
{
If(F_OrderStatus(BPID) == Enum_Filled) //如果买平委托成交
{
   Commentary("【" + COD + "平空:买平委托成交!】");
   VLM = VLM - BPM; //交易手数
   BPFLG = 0; //买平标志归0
}
}
}
}
//------------------------委托处理------------------------//
If(OPFLG == 1) //委托处理
{
If(BKDFLG == 1) //如果已开启买开处理
{
If(BKFLG == 0) //如果没有买开委托
{
BKM = Min(Ceiling(P * ASKV,1),VLM); //买开委托手数
If(BKM > 0) //如果买开委托手数大于0
{
   BKP = ASKP; //买开委托价格
   Commentary("【" + COD + "做多:公式买开" + Text(BKM) + "手!】");
   Commentary("【" + COD + "做多:买开委托发出!】");
   BKID = COD.A_SendOrder(Enum_Buy,Enum_Entry,BKM,BKP,AID); //发出买开委托
   BKFLG = 1; //已发出买开委托
}
Else If(BKM == 0) //如果买开委托手数等于0
{
   Commentary("【" + COD + "做多:买开委托完成!】");
   Exit(); //退出公式
}
}
}
If(SPDFLG > 0) //如果已开启卖平处理
{
If(SPFLG0 == 0 && SPFLG1 == 0 && SPFLG == 0) //如果没有卖平委托
{
SPM = Min(Ceiling(P * BIDV,1),VLM); //卖平委托手数
If(BRP > 0 && SPM > 0) //如果有多头可用持仓,且卖平委托手数大于0
{
   If(SH == 1) //如果是上期所合约
   {
      If(SPDFLG == 2) //如果是卖平今仓处理
      {
         If(BRP0 > 0) //如果有多头今仓可用持仓
         {
            SPM0 = Min(BRP0,SPM); //卖平今仓委托手数
            SPP0 = BIDP; //卖平今仓委托价格
            Commentary("【" + COD + "平多:公式卖平今仓" + Text(SPM0) + "手!】");
            Commentary("【" + COD + "平多:卖平今仓委托发出!】");
            SPID0 = COD.A_SendOrder(Enum_Sell,Enum_ExitToday,SPM0,SPP0,AID); //发出卖平今仓委托
            SPFLG0 = 1; //已发出卖平今仓委托
         }
         Else If(BRP0 == 0) //如果没有多头今仓可用持仓
         {
            Commentary("【" + COD + "平多:卖平委托完成!】");
            Exit(); //退出公式
         }
      }
      Else If(SPDFLG == 1) //如果是卖平处理
      {
         If(BRP1 > 0) //如果有多头老仓可用持仓
         {
            SPM1 = Min(BRP1,SPM); //卖平老仓委托手数
            SPP1 = BIDP; //卖平老仓委托价格
            Commentary("【" + COD + "平多:公式卖平老仓" + Text(SPM1) + "手!】");
            Commentary("【" + COD + "平多:卖平老仓委托发出!】");
            SPID1 = COD.A_SendOrder(Enum_Sell,Enum_Exit,SPM1,SPP1,AID); //发出卖平老仓委托
            SPFLG1 = 1; //已发出卖平老仓委托
         }
         Else If(BRP1 == 0) //如果没有多头老仓可用持仓
         {
            Commentary("【" + COD + "平多:卖平委托完成!】");
            Exit(); //退出公式
         }
      }
   }
   Else //如果非上期所合约
   {
      SPM = Min(BRP,SPM); //卖平委托手数
      SPP = BIDP; //卖平委托价格
      Commentary("【" + COD + "平多:公式卖平" + Text(SPM) + "手!】");
      Commentary("【" + COD + "平多:卖平委托发出!】");
      SPID = COD.A_SendOrder(Enum_Sell,Enum_Exit,SPM,SPP,AID); //发出卖平委托
      SPFLG = 1; //已发出卖平委托
   }
}
Else If(BRP == 0 || SPM == 0) //如果没有多头可用持仓,或卖平委托手数等于0
{
   Commentary("【" + COD + "平多:卖平委托完成!】");
   Exit(); //退出公式
}
}
}
If(SKDFLG == 1) //如果已开启卖开处理
{
If(SKFLG == 0) //如果没有卖开委托
{
SKM = Min(Ceiling(P * BIDV,1),VLM); //卖开委托手数
If(SKM > 0) //如果卖开委托手数大于0
{
   SKP = BIDP; //卖开委托价格
   Commentary("【" + COD + "做空:公式卖开" + Text(SKM) + "手!】");
   Commentary("【" + COD + "做空:卖开委托发出!】");
   SKID = COD.A_SendOrder(Enum_Sell,Enum_Entry,SKM,SKP,AID); //发出卖开委托
   SKFLG = 1; //已发出卖开委托
}
Else If(SKM == 0) //如果卖开委托手数等于0
{
   Commentary("【" + COD + "做空:卖开委托完成!】");
   Exit(); //退出公式
}
}
}
If(BPDFLG > 0) //如果已开启买平处理
{
If(BPFLG0 == 0 && BPFLG1 == 0 && BPFLG == 0) //如果没有买平委托
{
BPM = Min(Ceiling(P * ASKV,1),VLM); //买平委托手数
If(SRP > 0 && BPM > 0) //如果有空头可用持仓,且买平委托手数大于0
{
   If(SH == 1) //如果是上期所合约
   {
      If(BPDFLG == 2) //如果是买平今仓处理
      {
         If(SRP0 > 0) //如果有空头今仓可用持仓
         {
            BPM0 = Min(SRP0,BPM); //买平今仓委托手数
            BPP0 = ASKP; //买平今仓委托价格
            Commentary("【" + COD + "平空:公式买平今仓" + Text(BPM0) + "手!】");
            Commentary("【" + COD + "平空:买平今仓委托发出!】");
            BPID0 = COD.A_SendOrder(Enum_Buy,Enum_ExitToday,BPM0,BPP0,AID); //发出买平今仓委托
            BPFLG0 = 1; //已发出买平今仓委托
         }
         Else If(SRP0 == 0) //如果没有空头今仓可用持仓
         {
            Commentary("【" + COD + "平空:买平委托完成!】");
            Exit(); //退出公式
         }
      }
      Else If(BPDFLG == 1) //如果是买平处理
      {
         If(SRP1 > 0) //如果有空头老仓可用持仓
         {
            BPM1 = Min(SRP1,BPM); //买平老仓委托手数
            BPP1 = ASKP; //买平老仓委托价格
            Commentary("【" + COD + "平空:公式买平老仓" + Text(BPM1) + "手!】");
            Commentary("【" + COD + "平空:买平老仓委托发出!】");
            BPID1 = COD.A_SendOrder(Enum_Buy,Enum_Exit,BPM1,BPP1,AID); //发出买平老仓委托
            BPFLG1 = 1; //已发出买平老仓委托
         }
         Else If(SRP1 == 0) //如果没有空头老仓可用持仓
         {
            Commentary("【" + COD + "平空:买平委托完成!】");
            Exit(); //退出公式
         }
      }
   }
   Else //如果非上期所合约
   {
      BPM = Min(SRP,BPM); //买平委托手数
      BPP = ASKP; //买平委托价格
      Commentary("【" + COD + "平空:公式买平" + Text(BPM) + "手!】");
      Commentary("【" + COD + "平空:买平委托发出!】");
      BPID = COD.A_SendOrder(Enum_Buy,Enum_Exit,BPM,BPP,AID); //发出买平委托
      BPFLG = 1; //已发出买平委托
   }
}
Else If(SRP == 0 || BPM == 0) //如果没有空头可用持仓,或买平委托手数等于0
{
   Commentary("【" + COD + "平空:买平委托完成!】");
   Exit(); //退出公式
}
}
}
}
End


通过右上方菜单【运行】->【算法交易运行池】->【算法交易下单】,调出算法交易下单界面,按下图所示方法实现手动下单调用算法交易:


注:①如果再次下单,会再次加载该模型,不会直接在前一个算法交易模型中继续执行。

②如果模型中含有函数Exit(),则模型执行完毕后会自动退出。


策略2:拉动行情,每次自动把买盘吃光,将行情往上拉,反之亦然。


交易思路解析:

1、取值手动下单的合约、手数、买卖方向、开平方向;自设委托价格。

2、如果为开仓:

(1)如果为买入开仓:

分批买入,取盘口卖一量与剩余下单手数比较,取数量较小值根据盘口卖一价买入。

如果盘口卖一价变化,撤单并重新委托,取盘口卖一量与该批剩余下单手数比较,取数量较小值根据盘口卖一价买入,直至完全成交完全成交后退出算法。

(2)如果为卖出开仓:

分批卖出,取盘口买一量与剩余下单手数比较,取数量较小值根据盘口买一价卖出。

如果盘口买一价变化,撤单并重新委托,取盘口买一量与该批剩余下单手数比较,取数量较小值根据盘口买一价卖出,直至完全成交完全成交后退出算法。

3、如果为平仓:

(1)如果为买入平仓:

分批处理同买入开仓。

(2)如果为卖出开仓:

分批处理同卖出开仓。


源码实现:

Vars
Global_String AID; //账号
Global_String COD; //合约编码
Numeric SH; //上海合约标志
Numeric BSF; //买卖方向
Numeric EEF; //开平方向
Numeric BIDP,ASKP; //买卖一价
Numeric BIDV,ASKV; //买卖一量
Numeric BRP0,BRP1,BRP; //多头可用持仓
Numeric SRP0,SRP1,SRP; //空头可用持仓
Numeric OPFLG; //模型处理标志
Global_Numeric VLM; //交易手数
Global_Numeric KPFLG; //委托处理标志
Global_Numeric BKDFLG; //买开处理标志
Global_Numeric SKDFLG; //卖开处理标志
Global_Numeric BPDFLG; //买平处理标志
Global_Numeric SPDFLG; //卖平处理标志
Global_Numeric BKID,SKID; //开仓委托
Global_Numeric BKFLG,SKFLG; //开仓标志
Global_Numeric BKDEL,SKDEL; //开仓撤单标志
Global_Numeric BKCM,SKCM; //开仓成交手数
Global_Numeric BKM,SKM; //开仓委托手数
Global_Numeric BKP,SKP; //开仓委托价格
Global_Numeric BPID0,BPID1,BPID; //买平委托
Global_Numeric SPID0,SPID1,SPID; //卖平委托
Global_Numeric BPFLG0,BPFLG1,BPFLG; //买平标志
Global_Numeric SPFLG0,SPFLG1,SPFLG; //卖平标志
Global_Numeric BPDEL0,BPDEL1,BPDEL; //买平撤单标志
Global_Numeric SPDEL0,SPDEL1,SPDEL; //卖平撤单标志
Global_Numeric BPCM0,BPCM1,BPCM; //买平成交手数
Global_Numeric SPCM0,SPCM1,SPCM; //卖平成交手数
Global_Numeric BPM0,BPM1,BPM; //买平委托手数
Global_Numeric SPM0,SPM1,SPM; //卖平委托手数
Global_Numeric BPP0,BPP1,BPP; //买平委托价格
Global_Numeric SPP0,SPP1,SPP; //卖平委托价格
Begin
//------------------------委托获取------------------------//
If(1) //委托获取
{
If(KPFLG == 0) //如果未开启委托处理
{
AID = M_GetTradeAccount(0); //账号
COD = M_GetTradeContract(); //合约编码
BSF = M_GetTradeBuySell(); //买卖方向
EEF = M_GetTradeEntryExit(); //开平方向
VLM = M_GetTradeVol(); //交易手数
If(VLM > 0 && COD.A_IsExchangeOpen() == 1) //如果交易手数大于0,且当前状态是开盘
{
If(BSF == Enum_Buy && EEF == Enum_Entry) //如果是买开方向
{
   Commentary("【" + COD + "做多:手动买开" + Text(VLM) + "手!】");
   BKDFLG = 1; //开启买开处理
}
Else If(BSF == Enum_Sell && EEF == Enum_Exit) //如果是卖平方向
{
   Commentary("【" + COD + "平多:手动卖平" + Text(VLM) + "手!】");
   SPDFLG = 1; //开启卖平处理
}
Else If(BSF == Enum_Sell && EEF == Enum_ExitToday) //如果是卖平今方向
{
   Commentary("【" + COD + "平今多:手动卖平" + Text(VLM) + "手!】");
   SPDFLG = 2; //开启卖平今仓处理
}
Else If(BSF == Enum_Sell && EEF == Enum_Entry) //如果是卖开方向
{
   Commentary("【" + COD + "做空:手动卖开" + Text(VLM) + "手!】");
   SKDFLG = 1; //开启卖开处理
}
Else If(BSF == Enum_Buy && EEF == Enum_Exit) //如果是买平方向
{
   Commentary("【" + COD + "平空:手动买平" + Text(VLM) + "手!】");
   BPDFLG = 1; //开启买平处理
}
Else If(BSF == Enum_Buy && EEF == Enum_ExitToday) //如果是买平今方向
{
   Commentary("【" + COD + "平今空:手动买平" + Text(VLM) + "手!】");
   BPDFLG = 2; //开启买平今仓处理
}
KPFLG = 1; //开启委托处理
}
}
If(KPFLG == 1 && COD.A_IsExchangeOpen() == 1) //如果已开启委托处理,且当前状态是开盘
{
OPFLG = 1; //开启模型处理
}
}
//------------------------变量赋值------------------------//
If(OPFLG == 1) //变量赋值
{
BIDP = COD.Price("Bid1"); //买一价
ASKP = COD.Price("Ask1"); //卖一价
BIDV = COD.Price("BidVol1"); //买一量
ASKV = COD.Price("AskVol1"); //卖一量
SH = COD.A_IsSHCode(); //上海合约标志
BRP = COD.A_BuyRemainPosition(); //多头可用持仓
SRP = COD.A_SellRemainPosition(); //空头可用持仓
If(SH == 1) //如果是上期所合约
{
BRP0 = COD.A_TodayBuyRemainPosition(); //多头今仓可用持仓
SRP0 = COD.A_TodaySellRemainPosition(); //空头今仓可用持仓
BRP1 = BRP - BRP0; //多头老仓可用持仓
SRP1 = SRP - SRP0; //空头老仓可用持仓
}
}
//------------------------成交判断------------------------//
If(OPFLG == 1) //成交判断
{
If(BKFLG == 1) //如果有买开委托
{
If(F_OrderStatus(BKID) == Enum_Filled) //如果买开委托成交
{
Commentary("【" + COD + "做多:买开委托成交!】");
VLM = VLM - BKM; //交易手数
BKFLG = 0; //买开标志归0
BKDEL = 0; //买开撤单标志归0
}
Else If(F_OrderStatus(BKID) == Enum_Canceled) //如果买开委托已撤
{
Commentary("【" + COD + "做多:买开委托已撤!】");
BKCM = F_OrderFilledLot(BKID); //买开成交手数
If(BKCM > 0) //如果买开委托部分成交
{
   BKM = BKM - BKCM; //买开委托手数
   VLM = VLM - BKCM; //交易手数
}
BKM = Min(ASKV,BKM); //买开委托手数
If(BKM > 0) //如果买开委托手数大于0
{
   BKP = ASKP; //买开委托价格
   Commentary("【" + COD + "做多:公式买开" + Text(BKM) + "手!】");
   Commentary("【" + COD + "做多:买开委托追价!】");
   BKID = COD.A_SendOrder(Enum_Buy,Enum_Entry,BKM,BKP,AID); //发出买开委托
}
BKDEL = 0; //买开撤单标志归0
}
Else If(F_OrderStatus(BKID) == Enum_Declared || F_OrderStatus(BKID) == Enum_FillPart) //如果买开委托挂单
{
If(ASKP != BKP && BKDEL == 0) //如果卖一价不等于买开委托价格,且未撤单
{
   Commentary("【" + COD + "做多:买开委托撤单!】");
   F_DeleteOrder(F_OrderContractNo(BKID)); //撤掉买开委托挂单
   BKDEL = 1; //已发出撤掉买开委托挂单
}
}
}
If(SH == 1) //如果是上期所合约
{
If(SPFLG0 == 1) //如果有卖平今仓委托
{
If(F_OrderStatus(SPID0) == Enum_Filled) //如果卖平今仓委托成交
{
   Commentary("【" + COD + "平多:卖平今仓委托成交!】");
   VLM = VLM - SPM0; //交易手数
   SPFLG0 = 0; //卖平今仓标志归0
   SPDEL0 = 0; //卖平今仓撤单标志归0
}
Else If(F_OrderStatus(SPID0) == Enum_Canceled) //如果卖平今仓委托已撤
{
   Commentary("【" + COD + "平多:卖平今仓委托已撤!】");
   SPCM0 = F_OrderFilledLot(SPID0); //卖平今仓成交手数
   If(SPCM0 > 0) //如果卖平今仓委托部分成交
   {
      SPM0 = SPM0 - SPCM0; //卖平今仓委托手数
      VLM = VLM - SPCM0; //交易手数
   }
   SPM0 = Min1(BRP0,BIDV,SPM0); //卖平今仓委托手数
   If(BRP0 > 0 && SPM0 > 0) //如果有多头今仓可用持仓,且卖平今仓委托手数大于0
   {
      SPP0 = BIDP; //卖平今仓委托价格
      Commentary("【" + COD + "平多:公式卖平今仓" + Text(SPM0) + "手!】");
      Commentary("【" + COD + "平多:卖平今仓委托追价!】");
      SPID0 = COD.A_SendOrder(Enum_Sell,Enum_ExitToday,SPM0,SPP0,AID); //发出卖平今仓委托
   }
   SPDEL0 = 0; //卖平今仓撤单标志归0
}
Else If(F_OrderStatus(SPID0) == Enum_Declared || F_OrderStatus(SPID0) == Enum_FillPart) //如果卖平今仓委托挂单
{
   If(BIDP != SPP0 && SPDEL0 == 0) //如果买一价不等于卖平今仓委托价格,且未撤单
   {
      Commentary("【" + COD + "平多:卖平今仓委托撤单!】");
      F_DeleteOrder(F_OrderContractNo(SPID0)); //撤掉卖平今仓委托挂单
      SPDEL0 = 1; //已发出撤掉卖平今仓委托挂单
   }
}
}
If(SPFLG1 == 1) //如果有卖平老仓委托
{
If(F_OrderStatus(SPID1) == Enum_Filled) //如果卖平老仓委托成交
{
   Commentary("【" + COD + "平多:卖平老仓委托成交!】");
   VLM = VLM - SPM1; //交易手数
   SPFLG1 = 0; //卖平老仓标志归0
   SPDEL1 = 0; //卖平老仓撤单标志归0
}
Else If(F_OrderStatus(SPID1) == Enum_Canceled) //如果卖平老仓委托已撤
{
   Commentary("【" + COD + "平多:卖平老仓委托已撤!】");
   SPCM1 = F_OrderFilledLot(SPID1); //卖平老仓成交手数
   If(SPCM1 > 0) //如果卖平老仓委托部分成交
   {
      SPM1 = SPM1 - SPCM1; //卖平老仓委托手数
      VLM = VLM - SPCM1; //交易手数
   }
   SPM1 = Min1(BRP1,BIDV,SPM1); //卖平老仓委托手数
   If(BRP1 > 0 && SPM1 > 0) //如果有多头老仓可用持仓,且卖平老仓委托手数大于0
   {
      SPP1 = BIDP; //卖平老仓委托价格
      Commentary("【" + COD + "平多:公式卖平老仓" + Text(SPM1) + "手!】");
      Commentary("【" + COD + "平多:卖平老仓委托追价!】");
      SPID1 = COD.A_SendOrder(Enum_Sell,Enum_Exit,SPM1,SPP1,AID); //发出卖平老仓委托
   }
   SPDEL1 = 0; //卖平老仓撤单标志归0
}
Else If(F_OrderStatus(SPID1) == Enum_Declared || F_OrderStatus(SPID1) == Enum_FillPart) //如果卖平老仓委托挂单
{
   If(BIDP != SPP1 && SPDEL1 == 0) //如果买一价不等于卖平老仓委托价格,且未撤单
   {
      Commentary("【" + COD + "平多:卖平老仓委托撤单!】");
      F_DeleteOrder(F_OrderContractNo(SPID1)); //撤掉卖平老仓委托挂单
      SPDEL1 = 1; //已发出撤掉卖平老仓委托挂单
   }
}
}
}
Else //如果非上期所合约
{
If(SPFLG == 1) //如果有卖平委托
{
If(F_OrderStatus(SPID) == Enum_Filled) //如果卖平委托成交
{
   Commentary("【" + COD + "平多:卖平委托成交!】");
   VLM = VLM - SPM; //交易手数
   SPFLG = 0; //卖平标志归0
   SPDEL = 0; //卖平撤单标志归0
}
Else If(F_OrderStatus(SPID) == Enum_Canceled) //如果卖平委托已撤
{
   Commentary("【" + COD + "平多:卖平委托已撤!】");
   SPCM = F_OrderFilledLot(SPID); //卖平成交手数
   If(SPCM > 0) //如果卖平委托部分成交
   {
      SPM = SPM - SPCM; //卖平委托手数
      VLM = VLM - SPCM; //交易手数
   }
   SPM = Min1(BRP,BIDV,SPM); //卖平委托手数
   If(BRP > 0 && SPM > 0) //如果有多头可用持仓,且卖平委托手数大于0
   {
      SPP = BIDP; //卖平委托价格
      Commentary("【" + COD + "平多:公式卖平" + Text(SPM) + "手!】");
      Commentary("【" + COD + "平多:卖平委托追价!】");
      SPID = COD.A_SendOrder(Enum_Sell,Enum_Exit,SPM,SPP,AID); //发出卖平委托
   }
   SPDEL = 0; //卖平撤单标志归0
}
Else If(F_OrderStatus(SPID) == Enum_Declared || F_OrderStatus(SPID) == Enum_FillPart) //如果卖平委托挂单
{
   If(BIDP != SPP && SPDEL == 0) //如果买一价不等于卖平委托价格,且未撤单
   {
      Commentary("【" + COD + "平多:卖平委托撤单!】");
      F_DeleteOrder(F_OrderContractNo(SPID)); //撤掉卖平委托挂单
      SPDEL = 1; //已发出撤掉卖平委托挂单
   }
}
}
}
If(SKFLG == 1) //如果有卖开委托
{
If(F_OrderStatus(SKID) == Enum_Filled) //如果卖开委托成交
{
Commentary("【" + COD + "做空:卖开委托成交!】");
VLM = VLM - SKM; //交易手数
SKFLG = 0; //卖开标志归0
SKDEL = 0; //卖开撤单标志归0
}
Else If(F_OrderStatus(SKID) == Enum_Canceled) //如果卖开委托已撤
{
Commentary("【" + COD + "做空:卖开委托已撤!】");
SKCM = F_OrderFilledLot(SKID); //卖开成交手数
If(SKCM > 0) //如果卖开委托部分成交
{
   SKM = SKM - SKCM; //卖开委托手数
   VLM = VLM - SKCM; //交易手数
}
SKM = Min(BIDV,SKM); //卖开委托手数
If(SKM > 0) //如果卖开委托手数大于0
{
   SKP = BIDP; //卖开委托价格
   Commentary("【" + COD + "做空:公式卖开" + Text(SKM) + "手!】");
   Commentary("【" + COD + "做空:卖开委托追价!】");
   SKID = COD.A_SendOrder(Enum_Sell,Enum_Entry,SKM,SKP,AID); //发出卖开委托
}
SKDEL = 0; //卖开撤单标志归0
}
Else If(F_OrderStatus(SKID) == Enum_Declared || F_OrderStatus(SKID) == Enum_FillPart) //如果卖开委托挂单
{
If(BIDP != SKP && SKDEL == 0) //如果买一价不等于卖开委托价格,且未撤单
{
   Commentary("【" + COD + "做空:卖开委托撤单!】");
   F_DeleteOrder(F_OrderContractNo(SKID)); //撤掉卖开委托挂单
   SKDEL = 1; //已发出撤掉卖开委托挂单
}
}
}
If(SH == 1) //如果是上期所合约
{
If(BPFLG0 == 1) //如果有买平今仓委托
{
If(F_OrderStatus(BPID0) == Enum_Filled) //如果买平今仓委托成交
{
   Commentary("【" + COD + "平空:买平今仓委托成交!】");
   VLM = VLM - BPM0; //交易手数
   BPFLG0 = 0; //买平今仓标志归0
   BPDEL0 = 0; //买平今仓撤单标志归0
}
Else If(F_OrderStatus(BPID0) == Enum_Canceled) //如果买平今仓委托已撤
{
   Commentary("【" + COD + "平空:买平今仓委托已撤!】");
   BPCM0 = F_OrderFilledLot(BPID0); //买平今仓成交手数
   If(BPCM0 > 0) //如果买平今仓委托部分成交
   {
      BPM0 = BPM0 - BPCM0; //买平今仓委托手数
      VLM = VLM - BPCM0; //交易手数
   }
   BPM0 = Min1(SRP0,ASKV,BPM0); //买平今仓委托手数
   If(SRP0 > 0 && BPM0 > 0) //如果有空头今仓可用持仓,且买平今仓委托手数大于0
   {
      BPP0 = ASKP; //买平今仓委托价格
      Commentary("【" + COD + "平空:公式买平今仓" + Text(BPM0) + "手!】");
      Commentary("【" + COD + "平空:买平今仓委托追价!】");
      BPID0 = COD.A_SendOrder(Enum_Buy,Enum_ExitToday,BPM0,BPP0,AID); //发出买平今仓委托
   }
   BPDEL0 = 0; //买平今仓撤单标志归0
}
Else If(F_OrderStatus(BPID0) == Enum_Declared || F_OrderStatus(BPID0) == Enum_FillPart) //如果买平今仓委托挂单
{
   If(ASKP != BPP0 && BPDEL0 == 0) //如果卖一价不等于买平今仓委托价格,且未撤单
   {
      Commentary("【" + COD + "平空:买平今仓委托撤单!】");
      F_DeleteOrder(F_OrderContractNo(BPID0)); //撤掉买平今仓委托挂单
      BPDEL0 = 1; //已发出撤掉买平今仓委托挂单
   }
}
}
If(BPFLG1 == 1) //如果有买平老仓委托
{
If(F_OrderStatus(BPID1) == Enum_Filled) //如果买平老仓委托成交
{
   Commentary("【" + COD + "平空:买平老仓委托成交!】");
   VLM = VLM - BPM1; //交易手数
   BPFLG1 = 0; //买平老仓标志归0
   BPDEL1 = 0; //买平老仓撤单标志归0
}
Else If(F_OrderStatus(BPID1) == Enum_Canceled) //如果买平老仓委托已撤
{
   Commentary("【" + COD + "平空:买平老仓委托已撤!】");
   BPCM1 = F_OrderFilledLot(BPID1); //买平老仓成交手数
   If(BPCM1 > 0) //如果买平老仓委托部分成交
   {
      BPM1 = BPM1 - BPCM1; //买平老仓委托手数
      VLM = VLM - BPCM1; //交易手数
   }
   BPM1 = Min1(SRP1,ASKV,BPM1); //买平老仓委托手数
   If(SRP1 > 0 && BPM1 > 0) //如果有空头老仓可用持仓,且买平老仓委托手数大于0
   {
      BPP1 = ASKP; //买平老仓委托价格
      Commentary("【" + COD + "平空:公式买平老仓" + Text(BPM1) + "手!】");
      Commentary("【" + COD + "平空:买平老仓委托追价!】");
      BPID1 = COD.A_SendOrder(Enum_Buy,Enum_Exit,BPM1,BPP1,AID); //发出买平老仓委托
   }
   BPDEL1 = 0; //买平老仓撤单标志归0
}
Else If(F_OrderStatus(BPID1) == Enum_Declared || F_OrderStatus(BPID1) == Enum_FillPart) //如果买平老仓委托挂单
{
   If(ASKP != BPP1 && BPDEL1 == 0) //如果卖一价不等于买平老仓委托价格,且未撤单
   {
      Commentary("【" + COD + "平空:买平老仓委托撤单!】");
      F_DeleteOrder(F_OrderContractNo(BPID1)); //撤掉买平老仓委托挂单
      BPDEL1 = 1; //已发出撤掉买平老仓委托挂单
   }
}
}
}
Else //如果非上期所合约
{
If(BPFLG == 1) //如果有买平委托
{
If(F_OrderStatus(BPID) == Enum_Filled) //如果买平委托成交
{
   Commentary("【" + COD + "平空:买平委托成交!】");
   VLM = VLM - BPM; //交易手数
   BPFLG = 0; //买平标志归0
   BPDEL = 0; //买平撤单标志归0
}
Else If(F_OrderStatus(BPID) == Enum_Canceled) //如果买平委托已撤
{
   Commentary("【" + COD + "平空:买平委托已撤!】");
   BPCM = F_OrderFilledLot(BPID); //买平成交手数
   If(BPCM > 0) //如果买平委托部分成交
   {
      BPM = BPM - BPCM; //买平委托手数
      VLM = VLM - BPCM; //交易手数
   }
   BPM = Min1(SRP,ASKV,BPM); //买平委托手数
   If(SRP > 0 && BPM > 0) //如果有空头可用持仓,且买平委托手数大于0
   {
      BPP = ASKP; //买平委托价格
      Commentary("【" + COD + "平空:公式买平" + Text(BPM) + "手!】");
      Commentary("【" + COD + "平空:买平委托追价!】");
      BPID = COD.A_SendOrder(Enum_Buy,Enum_Exit,BPM,BPP,AID); //发出买平委托
   }
   BPDEL = 0; //买平撤单标志归0
}
Else If(F_OrderStatus(BPID) == Enum_Declared || F_OrderStatus(BPID) == Enum_FillPart) //如果买平委托挂单
{
   If(ASKP != BPP && BPDEL == 0) //如果卖一价不等于买平委托价格,且未撤单
   {
      Commentary("【" + COD + "平空:买平委托撤单!】");
      F_DeleteOrder(F_OrderContractNo(BPID)); //撤掉买平委托挂单
      BPDEL = 1; //已发出撤掉买平委托挂单
   }
}
}
}
}
//------------------------委托处理------------------------//
If(OPFLG == 1) //委托处理
{
If(BKDFLG == 1) //如果已开启买开处理
{
If(BKFLG == 0) //如果没有买开委托
{
BKM = Min(ASKV,VLM); //买开委托手数
If(BKM > 0) //如果买开委托手数大于0
{
   BKP = ASKP; //买开委托价格
   Commentary("【" + COD + "做多:公式买开" + Text(BKM) + "手!】");
   Commentary("【" + COD + "做多:买开委托发出!】");
   BKID = COD.A_SendOrder(Enum_Buy,Enum_Entry,BKM,BKP,AID); //发出买开委托
   BKFLG = 1; //已发出买开委托
}
Else If(BKM == 0) //如果买开委托手数等于0
{
   Commentary("【" + COD + "做多:买开委托完成!】");
   Exit(); //退出公式
}
}
}
If(SPDFLG > 0) //如果已开启卖平处理
{
If(SPFLG0 == 0 && SPFLG1 == 0 && SPFLG == 0) //如果没有卖平委托
{
SPM = Min(BIDV,VLM); //卖平委托手数
If(BRP > 0 && SPM > 0) //如果有多头可用持仓,且卖平委托手数大于0
{
   If(SH == 1) //如果是上期所合约
   {
      If(SPDFLG == 2) //如果是卖平今仓处理
      {
         If(BRP0 > 0) //如果有多头今仓可用持仓
         {
            SPM0 = Min(BRP0,SPM); //卖平今仓委托手数
            SPP0 = BIDP; //卖平今仓委托价格
            Commentary("【" + COD + "平多:公式卖平今仓" + Text(SPM0) + "手!】");
            Commentary("【" + COD + "平多:卖平今仓委托发出!】");
            SPID0 = COD.A_SendOrder(Enum_Sell,Enum_ExitToday,SPM0,SPP0,AID); //发出卖平今仓委托
            SPFLG0 = 1; //已发出卖平今仓委托
         }
         Else If(BRP0 == 0) //如果没有多头今仓可用持仓
         {
            Commentary("【" + COD + "平多:卖平委托完成!】");
            Exit(); //退出公式
         }
      }
      Else If(SPDFLG == 1) //如果是卖平处理
      {
         If(BRP1 > 0) //如果有多头老仓可用持仓
         {
            SPM1 = Min(BRP1,SPM); //卖平老仓委托手数
            SPP1 = BIDP; //卖平老仓委托价格
            Commentary("【" + COD + "平多:公式卖平老仓" + Text(SPM1) + "手!】");
            Commentary("【" + COD + "平多:卖平老仓委托发出!】");
            SPID1 = COD.A_SendOrder(Enum_Sell,Enum_Exit,SPM1,SPP1,AID); //发出卖平老仓委托
            SPFLG1 = 1; //已发出卖平老仓委托
         }
         Else If(BRP1 == 0) //如果没有多头老仓可用持仓
         {
            Commentary("【" + COD + "平多:卖平委托完成!】");
            Exit(); //退出公式
         }
      }
   }
   Else //如果非上期所合约
   {
      SPM = Min(BRP,SPM); //卖平委托手数
      SPP = BIDP; //卖平委托价格
      Commentary("【" + COD + "平多:公式卖平" + Text(SPM) + "手!】");
      Commentary("【" + COD + "平多:卖平委托发出!】");
      SPID = COD.A_SendOrder(Enum_Sell,Enum_Exit,SPM,SPP,AID); //发出卖平委托
      SPFLG = 1; //已发出卖平委托
   }
}
Else If(BRP == 0 || SPM == 0) //如果没有多头可用持仓,或卖平委托手数等于0
{
   Commentary("【" + COD + "平多:卖平委托完成!】");
   Exit(); //退出公式
}
}
}
If(SKDFLG == 1) //如果已开启卖开处理
{
If(SKFLG == 0) //如果没有卖开委托
{
SKM = Min(BIDV,VLM); //卖开委托手数
If(SKM > 0) //如果卖开委托手数大于0
{
   SKP = BIDP; //卖开委托价格
   Commentary("【" + COD + "做空:公式卖开" + Text(SKM) + "手!】");
   Commentary("【" + COD + "做空:卖开委托发出!】");
   SKID = COD.A_SendOrder(Enum_Sell,Enum_Entry,SKM,SKP,AID); //发出卖开委托
   SKFLG = 1; //已发出卖开委托
}
Else If(SKM == 0) //如果卖开委托手数等于0
{
   Commentary("【" + COD + "做空:卖开委托完成!】");
   Exit(); //退出公式
}
}
}
If(BPDFLG > 0) //如果已开启买平处理
{
If(BPFLG0 == 0 && BPFLG1 == 0 && BPFLG == 0) //如果没有买平委托
{
BPM = Min(ASKV,VLM); //买平委托手数
If(SRP > 0 && BPM > 0) //如果有空头可用持仓,且买平委托手数大于0
{
   If(SH == 1) //如果是上期所合约
   {
      If(BPDFLG == 2) //如果是买平今仓处理
      {
         If(SRP0 > 0) //如果有空头今仓可用持仓
         {
            BPM0 = Min(SRP0,BPM); //买平今仓委托手数
            BPP0 = ASKP; //买平今仓委托价格
            Commentary("【" + COD + "平空:公式买平今仓" + Text(BPM0) + "手!】");
            Commentary("【" + COD + "平空:买平今仓委托发出!】");
            BPID0 = COD.A_SendOrder(Enum_Buy,Enum_ExitToday,BPM0,BPP0,AID); //发出买平今仓委托
            BPFLG0 = 1; //已发出买平今仓委托
         }
         Else If(SRP0 == 0) //如果没有空头今仓可用持仓
         {
            Commentary("【" + COD + "平空:买平委托完成!】");
            Exit(); //退出公式
         }
      }
      Else If(BPDFLG == 1) //如果是买平处理
      {
         If(SRP1 > 0) //如果有空头老仓可用持仓
         {
            BPM1 = Min(SRP1,BPM); //买平老仓委托手数
            BPP1 = ASKP; //买平老仓委托价格
            Commentary("【" + COD + "平空:公式买平老仓" + Text(BPM1) + "手!】");
            Commentary("【" + COD + "平空:买平老仓委托发出!】");
            BPID1 = COD.A_SendOrder(Enum_Buy,Enum_Exit,BPM1,BPP1,AID); //发出买平老仓委托
            BPFLG1 = 1; //已发出买平老仓委托
         }
         Else If(SRP1 == 0) //如果没有空头老仓可用持仓
         {
            Commentary("【" + COD + "平空:买平委托完成!】");
            Exit(); //退出公式
         }
      }
   }
   Else //如果非上期所合约
   {
      BPM = Min(SRP,BPM); //买平委托手数
      BPP = ASKP; //买平委托价格
      Commentary("【" + COD + "平空:公式买平" + Text(BPM) + "手!】");
      Commentary("【" + COD + "平空:买平委托发出!】");
      BPID = COD.A_SendOrder(Enum_Buy,Enum_Exit,BPM,BPP,AID); //发出买平委托
      BPFLG = 1; //已发出买平委托
   }
}
Else If(SRP == 0 || BPM == 0) //如果没有空头可用持仓,或买平委托手数等于0
{
   Commentary("【" + COD + "平空:买平委托完成!】");
   Exit(); //退出公式
}
}
}
}
End
    


通过右上方菜单【运行】->【算法交易运行池】->【算法交易下单】,调出算法交易下单界面,按下图所示方法实现手动下单调用算法交易:


注:①如果再次下单,会再次加载该模型,不会直接在前一个算法交易模型中继续执行。

②如果模型中含有函数Exit(),则模型执行完毕后会自动退出。


案例二:手动下单+多账号智能分批

算法交易也支持多账号智能分批,既可以对多个账号进行分组,设定不同的委托手数倍率,也可以根据对手盘情况实时计算每一批的总手数,实现多账号智能分批、统一管理。

例如:

我们有三个交易账号需要同时开仓,三个交易账号的委托手数倍率分别为1、1.5、2.5。我们可在多账号下单界面中勾选要参与交易的账号,并设定好下单倍率。



我们可以一键对这三个账号一起进行智能分批下单。

首先,要求每批的总手数不超过盘口对手盘量的20%。首批三个账户按照1 : 1.5 :2.5的比例进行下单。

其次,任何一个账号第一批成交以后(三个账号不一定同时都成交),第二批委托数量为对手盘量的20%乘以该账号的比例,直到全部成交。

最后,任何一个账号如3秒未全部成交,则执行追价策略确保成交。

这样既保证了总手数不对趋势造成影响,也同时完成了三个账号的分批建仓。

代码如下:
Vars
   Global_StringArray AID; //账号
   Global_String COD; //合约编码
   Numeric X; //循环变量
   Numeric T; //时间间隔
   Numeric P; //数值比例
   Numeric BSF; //买卖方向
   Numeric EEF; //开平方向
   Numeric VLM; //交易手数
   Numeric NOW; //当前时间
   Numeric ASKP; //卖一价
   Numeric ASKV; //卖一量
   Numeric ODFLG; //挂单判断标志
   Numeric OPFLG; //模型处理标志
   Global_Numeric ADN; //账号数量
   Global_Numeric TP; //下单总倍数
   Global_Numeric KPFLG; //委托处理标志
   Global_Numeric BKDFLG; //买开处理标志
   Global_NumericArray NP; //下单倍数
   Global_NumericArray BKID; //买开委托
   Global_NumericArray BKFLG; //买开标志
   Global_NumericArray BKDEL; //买开撤单标志
   Global_NumericArray BKSM; //买开总手数
   Global_NumericArray BKM; //买开委托手数
   Global_NumericArray BKP; //买开委托价格
   Global_NumericArray BKT; //买开委托时间
Begin
//------------------------委托获取------------------------//
If(1) //委托获取
{
   If(KPFLG == 0) //如果未开启委托处理
   {
      ADN = M_GetTradeAccountNum; //账号数量
      COD = M_GetTradeContract(); //合约编码
      BSF = M_GetTradeBuySell(); //买卖方向
      EEF = M_GetTradeEntryExit(); //开平方向
      VLM = M_GetTradeVol(); //交易手数
      For X = 0 To ADN - 1 //遍历账号
      {
         AID[X] = M_GetTradeAccount(X); //账号
         NP[X] = M_GetTradeOrderRatio(X); //下单倍数
         BKSM[X] = NP[X] * VLM; //买开总手数
         TP = TP + NP[X]; //下单总倍数
      }
      If(VLM > 0 && COD.A_IsExchangeOpen() == 1) //如果交易手数大于0,且当前状态是开盘
      {
         If(BSF == Enum_Buy && EEF == Enum_Entry) //如果是买开方向
         {
            Commentary("【" + COD + "做多:手动买开" + Text(VLM) + "手!】");
            BKDFLG = 1; //开启买开处理
         }
         KPFLG = 1; //开启委托处理
      }
   }
   If(KPFLG == 1 && COD.A_IsExchangeOpen() == 1) //如果已开启委托处理,且当前状态是开盘
   {
      OPFLG = 1; //开启模型处理
   }
}
//------------------------变量赋值------------------------//
If(OPFLG == 1) //变量赋值
{
   T = 3; //时间间隔
   P = 0.2; //数值比例
   NOW = CurrentTime(); //当前时间
   ASKP = COD.Price("Ask1"); //卖一价
   ASKV = COD.Price("AskVol1"); //卖一量
}
//------------------------成交判断------------------------//
If(OPFLG == 1) //成交判断
{
   For X = 0 To ADN - 1 //遍历账号
   {
      If(BKFLG[X] == 1) //如果有买开委托
      {
         If(F_OrderStatus(BKID[X]) == Enum_Filled) //如果买开委托成交
         {
            Commentary("【" + COD + "做多:买开委托成交!" + AID[X] + "】");
            BKFLG[X] = 0; //买开标志归0
            BKDEL[X] = 0; //买开撤单标志归0
         }
         Else If(F_OrderStatus(BKID[X]) == Enum_Canceled) //如果买开委托已撤
         {
            Commentary("【" + COD + "做多:买开委托已撤!" + AID[X] + "】");
            If(F_OrderFilledLot(BKID[X]) > 0) //如果买开委托部分成交
            {
               BKM[X] = BKM[X] - F_OrderFilledLot(BKID[X]); //买开委托手数
            }
            If(BKM[X] > 0) //如果买开委托手数大于0
            {
               BKP[X] = ASKP; //买开委托价格
               Commentary("【" + COD + "做多:买开委托追价!" + AID[X] + "】");
               BKID[X] = COD.A_SendOrder(Enum_Buy,Enum_Entry,BKM[X],BKP[X],AID[X]); //发出买开委托
               BKT[X] = NOW; //买开委托时间
            }
            BKDEL[X] = 0; //买开撤单标志归0
         }
         Else If(F_OrderStatus(BKID[X]) == Enum_Declared || F_OrderStatus(BKID[X]) == Enum_FillPart) //如果买开委托挂单
         {
            If(BKDEL[X] == 0) //如果未撤单
            {
               If(TimeDiff(BKT[X],NOW) >= T) //如果时间间隔T秒
               {
                  Commentary("【" + COD + "做多:买开委托撤单!" + AID[X] + "】");
                  COD.F_DeleteOrder(F_OrderContractNo(BKID[X]),AID[X]); //撤掉买开委托挂单
                  BKDEL[X] = 1; //已发出撤掉买开委托挂单
               }
            }
         }
      }
   }
   ODFLG = 1; //挂单判断标志初始化
   For X = 0 To ADN - 1 //遍历账号
   {
      If(BKFLG[X] == 1 || BKSM[X] > 0) //如果有买开委托,或有剩余买开手数
      {
         ODFLG = 2; //存在买开委托挂单
      }
   }
   If(ODFLG == 1) //如果没有买开委托
   {
      Commentary("【" + COD + "做多:买开委托完成!】");
      BKDFLG = 0; //买开处理标志归0
      Exit(); //退出公式
   }
}
//------------------------委托处理------------------------//
If(OPFLG == 1) //委托处理
{
   If(BKDFLG == 1) //如果已开启买开处理
   {
      For X = 0 To ADN - 1 //遍历账号
      {
         If(BKFLG[X] == 0) //如果没有买开委托
         {
            If(TP > 0) //如果已取得下单总倍数
            {
               BKM[X] = Min(Floor((NP[X] / TP) * P * ASKV),BKSM[X]); //买开委托手数
            }
            If(BKM[X] > 0) //如果买开委托手数大于0
            {
               BKP[X] = ASKP; //买开委托价格
               Commentary("【" + COD + "做多:公式买开" + Text(BKM[X]) + "手!" + AID[X] + "】");
               Commentary("【" + COD + "做多:买开委托发出!" + AID[X] + "】");
               BKID[X] = COD.A_SendOrder(Enum_Buy,Enum_Entry,BKM[X],BKP[X],AID[X]); //发出买开委托
               BKSM[X] = BKSM[X] - BKM[X]; //买开总手数自减买开处理手数
               BKT[X] = NOW; //买开委托时间
               BKFLG[X] = 1; //已发出买开委托
            }
         }
      }
   }
}
End



  模组是基金经理的模型运行管理操作页面,支持投资组合,支持“将鸡蛋放到不同的篮子里”,通过多品种、多策略、多周期的组合交易,构建最优的投资组合。

  每一个模型分配一笔资金,独立运行,具有独立的资金、头寸和风险控制。这样可以在模型的运行过程中,了解每一个模型的资金分配情况和权益变化,及时发现运行效果不理想或已经失效的模型,灵活调整投资组合,提高组合收益,降低投资风险;独立的头寸计算,也是后期投入资金不断增加,制定资金再分配计划的保障。

  模组中每个运行的模型称为单元,模组为每个单元分配独立的资金,各单元独立计算可用资金及权益变化。方便基金经理了解投资组合结构、每个模型运行情况及整体收益情况。

  模组还支持查看各分区的合计持仓、可用资金等基本信息,以及每个分区的组合资金曲线,直观的反映一段时间内,投资组合内每个模组单元和整体的资金变动情况,为优化投资组合提供依据。

前言

  wh9的模组分区囊括一只资管产品的各个模型运行单元的情况下,每个模组分区相当于一个资管产品。当需要对某一个资管产品申购/赎回时,只需输入申购/赎回总金额,软件会根据该分区内每个模组运行单元的权益占比,自动计算每个模组运行单元的出入金金额。同时,算法交易可通过函数获取出入金值并计算调仓手数,在需要调仓时进行智能分批下单,不仅能够减少滑点损失,还能最大程度的降低人工调仓出错的概率。

优势

  • 根据模组运行单元权益占比,自动计算出入金金额。
  • 调仓可使用算法交易进行智能分批下单,减少滑点损失,降低人工调仓出错概率。

案例

案例:产品申购/赎回管理

某产品A初始资金5000万,将资金分配给了10个不同的品种进行量化交易。某日客户申购该产品1000万,需要在下一个交易日的开盘阶段,将新入的1000万资金按比例分配给10个模组运行单元并进行调仓。



系统根据模组运行单元的权益占比,自动计算出了入金金额,点击下方“确认”按钮以后,对所有模组单元进行了入金调整。



交易模型通过F_GetInOutMoney函数取得模组当前单元本次出/入金值,并根据权益占比和持仓手数,计算出调仓手数并发出委托。

申购/赎回算法部分源码:

Vars
   Numeric MQT; //模组权益
   Numeric BPS; //多头持仓
   Numeric IOM; //出入金
   Global_Numeric IOMA; //记录出入金
   ... ... //省略部分源码
Begin
//------------------------变量赋值------------------------//
   If(OPFLG == 1)//变量赋值
   {
      MQT = MoneyTot;// 模组权益
      IOM = F_GetInOutMoney(); //出入金
      ... ... //省略部分源码
   }
   ... ... //省略部分源码
//------------------------委托处理------------------------//
    If(OPFLG == 1) //委托处理
    {
      If(IOM != 0 && KPCFLG == 0) //如果有出入金,且未开启加减仓处理
      {
         IOMA = IOM; //记录出入金
         KPCFLG = 1; //开启加减仓处理
      }
      If(KPCFLG == 1) //如果已开启加减仓处理
      {
         If(BKFLG == 0 && BKDFLG == 0) //如果没有买开委托和买开处理
         {
            If(SPFLG0 == 0 && SPFLG1 == 0 && SPFLG == 0 && SPDFLG == 0) //如果没有卖平委托和卖平处理
            {
               If(BPS > 0) //如果有多头持仓
               {
                  NP = MQT / BPS;
                   BKCV = IIF(IOMA > 0,Floor(IOMA / NP),Ceiling(IOMA / NP,1)); //根据入金金额计算补仓手数
                   Commentary("【模型资金:" + Text(MQT) + ",多头持仓:" + Text(BPS) + "手,单手资金:" + Text(NP) + "!】");
                   Commentary("【模型资金:" + Text(MQT) + ",多头持仓:" + Text(BPS) + "手,单手资金:" + Text(NP) + "!】");
                  If(BKCV > 0) //如果需要加仓
                  {
                     BKDV = BKCV; //买开处理手数
                     BKDFLG = 2; //开启多头加仓买开处理
                  }
                  Else If(BKCV < 0) //如果需要减仓
                  {
                     SPDV = Abs(BKCV); //卖平处理手数
                     SPDFLG = 2; //开启多头减仓卖平处理
                  }
               }
               KPCFLG = 0; //委托处理标志归0
            }
         }
      }
   }
   ... ... //省略部分源码
End


软件在开盘时对所有需要调仓的模组运行单元进行了补仓操作。



前言

  文华精选期货因子库囊括量价、动量、期限结构、持仓、基本面、BETA六大类精选因子,以期货市场全品种为标的,提供单因子筛选、多因子排名分析等功能。可借助多因子综合排名信息,筛选出能够带来更多超额收益的品种,构建最优组合。还可以对多个品种在同一时间点的强弱情况进行对比分析,建立对冲组合,实现期货横截面交易策略。

优势

  • 提供包含量价、动量、期限结构、持仓、基本面、BETA六大类精选期货因子库。
  • 可对期货全品种进行筛选,构建最优组合。
  • 多因子综合排名分析,实现期货横截面交易策略。

案例

案例一:文华精选期货因子助力品种筛选

不管是CTA策略还是日内策略,均有选择品种的需求。在传统的量价因子基础上,我们可以借助更多的风格因子,通过多因子综合排名,筛选出能够带来更多超额收益的品种构建投资组合。


因子类型 超额收益率来源
动量因子 前期价格表现较强的品种带来的风险溢价
期限结构因子 展期收益大的品种所带来的风险溢价
持仓因子 大量资金流入所带来的的风险溢价
基本面因子 供求关系变化带来的风险溢价
BETA因子 对通货膨胀敏感带来的风险溢价

1、我们先从量价因子入手,选择“沉淀资金”因子和“流动性”因子,筛选出受欢迎度高、流动性好的品种,此类品种出现趋势的概率大,也更适合大资金建仓;

2、在动量因子中,我们选择了“涨幅占比”因子,用于筛选出近期涨跌幅度更大的品种,以期待获得更高的收益率;

3、在期限结构因子中,选择“主力现货贴水率”因子,筛选出期货价格远低于现货价格的品种,更适合做多交易;

4、在持仓因子中,选择“会员持买单量增减”因子,跟随多头主力资金动向;

5、基本面因子中,选择“仓单变化率”因子,筛选出受供求关系影响大的品种,短期趋势更明显;

6、BETA因子中,选择“CPI因子”,该因子计算了CPI变化率与指数合约收益率的回归系数,可以衡量指数收益率受通货膨胀影响的大小。



根据系统筛选结果,初选出IC、焦煤、棕榈、沪镍、豆油、沪锡、橡胶、焦炭、IF、铁矿这10个备选品种,再根据每个因子的实际数值,剔除掉一些单因子表现极为不好的品种,例如IC、IF在“会员持买单量增减”因子中表现很差。



最终,根据多因子综合排名和单因子表现确认焦煤、棕榈、豆油、橡胶、焦炭、铁矿为交易品种,构建投资组合,并以多头交易为主。

案例二:期货横截面交易策略

横截面策略是一种泛套利策略,主要是指的是在同一个时间点(或者同一个时间区间),同时做多、做空多个品种,形成一个多空对冲组合,以期多空两个方向交易的盈利之和为正的一类策略。

横截面策略盈利的逻辑是基于期货价格的变动:强者恒强/弱者恒弱的假设,即期货价格具有一定惯性,趋势行情具有延续性,前期上涨幅度较大的合约,后期还能够继续上涨的概率更大。

例如:使用期货品种筛选功能,对市场所有的期货品种按照涨跌幅和资金流向进行排序:



根据综合排名结果做多前5的品种,做空后5的品种,形成一个对冲组合。



如下图,一周以后,共盈利639950元,收益率5.18%。



前言

  对于使用Excel编写交易策略的用户,wh9支持自动读取Excel表格的动态数据,可将策略最终的交易价格提取出来,转化为云端条件单的触发价格,使用云端条件单完成交易。当Excel策略的交易价格实时更新时,无需重新导入文档,可一键更新所有条件单价格,实现半自动交易。

优势

  • 将Excel中策略的交易价格转化为条件单的触发价格,实现半自动交易。
  • 交易价格更新时,无需重新导入文档,可一键更新所有条件单价格。

案例

案例:Excel接口实现半自动交易

由于Excel很难对接交易,所以我们使用Excel编写交易策略以后,往往需要根据策略的交易价格人工下单,而wh9软件提供了Excel接口,配合云端条件单功能,可代替人工下单,实现半自动交易。

首先,我们在Excel表格中新建一列,将交易策略计算出的交易价格放入这一列中。例如:策略确定沪铜2110合约价格大于68860元时,需做多10手。



其次,打开wh9软件,选择右上角“量化”—》“条件单EXCEL接口”功能,导入Excel表格并添加好条件单。




最后,当行情发生变化,策略计算出了新的交易价格时,无需重新导入表格, 可实时读取EXCEL的动态数据。



点击软件右下角“更新”按钮,即可一键更新全部云端条件单价格。



注意:1、软件中填写的标签名称必须与Excel中的标签名称保持一致,包括大小写。

2、设定条件单时需要选择“文件价格”并准确填写好单元格标识。

前言

  wh9提供了Python交易接口功能,只需简单导入文华whorder包,即可实现自动下单,省去Python客户复杂的交易接口开发工作。该接口不仅支持使用Python函数直接发出委托,还支持调用wh9的算法交易功能进行智能分批下单,提高成交效率,降低冲击成本。

优势

  • 导入文华whorder包,即可支持自动下单,无需做交易接口开发工作。
  • Python下单支持算法交易,提高成交效率,降低冲击成本。

案例

案例:Python接口实现智能分批下单

当我们已有的Python策略需要进行交易时,可利用wh9的Python接口实现自动交易,并使用算法交易功能实现智能分批下单。


Python策略代码:

import pandas as pd
df=pd.read_csv('D:/test/沪铜2110.csv')
close=df.set_index('date')
import talib
ma5 = talib.MA(close['cu2110'] , timeperiod = 5).iloc[-1] #求五日均值
ma10 = talib.MA(close['cu2110'] , timeperiod = 10).iloc[-1] #求十日均值
ma5_ref=talib.MA(close['cu2110'] , timeperiod = 5).iloc[-2]
ma10_ref = talib.MA(close['cu2110'] , timeperiod = 10).iloc[-2]


第一步:在Python系统中导入文华whorder包。

导入方法:https://www.wenhua.com.cn/guide/jksm.htm


第二步:在Python策略中,进行初始化,并加入委托语句


import pandas as pd
df=pd.read_csv('D:/test/沪铜2110.csv')
close=df.set_index('date')
import talib
ma5 = talib.MA(close['cu2110'] , timeperiod = 5).iloc[-1] #求五日均值
ma10 = talib.MA(close['cu2110'] , timeperiod = 10).iloc[-1] #求十日均值
ma5_ref=talib.MA(close['cu2110'] , timeperiod = 5).iloc[-2]
ma10_ref = talib.MA(close['cu2110'] , timeperiod = 10).iloc[-2]
#算法接管下单
import whorder
api = whorder.PyApi()
api.Init("mt9000903")
if ma5>ma10:
   api.SendOrderToAlgo(Account="1107200359",Contract="cu2110",BuyOrSell=0,EntryOrExit= 0,
    Lot=10,Price=69360, FokFakFlag=0, FormulaName="根据盘口智能分批下单")


第三步:打开wh9软件,登陆交易账号,运行Python程序,开始发送委托。




前言

  wh9提供了引用自有数据的功能,可使用自有数据管理系统对机构自有数据进行维护和管理。自有数据可通过函数引用到wh9的公式中,将自有数据与期货数据相结合,形成机构独特的量化交易策略,不仅支持绘制图表,还支持模型历史数据回测并提供测试报告。自有数据实时更新,可通过期货运行模组实现全自动交易。

优势

  • 机构自有数据可通过wh9软件实现量化交易,并支持历史数据回测。
  • 期货运行模组配合自有数据实现全自动交易。

案例

案例一:引用现货数据实现期限结构策略

套期保值是期货市场的主要功能之一,一个成熟的期货市场,套保者应该是市场的中坚力量。出现期货溢价或现货溢价是由于套保者多空不平衡导致,这种现象需要投机者的介入方能保持平衡。这就是期货市场通过将价格风险转移给投机者,而为套保者提供保险的原因,投机者理应获得一定的风险溢价。


我们可以引用现货价格到软件中,对比现货价格与期货价格的大小,当出现现货大幅溢价时买入期货合约,等待期货价格向现货价格回归以后平仓出场,赚取期货的展期收益。


我们使用“自有数据管理系统”导入沪铜现货数据,并在公式中使用GetCustomData函数将沪铜现货数据引用到策略中。



代码如下:

Vars
      //------------------------信号变量------------------------//
      NumericSeries GIP; //自有现货价格数据
      //------------------------算法变量------------------------//
      Numeric N; //下单手数
      Numeric SH; //上海合约标志
      ……//省略部分源码
Begin
      //------------------------信号发出------------------------//
      If(1) //信号发出
      {
            GIP = GetCustomData(3/*现货铜 (3)*/);
            If(GIP > Close) //如果满足多头开仓条件
            {
                  BK; //发出BK信号
            }
            If(GIP <= Close) //如果满足多头平仓条件
            {
                  SP; //发出SP信号
            }
            If(GIP < Close) //如果满足空头开仓条件
            {
                   SK; //发出SK信号
            }
            If(GIP >= Close) //如果满足空头平仓条件
            {
                   BP; //发出BP信号
            }
      }
      //------------------------处理开启------------------------//
      If(A_IsExchangeOpen() == 1) //如果是开盘状态
      {
            If(BarStatus() == 2) //如果不带入历史值
            {
                  If(RunStart() == 1) //如果已初始化成功
                  {
                        OPFLG = 1; //开启模型处理
                  }
            }
      }
             ……//省略部分源码
End
模型回测参数:
合约:沪铜主连
初始资金:100万
k线周期:日k线
回测时间:20150101~20201014
交易手数:10手
模型回测报告:



案例二:引用突发事件优化趋势跟踪策略

基本面分析是指从商品的实际供给和需求对商品价格的影响这一角度来进行分析的方法。对基本面进行分析可以帮助交易者确定交易的大方向,形成交易的信心基础。基本面信息除了包括商品的生产量、消费量、进出口量、库存量等数据以外,突发的新闻事件也是一个重要的参考数据,突发事件往往会造成商品价格短期的剧烈波动,如果模型不能及时对这些信息做出反应,模型的盈利能力就会大打折扣了。


一些机构会收集市场中大量的突发新闻事件,并评估其对期货价格的影响,当出现较大影响的新闻时,需要及时对模型的信号进行调整。


我们使用“自有数据管理系统”导入突发新闻事件数据,当数据为0时,表示没有突发事件发生;当数据为1时,表示有利于多头的突发事件发生;当数据为2时,表示有利于空头的突发事件发生。


我们在原有策略的基础上增加突发事件判断条件,当出现突发事件时,及时调整信号方向,代码如下:

Params
      Numeric ATRs(3); //几倍ATR止盈
      Numeric ATRLength(10); //ATR周期

Vars
      //------------------------信号变量------------------------//
      NumericSeries GIP; //自有突发事件数据
      Numeric ATRVal; //ATR(平均真实波幅)
      NumericSeries WAvgPrice; //K线加权均值
      NumericSeries Resistance; //阻力线
      NumericSeries Support; //支撑线
      NumericSeries MyExitPrice; //开仓BAR根据当时的ATR计算出的止盈价
      //------------------------算法变量------------------------//
      Numeric N; //下单手数
      Numeric N; //下单手数
      ……//省略部分源码
Begin
      //------------------------信号发出------------------------//
      If(1) //信号发出
      {
            GIP = GetCustomData(1/*突发事件 (1)*/);
            WAvgPrice = (High + Low + (Close * 2)) / 4;
            Resistance = (WAvgPrice * 2) - Low;
            Support = (WAvgPrice * 2) - High;
            PlotNumeric("Resistance",Resistance[1]);
            PlotNumeric("Support",Support[1]);
            ATRVal = AvgTrueRange(ATRLength);
            If(MarketPosition == 0 && High >= Resistance[1] + MinMove * PriceScale && Vol > 0)
            {
                  BK(DefaultVol,Max(Open,Resistance[1] + MinMove * PriceScale));
            }
            If(MarketPosition == 0 && Low <= Support[1] - MinMove * PriceScale && Vol> 0)
            {
                  SK(DefaultVol,Min(Open,Support[1] - MinMove * PriceScale));
            }
            If(MarketPosition == 1 && BarsSinceEntry == 0)
            {
                   MyExitPrice = EntryPrice + ATRVal * ATRs;
            }
            If(MarketPosition == -1 && BarsSinceEntry == 0)
            {
                   MyExitPrice = EntryPrice - ATRVal * ATRs;
            }
            If(MarketPosition == 1 && BarsSinceEntry > 0 && Vol > 0)
            {
                  If(Low <= Support[1] - MinMove * PriceScale)
                  {
                         MyExitPrice = EntryPrice - ATRVal * ATRs;
                  }
            }
            If(MarketPosition == -1 && BarsSinceEntry > 0 && Vol > 0)
            {
                  If(High >= Resistance[1] + MinMove * PriceScale)
                  {
                         BP(DefaultVol,Max(Open,Resistance[1] + MinMove * PriceScale));
                  }
            }
             If(GIP==1) //如果美元降息,满足反手做多条件
            {
                   BPK; //发出BPK信号
            }
            If(GIP==2) //如果美元加息,满足反手做空条件
            {
                   SPK; //发出SPK信号
            }
      }
      //------------------------处理开启------------------------//
      If(A_IsExchangeOpen() == 1) //如果是开盘状态
      {
            If(BarStatus() == 2) //如果不带入历史值
            {
             ……//省略部分源码
End

测试报告:

对比前后两个策略发现,加入了突发事件判断以后,不仅策略的盈利能力大幅提高,在回撤的控制上,也优于原有策略。

前言

  期货主连链回测是一种回测方式,也是一种换月方法,是将模型加载在主连合约上,信号根据当前主力合约进行计算显示。主力换月时,对新旧主力合约的信号方向做比较,信号方向相同,说明趋势方向相同,旧主力平仓,新主力开仓;信号方向不同,旧主力平仓,新主力重新计算开仓信号,有效降低趋势方向不同带来的换月损失。

优势

  • 换月时,新旧主力合约信号方向不同,新主力重新计算信号开仓,降低换月损失。
  • 测试报告详细记录换月成本,提供连续、准确的回测数据。

案例

案例:期货主连链回测使用方法

在编写量化模型时,我们在Setting字段下写入Trade_Chain,即可进行主连链回测。


模型示例:

Vars
   Numeric Ma5;
   Numeric Ma10;
Setting
   Trade_Chain:Auto;
Begin
   Ma5=Ma(Close,5);
   Ma10=Ma(Close,10);
   If(Cross(Ma5,Ma10))
   BPK;
   If(CrossDown(Ma5,Ma10))
   SPK;
End


我们在“量化”菜单中选择“期货主连链”回测,选择螺纹钢主连进行测试。



回测后提供策略在主力合约上连续运行的效果分析报告和资金曲线,供投资者分析策略连续交易的整体效果,便于调试交易策略,降低试错成本。




我们发现在2019年12月6日螺纹2001换月到螺纹2005时,2001合约是空头开仓信号,2005合约是多头开仓信号,换月时,系统对2001合约进行了平仓操作,并重新计算了05合约的开仓信号,规避了2005合约行情上涨的损失。



主连链回测还提供从信号计算开始时间到数据结束时间范围内,所有主力合约的独立回测报告和资金曲线。可查看到策略在每一个主力合约上的盈利效果,对策略在不同测试区间内分段调试。


前言

问题一:超长的K线数据有什么用?
  以上期所的螺纹钢合约为例,螺纹钢2009年挂牌交易至今,已经有超过10年的历史数据。前8年的历史数据囊括了2009年的急涨急跌行情、2011年的震荡行情、2015年的V字形翻转行情,这些数据为模型的回测提供了充足的数据样本和各种极端行情变化。
  我们可以使用前8年的数据进行模型的优化,然后使用最近两年的数据对模型进行最终的验证。这样即可以判断模型是否过度优化,也能检验模型是否能够适应当前的行情变化。

问题二:k线数据的准确性至关重要

  这些看似不符合正常行情变化的“异常K线”是错误数据吗?经过文华多方面求证,确认这些数据都是准确无误的,是极端行情的真实反应。
  类似的极端行情还有很多,2012年橡胶合约交易单位扩大至每手10吨,导致大量橡胶日内模型持续亏损;2013年上期所正式上线贵金属夜盘交易,导致大量贵金属策略失效;2015年股指期货大幅提高保证金,导致多家投资机构资金大幅回撤。。。   只有准确无误的历史数据才能确保策略回测的真实有效,才能全面检验各种极端行情对策略收益的影响,从而防止“黑天鹅”事件的发生。

问题三:文华为你提供的超长的、准确的k线数据
  保证数据的准确性,仅依靠计算机自动处理是远远不够的,数据在网络传输、软件处理过程中是无法避免出错的,必须由有多年数据处理经验的专业人士来进行人工校验。
  文华财经创立于1996年,是国内四家期货交易所官方授权行情转发商,具有20多年行情转发和数据处理经验。
  为了保证数据准确,我们配备了一支专业的数据处理团队,从交易所的数据源到文华数据中心,再到文华客户端,在各个环节进精准的校对和修正。

优势

  • 国内所有期货品种挂牌交易以来全部历史k线数据。
  • 国内四家期货交易所官方授权行情转发商。
  • 多层次校验,确保数据准确。

案例

案例:超长k线数据测试

使用足够多的历史数据进行测试,才能反映出一个模型的真实情况,少量的历史数据往往带有欺骗性,容易使交易者对策略进行错误的评估。

模型:金肯特纳策略


测试合约周期:铁矿15分钟


模型代码:

Params
   Numeric AvgLength(40); //三价均线参数
   Numeric AtrLength(40); //真实波幅参数
   Numeric Lots(DefaultVol); //交易手数
Vars
   NumericSeries MovAvgVal(0); //三价均线
   NumericSeries UpBand(0); //通道上轨
NumericSeries DnBand(0); //通道下轨
   NumericSeries LiquidPoint(0); //出场条件
Begin
   // 三价均线
   MovAvgVal =Ma((High + Low + Close) / 3, AvgLength);
   // 通道上轨
   UpBand = MovAvgVal + AvgTrueRange(AtrLength);
   //通道下轨
   DnBand = MovAvgVal - AvgTrueRange(AtrLength);
   // 出场条件
   LiquidPoint = MovAvgVal;
   // 画线
   PlotNumeric("movAvgVal", MovAvgVal);
   PlotNumeric("upBand", UpBand);
   PlotNumeric("DnBand", DnBand);
   // 三价均线向上,并且价格上破通道上轨,开多单
   If ( MarketPosition != 1 And MovAvgVal[1] > MovAvgVal[2] And High >= UpBand[1] ) BK(Lots, Max ( Open, UpBand[1] ) );
   // 三价均线向下,并且价格下破通道下轨,开空单
   If ( MarketPosition != -1 And MovAvgVal[1] < MovAvgVal[2] And Low <= DnBand[1] ) SK ( Lots, Min ( Open, DnBand[1] ) );
   // 持有多单时,价格下破三价均线,平多单
   If ( MarketPosition == 1 And BarsSinceEntry >= 1 And Low <= LiquidPoint[1] ) SP ( DefaultVol, Min ( Open, LiquidPoint[1] ) );
   // 持有空单时,价格上破三价均线,平空单
   If ( MarketPosition == -1 And BarsSinceEntry >= 1 And High >= LiquidPoint[1] ) BP ( DefaultVol, Max ( Open, LiquidPoint[1] ) );
End


测试1:


从16年1月1日开始测试至今,初始资金1万元,固定手数为1手

从回测报告来看,这是一个年化收益率达180%以上,最大回撤控制在40%以内,看起来还不错的策略



测试2:


将测试时间修改为从上市日起至今,则发现同样的策略竟然在15年就已经严重亏损,早就爆仓出局了。



对比分析:


回顾一下铁矿的历史数据不难发现,在14年底,铁矿有长达三个月的震荡行情,使得价格在三价均线上下反复徘徊,产生大量的连续亏损信号。事实上,在这种相对极端的行情下,很多趋势类策略都很难产生较好的收益,而我们的金肯特纳策略也恰恰无法适配从而导致爆仓。


由此可见,一个看似还不错的策略,如果没有长时间历史数据测试的支撑,在极端行情下可能会面临着很大的风险。为了避免这种情况的发生,拉长历史数据、进行样本外回测,不失为一种规避风险的方法,而这一切的基础,便是要拥有足够长时间的历史数据。

金融工程师支持:400-811-3366(工作日8:00~22:00,五一、十一、春节初三至初六16:30~20:30)
© 上海文华财经资讯股份有限公司   ICP证号:沪B2-20110035