老师好!
最近碰到一些代码的问题,特向各位老师请教:
有几个基于产业链的套利系统想在TBQ中用代码实现出来,TBQ的帮助中有关于套利发单的完整的代码,我基本能看懂,但里面的函数调用比较多,如何在系统中应用,始终心里没底。想向老师请教如何把自己的套利系统与TBQ“帮助”中关于套利发单的代码结合起来实现实盘应用,帮助中的具体代码在回帖中。
还有:以前在tb6中,这个策略是基于日线的,利用TBQ帮助中现成的代码直接用在tick上不知行不行?
先谢谢老师!
例如:关于焦炭与焦煤的套利系统
产业关系:炼焦利润大致等于焦炭价格 - 1.4*焦煤价格 - 其他成本
// 简称: SpreadTrader
// 名称: 套利宝
// 类别: 公式应用
// 类型: 用户应用
// 输出: Void
//------------------------------------------------------------------------
Params
String SpreadSection("SpreadTrader"); // 用于数据库存储的Section设置
String SymbolA("y2205.DCE"); // Data0商品信息,为盘口活跃品种
String SymbolB("y2209.DCE"); // Data1商品信息,为盘口不活跃品种
Bool ResetPosition(False); // 重设持仓数据
Integer InitPosition(0); // 初始持仓值
Integer SpreadUnitA(1); // Data0的价差计算单位
Integer SpreadUnitB(1); // Data1的价差计算单位
Bool SpreadLong(True); // True对价差做多,False对价差做空
Numeric EntryLine(0); // 价差开仓位置
Numeric ExitLine(100); // 价差平仓位置
Integer MaxPosition(1); // 最大持仓手数
Integer DeleteOrderSet(2); // 挂单后盘口变化点数设置(1-N),大于等于这个点数才撤单,设置太小会导致撤单次数太多。
Integer OrderOffset(0); // 挂单成交后补单的委托价格偏移点数
Vars
Global Integer i; // 函数内使用临时变量
Global String tmpStr; // 函数内使用临时变量
Global Integer tmpInteger; // 函数内使用临时变量
Global Numeric tmpNumeric; // 函数内使用临时变量
Global Tick tmpTickData; // 函数内使用临时变量
Global Order tmpOrder; // 函数内使用临时变量
Global Bool needCancelOrder; // 是否需要撤单的临时变量
Global Bool dataReady; // 检查数据是否正确的标识
Global Bool paramReady; // 检查参数是否正确的标识
Global Numeric priceTickA; // Data0的价格变动单位
Global Numeric priceTickB; // Data1的价格变动单位
Global Array<Tick> lastTickData; // 缓存的最新Tick数据
Global Array<bool> tickDataValid; // Tick数据是否有效标识
Global Numeric spreadBidPrice; // 价差的买盘价
Global Numeric spreadAskPrice; // 价差的卖盘价
Global Numeric orderPrice; // 委托单价格
Global Numeric upPrice; // 价格上限
Global Numeric dnPrice; // 价格下限
Global String curPosKey; // 根据商品信息生成的Key,使用该Key来保存持仓数据到数据库中
Global Integer curPosition(0); // 当前持仓手数,正数为多头持仓,负数为空头持仓
Global Integer curEntryStatus(0); // 当前套利下单的开仓处理状态 共有8种
// 0 - 初始状态为0时,用OnEntryStatusNone发送data1的开仓单
// 1/3/5/7 - 等待委托单到交易所:不操作
// 2 - 撤单重发data1:用OnEntryStatusSendedData1监控data1是否需要撤单重发,行情数据错误或价格偏离委托太远就撤单重发
// 4 - Data1挂单委托成交:用OnEntryStatusFilledData1确认data1开仓成功,然后发送data0的开仓单 // 5 - Data0直接委托发送中
// 6 - 是否需要撤单重发data0:用OnEntryStatusSendedData0监控发送data0的开仓单
// 8 - 更改数据库仓位状态:用OnEntryStatusFilledData0确认data0开仓成功,更改状态
// Integer RunSpreadOrderEntry:开仓交易的主函数,根据不同的开仓状态调用前面5个函数
Global Integer curExitStatus(0); // 当前套利下单的平仓处理状态
// 0 - 初始状态是0时,用 OnExitStatusNone发送data1的平仓单
// 1 - Data1挂单委托发送中,等待委托单到交易所
// 2 - Data1挂单委托成功,用OnExitStatusSendedData1判断是否需要重发
// 3 - Data1挂单委托撤单中,等待委托单到交易所
// 4 - Data1挂单委托成交:用OnExitStatusFilledData1判断data1成交后,平仓data0
// 5 - Data0直接委托发送中,等待委托单到交易所
// 6 - Data0委托发送成功,,用OnExitStatusSendedData0判断是否需要重发data0
// 7 - Data0委托撤单中,等待委托单到交易所
// 8 - Data0委托成交,用OnExitStatusFilledData0判断data0成交后,更改数据库仓位状态
// -99 - 出错状态,需人工干预
// RunSpreadOrderExit() 平仓交易的主函数,根据不同的平仓状态调用前面5个函数
Global Array<Integer> entryPairAOrderIds; // 缓存的Data0开仓OrderIds
Global Array<Integer> entryPairBOrderIds; // 缓存的Data1开仓OrderIds
Global Array<Integer> exitPairAOrderIds; // 缓存的Data0平仓OrderIds
Global Array<Integer> exitPairBOrderIds; // 缓存的Data1平仓OrderIds
Defs
bool CheckParams()
{
If(SpreadLong)//如果对价差做多为真
{
If(EntryLine >= ExitLine) Return False;//如果开仓线大于等于平仓线,checkparams为假,不能开仓
}
Else
{
If(EntryLine <= ExitLine) Return False;//如果开仓线小于等于平仓线,checkparams为假,不能开仓
}
Return True;
}
bool CheckTickData(TickRef tickData)//为真时,tick数据可用
{
/*
Commentary("symbol="+tickData.symbol); //合约名
Commentary("time="+text(tickData.datetime)); //时间
Commentary("AskPrice="+text(tickData.bidask1.askP)); //申卖价1
Commentary("AskVol="+text(tickData.bidask1.askV)); //申卖量1
Commentary("BidPrice="+text(tickData.bidask1.bidP)); //申买价1
Commentary("BidVol="+text(tickData.bidask1.bidV)); //申买量1
Commentary("Last="+text(tickData.last)); //现价
Commentary("Open="+text(tickData.open)); //开盘价
Commentary("High="+text(tickData.high)); //最高价
Commentary("Low="+text(tickData.low)); //最低价
Commentary("Volume="+text(tickData.volume)); //现手
Commentary("TotalVolume="+text(tickData.totalVolume)); //总成交
Commentary("---------------separator---------------");
*/
If(tickData.last > 0 && tickData.totalVolume > 0)//检查tick数据,如果价格和成交量都大于0,CheckTickData为真
Return True;
Else
Return False;
} //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~计算两个合约价差值~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Numeric CalcSpreadPrice(Numeric p1, Numeric p2)
{
return p1-p2;
}
//~~~~~~~~~~~~~~~~~~~~~~计算下单价格,涨跌停返回-1,价差价格不利时返回-2,正常计算返回0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
Integer CalcSendOrderPrice(Bool entry,NumericRef myPrice)
{
If((SpreadLong&&entry)||(!SpreadLong&&!entry)) // 当前允许多头开仓或空头平仓
{
if (lastTickData[0].bidask1.askP < 0.000001 || lastTickData[1].bidask1.bidP < 0.000001) return -1;//涨跌停时函数返回-1
spreadAskPrice = CalcSpreadPrice(lastTickData[0].bidask1.askP*SpreadUnitA,lastTickData[1].bidask1.bidP*SpreadUnitB);//计算价差
If(spreadAskPrice > IIF(entry,EntryLine,ExitLine)) return -2;//如果开仓时价差大于开仓线,或者非开仓时价差大于平仓线,函数返回-2
orderPrice = lastTickData[1].bidask1.bidP;//下单价格等于买一价
if (lastTickData[1].limitUp > 0.000001 && orderPrice > lastTickData[1].limitUp) return -3;//如果上一个价格涨停价不是0(未涨停)并且下单价大于前一天的涨停价函数返回-3
}
Else // 多头平仓或空头开仓
{
if (lastTickData[0].bidask1.bidP < 0.000001 || lastTickData[1].bidask1.askP < 0.000001) return -1;//涨跌停时函数返回-1
spreadBidPrice = CalcSpreadPrice(lastTickData[0].bidask1.bidP*SpreadUnitA,lastTickData[1].bidask1.askP*SpreadUnitB);//计算价差
If(spreadBidPrice < IIF(entry,EntryLine,ExitLine)) return -2;//如果开仓时价差大于开仓线,或者非开仓时价差大于平仓线,函数返回-2
orderPrice = lastTickData[1].bidask1.askP;//下单价格等于卖一价
if (lastTickData[1].limitDown > 0.000001 && orderPrice < lastTickData[1].limitDown) return -3;//如果上一个价格未涨停并且下单价小于前一天的跌停价,函数返回-3
}
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~获得已发单的发单价~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
Numeric GetSendedOrderPrice(Bool entry,Bool pairB)
{
tmpNumeric = InvalidNumeric;
tmpInteger = InvalidInteger;
If(entry)
{
if(pairB)
{
tmpInteger = entryPairBOrderIds[0];
}Else
{
tmpInteger = entryPairAOrderIds[0];
}
}Else
{
if(pairB)
{
tmpInteger = exitPairBOrderIds[0];
}Else
{
tmpInteger = exitPairAOrderIds[0];
}
}
If(tmpInteger!=InvalidInteger && A_GetOrder(tmpInteger,tmpOrder))
{
tmpNumeric = tmpOrder.price;
}
Return tmpNumeric;
}
//-------------------------------------------------------------------------
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·开仓操作处理函数~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Integer OnEntryStatusNone()
{
tmpInteger = CalcSendOrderPrice(True,orderPrice);
If(tmpInteger != 0) Return tmpInteger;//假如CalcSendOrderPrice不为0,对tmpInteger的赋值不变
ArrayClear(entryPairBOrderIds);//一维数组内全部清空
If(!Data1.A_SendOrderEx(IIF(SpreadLong,Enum_Sell,Enum_Buy),Enum_Entry,1,orderPrice,entryPairBOrderIds)) Return -4;//开仓挂单没有成功,函数等于-4
curEntryStatus = 1;
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~以下对data1的委托单进行处理,如果价格偏移过大,判断是否对自己有利,有利则重新定义交易价格,不利则撤单~~~~~~~~~~~~~~~~~
Integer OnEntryStatusSendedData1()
{
needCancelOrder = False;
If(SpreadLong)//对差价做多为真
{
If (lastTickData[0].bidask1.askP > 0.000001 && lastTickData[1].bidask1.bidP > 0.000001)//假如当前没有涨停并且前一天没有涨停
{
orderPrice = (SpreadUnitA*lastTickData[0].bidask1.askP-EntryLine)/SpreadUnitB;//开仓价格等于A价差的计算单位乘以买一价的积减去开仓线,再除以B价差的计算单位
if(lastTickData[1].bidask1.bidP > orderPrice) // 价格有利,则用叫买价发单
orderPrice = lastTickData[1].bidask1.bidP;
}Else
{
needCancelOrder = True;//如果价格偏移且对成交不利,撤单
}
}
Else//如果对差价做多为假(做空为真)
{
If (lastTickData[0].bidask1.bidP > 0.000001 && lastTickData[1].bidask1.askP > 0.000001)//当前价格没有跌停且上一个价格没有涨停
{
orderPrice = (SpreadUnitA*lastTickData[0].bidask1.bidP-EntryLine)/SpreadUnitB;
if(lastTickData[1].bidask1.askP < orderPrice) // 价格有利,则用叫卖价发单
orderPrice = lastTickData[1].bidask1.askP;
}Else
{
needCancelOrder = True;
}
}
If(!needCancelOrder)//如果不需要撤单
{
tmpNumeric = GetSendedOrderPrice(true,true);
upPrice = tmpNumeric+priceTickB*DeleteOrderSet;
dnPrice = tmpNumeric-priceTickB*DeleteOrderSet;
if (orderPrice > dnPrice && orderPrice < upPrice)//如果价格偏移在设定的范围之内,则不需要撤单重发
needCancelOrder = False; // 不需要撤单重发
Else
needCancelOrder = True;
}
If(needCancelOrder)//如果需要撤单
{
For i=0 To GetArraySize(entryPairBOrderIds)-1
{
Data1.A_DeleteOrderEx(entryPairBOrderIds[i]);
}
curEntryStatus = 3;
}
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~判断data1的开仓状态~~~~~~~~~~~~~~~~~~~~~~~~
Integer OnEntryStatusFilledData1()
{
If(SpreadLong)
{
orderPrice = lastTickData[0].limitUp;//指令价位涨停价
If(lastTickData[0].bidask1.askP > 0.000001)//如果当前没有涨停,指令价为指令价与卖一价+设定点位的较小值
{
orderPrice = Min(orderPrice,lastTickData[0].bidask1.askP+priceTickA*OrderOffset);
}
}Else
{
orderPrice = lastTickData[0].limitDown;//指令价位跌停价
If(lastTickData[0].bidask1.bidP > 0.000001)//如果没有跌停,指令价为指令价与买一价+设定点位的较大值
{
orderPrice = Max(orderPrice,lastTickData[0].bidask1.bidP+priceTickA*OrderOffset);
}
}
ArrayClear(entryPairAOrderIds);
If(!Data0.A_SendOrderEx(IIF(SpreadLong,Enum_Buy,Enum_Sell),Enum_Entry,1,orderPrice,entryPairAOrderIds)) Return -1;
curEntryStatus = 5;
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~监控data0的开仓挂单~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Integer OnEntryStatusSendedData0()
{
If(SpreadLong)//设定做多的下单价格
{
orderPrice = lastTickData[0].bidask1.askP+priceTickA*OrderOffset;
}Else//设定做空的下单价格
{
orderPrice = lastTickData[0].bidask1.bidP-priceTickA*OrderOffset;
}
tmpNumeric = GetSendedOrderPrice(true,False);
if (orderPrice > tmpNumeric+0.000001 || orderPrice <= tmpNumeric-0.000001) // 新的委托价格和原委托价格不同即撤单重发
{
For i=0 To GetArraySize(entryPairAOrderIds)-1
{
Data0.A_DeleteOrderEx(entryPairAOrderIds[i]);
}
curEntryStatus = 7;
}
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~~data0的开仓成交状态~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Integer OnEntryStatusFilledData0()
{
curEntryStatus = 0;
curPosition = curPosition + 1;
SetTBProfileString(SpreadSection,curPosKey,Text(curPosition));
Return 0;
}
Integer RunSpreadOrderEntry()//委托A或委托B已开仓成交
{
if (curPosition < MaxPosition && curEntryStatus != -99) // 还可以开仓
{
If(curEntryStatus == 0)
{
OnEntryStatusNone();
}Else if(curEntryStatus == 1 || curEntryStatus == 5)
{
// 等待委托单发送到交易所
}Else if(curEntryStatus == 2)
{
OnEntryStatusSendedData1();
}Else if(curEntryStatus == 3 || curEntryStatus == 7)
{
// 等待撤单发送到交易所
}Else if(curEntryStatus == 4)
{
OnEntryStatusFilledData1();
}Else if(curEntryStatus == 6)
{
OnEntryStatusSendedData0();
}Else if(curEntryStatus == 8)
{
OnEntryStatusFilledData0();
}
}
spreadAskPrice = CalcSpreadPrice(lastTickData[0].bidask1.askP*SpreadUnitA,lastTickData[1].bidask1.bidP*SpreadUnitB);
spreadBidPrice = CalcSpreadPrice(lastTickData[0].bidask1.bidP*SpreadUnitA,lastTickData[1].bidask1.askP*SpreadUnitB);
Commentary("SpreadPrice="+Text(spreadAskPrice));
Commentary("SpreadBid="+Text(spreadBidPrice));
FileAppend("D:\\SpreadTrader.tbf","CurPosition="+Text(curPosition));
Return 0;
}
//-------------------------------------------------------------------------
// 以下为平仓操作处理函数
Integer OnExitStatusNone()
{
tmpInteger = CalcSendOrderPrice(False,orderPrice);
If(tmpInteger != 0) Return tmpInteger;
ArrayClear(exitPairBOrderIds);
If(!Data1.A_SendOrderEx(IIF(SpreadLong,Enum_Buy,Enum_Sell),Enum_Exit,1,orderPrice,exitPairBOrderIds)) Return -4;
curExitStatus = 1;
Return 0;
}
Integer OnExitStatusSendedData1()
{
needCancelOrder = False;
If(SpreadLong)
{
If (lastTickData[0].bidask1.bidP > 0.000001 && lastTickData[1].bidask1.askP > 0.000001)
{
orderPrice = (SpreadUnitA*lastTickData[0].bidask1.bidP-ExitLine)/SpreadUnitB;
if(lastTickData[1].bidask1.askP < orderPrice) // 价格有利,则用叫卖价发单
orderPrice = lastTickData[1].bidask1.askP;
}Else
{
needCancelOrder = True;
}
}Else
{
If (lastTickData[0].bidask1.askP > 0.000001 && lastTickData[1].bidask1.bidP > 0.000001)
{
orderPrice = (SpreadUnitA*lastTickData[0].bidask1.askP-ExitLine)/SpreadUnitB;
if(lastTickData[1].bidask1.bidP > orderPrice) // 价格有利,则用叫买价发单
orderPrice = lastTickData[1].bidask1.bidP;
}Else
{
needCancelOrder = True;
}
}
If(!needCancelOrder)
{
tmpNumeric = GetSendedOrderPrice(False,true);
upPrice = tmpNumeric+priceTickB*DeleteOrderSet;
dnPrice = tmpNumeric-priceTickB*DeleteOrderSet;
if (orderPrice > dnPrice && orderPrice < upPrice)
needCancelOrder = False; // 不需要撤单重发
Else
needCancelOrder = True;
}
If(needCancelOrder)
{
For i=0 To GetArraySize(exitPairBOrderIds)-1
{
Data1.A_DeleteOrderEx(exitPairBOrderIds[i]);
}
curExitStatus = 3;
}
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~标记data1发送平仓单~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Integer OnExitStatusFilledData1()
{
If(SpreadLong)
{
orderPrice = lastTickData[0].limitDown;
If(lastTickData[0].bidask1.bidP > 0.000001)
{
orderPrice = Max(orderPrice,lastTickData[0].bidask1.bidP-priceTickA*OrderOffset);
}
}Else
{
orderPrice = lastTickData[0].limitUp;
If(lastTickData[0].bidask1.askP > 0.000001)
{
orderPrice = Min(orderPrice,lastTickData[0].bidask1.askP-priceTickA*OrderOffset);
}
}
ArrayClear(exitPairAOrderIds);
If(!Data0.A_SendOrderEx(IIF(SpreadLong,Enum_Sell,Enum_Buy),Enum_Exit,1,orderPrice,exitPairAOrderIds)) Return -1;
curExitStatus = 5;
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~标记data0发送平仓单~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Integer OnExitStatusSendedData0()
{
If(SpreadLong)
{
orderPrice = lastTickData[0].bidask1.bidP-priceTickA*OrderOffset;
}Else
{
orderPrice = lastTickData[0].bidask1.askP+priceTickA*OrderOffset;
}
tmpNumeric = GetSendedOrderPrice(False,False);
if (orderPrice > tmpNumeric+0.000001 || orderPrice < tmpNumeric-0.000001) // 新的委托价格和原委托价格不同即撤单重发
{
For i=0 To GetArraySize(exitPairAOrderIds)-1
{
Data0.A_DeleteOrderEx(exitPairAOrderIds[i]);
}
curExitStatus = 7;
}
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~标记data0平仓单成交~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Integer OnExitStatusFilledData0()
{
curExitStatus = 0;
curPosition = curPosition - 1;
SetTBProfileString(SpreadSection,curPosKey,Text(curPosition));
Return 0;
}
//~~~~~~~~~~~~~~~~~~~~标记委托A或委托B平仓单成交~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Integer RunSpreadOrderExit()//委托A或委托B已平仓成交
{
if (curPosition > 0 && curExitStatus != -99) // 还可以开仓
{
If(curExitStatus == 0)
{
OnExitStatusNone();
}Else if(curExitStatus == 1 || curExitStatus == 5)
{
// 等待委托单发送到交易所
}Else if(curExitStatus == 2)
{
OnExitStatusSendedData1();
}Else if(curExitStatus == 3 || curExitStatus == 7)
{
// 等待撤单发送到交易所
}Else if(curExitStatus == 4)
{
OnExitStatusFilledData1();
}Else if(curExitStatus == 6)
{
OnExitStatusSendedData0();
}Else if(curExitStatus == 8)
{
OnExitStatusFilledData0();
}
}
Return 0;
}
//-------------------------------------------------------------------------
// 以下为委托状态变化处理函数
Bool IsMyOrder(OrderRef ord,ArrayRef<Integer> orderIds)//检查委托单是否为这个套利交易的委托单
{
for i=0 To GetArraySize(orderIds)-1
{
If(ord.orderId==orderIds[i])
Return True;
}
Return False;
}
Integer OnNotifySending(OrderRef ord,bool pairB)//true为B委托单发送中,False为A委托单发送中
{
tmpInteger = IIF(pairB,1,5); // 默认为发送中
If(ord.status==Enum_Declared) // 已报
{
If(ord.exchOrderId!="")
{
tmpInteger = IIF(pairB,2,6);
}
}else If(ord.status==Enum_Deleted || ord.status==Enum_Canceled) // 废单或交易所自动撤单
{
tmpInteger = IIF(pairB,0,4); // 修改为初始状态或Pair B已成交状态
}Else If(ord.status==Enum_Filled) // 跳过已报状态直接收到成交状态
{
tmpInteger = IIF(pairB,4,8); // 修改为已成交状态
}Else If(ord.status==Enum_Declare)
{
// 等待发送成功
}Else
{
tmpInteger = -99; // 错误的状态
}
Return tmpInteger;
}
Integer OnNotifySended(OrderRef ord,bool pairB)//true为B委托单发送成功,false为A委托单发送成功
{
tmpInteger = IIF(pairB,2,6); // 默认为已报
If(ord.status==Enum_Filled) // 已成交
{
tmpInteger = IIF(pairB,4,8); // 修改为已成交状态
}Else If(ord.status==Enum_Canceled) // 已撤单
{
tmpInteger = IIF(pairB,0,4); // 修改为初始状态或Pair B已成交状态
}Else If(ord.status==Enum_FillPart) // 部分成交
{
// 等待全部成交
}Else If(ord.status!=Enum_Declared)
{
tmpInteger = -99; // 错误的状态
}
Return tmpInteger;
}
Integer OnNotifyCanceling(OrderRef ord,bool pairB)//true为B委托单撤单中,FALSE为A委托单撤单中
{
tmpInteger = IIF(pairB,3,7); // 默认为撤单中
If(ord.status==Enum_Canceled) // 已撤单
{
tmpInteger = IIF(pairB,0,4); // 修改为初始状态或Pair B已成交状态
}Else If(ord.status==Enum_Filled) // 撤单不及时,已经成交
{
tmpInteger = IIF(pairB,4,8); // 修改为已成交状态
}Else If(ord.status==Enum_Declared) // 已报
{
// 等待撤单成功
}Else If(ord.status!=Enum_Canceling)
{
tmpInteger = -99; // 错误的状态
}
Return tmpInteger;
}
Integer OnNotifyOrder(OrderRef ord,Integer myStatus)//开仓和平仓主函数的主函数
{
If(myStatus==1) // 委托B发送中
{
myStatus = OnNotifySending(ord,True);
}else If(myStatus==2) // 委托B发送成功
{
myStatus = OnNotifySended(ord,True);
}else If(myStatus==3) // 委托B撤单中
{
myStatus = OnNotifyCanceling(ord,True);
}else If(myStatus==5) // 委托A发送中
{
myStatus = OnNotifySending(ord,False);
}else If(myStatus==6) // 委托A发送成功
{
myStatus = OnNotifySended(ord,False);
}Else If(myStatus==7) // 委托A撤单中
{
myStatus = OnNotifyCanceling(ord,False);
}
If(myStatus==4||myStatus==8) // 委托A或委托B已经成交
{
RunSpreadOrderEntry();
RunSpreadOrderExit();
}
Return myStatus;
}
Events
OnInit()
{
SubscribeBar(data0.symbol,"tick");//订阅两个品种的tick行情
SubscribeBar(data1.symbol,"tick");//订阅两个品种的tick行情
A_SubscribeTradeByCreateId(Enum_Trade_Source_ALL);//根据操作源ID订阅委托
paramReady = CheckParams();
}
//在所有的数据源准备完成后调用,应用在数据源的设置等操作
OnReady()
{
curPosKey = data0.symbol+"-"+data1.symbol+IIFString(SpreadLong,".Long",".Short")+"Pos";
If(ResetPosition) // 重置持仓数据
{
curPosition = InitPosition;
SetTBProfileString(SpreadSection,curPosKey,Text(curPosition));
}Else // 从数据库中读取持仓数据
{
tmpStr = GetTBProfileString(SpreadSection,curPosKey);
If(tmpStr!=InvalidString && tmpStr !="")
curPosition = Value(tmpStr);
}
priceTickA = Data0.MinMove*Data0.PriceScale;
priceTickB = Data1.MinMove*Data1.PriceScale;
}
//在新bar的第一次执行之前调用一次,参数为新bar的图层数组
OnBarOpen(ArrayRef<Integer> indexs)
{
}
OnBar(ArrayRef<Integer> indexs)
{
For i=0 To GetArraySize(indexs)-1
{
Data[indexs[i]].GetTick(tmpTickData);
if(CheckTickData(tmpTickData)) //检查tick数据
{
tickDataValid[indexs[i]] = True;//tick数据有效
lastTickData[indexs[i]] = tmpTickData;
}
}
dataReady = True;
For i=0 To DataCount-1
{
If(!tickDataValid[indexs[i]])
{
dataReady = False;
Break;
}
}
If(paramReady && dataReady)
{
RunSpreadOrderEntry();
RunSpreadOrderExit();
}
}
//持仓更新事件函数,参数pos表示更新的持仓结构体
OnPosition(PositionRef pos)
{
}
//委托更新事件函数,参数ord表示更新的委托结构体
OnOrder(OrderRef ord)
{
If(IsMyOrder(ord,entryPairAOrderIds)||IsMyOrder(ord,entryPairBOrderIds)) // 判断是否为该系统发出的开仓单
{
curEntryStatus = OnNotifyOrder(ord, curEntryStatus);
}else if(IsMyOrder(ord,exitPairAOrderIds)||IsMyOrder(ord,exitPairBOrderIds)) // 判断是否为该系统发出的平仓单
{
curExitStatus = OnNotifyOrder(ord, curExitStatus);
}
}
//成交更新事件函数,参数ordFill表示更新的成交结构体
OnFill(FillRef ordFill)
{
}
//定时器更新事件函数,参数id表示定时器的编号,millsecs表示定时间的间隔毫秒值
OnTimer(Integer id,Integer intervalMillsecs)
{
}
//------------------------------------------------------------------------
// 编译版本: 2020/01/06 130422
// 版权所有 nopain
// 更改声明 TradeBlazer Software保留对TradeBlazer平台
// 每一版本的TradeBlazer公式修改和重写的权利
//------------------------------------------------------------------------