二、套利量化编写详解

套利是一种稳定性高,但盈利率较低的交易模式。大多数情况下,套利亏损的原因并不是没有好的套利机会,而是当套利机会出现时没有抓住入场时机,出现瘸腿、价差滑点大等问题。算法交易可以根据套利合约盘口的挂单量和委托价,灵活调整委托量和委托顺序,及时追价或撤单,确保套利成功避免瘸腿,减少滑点损失从而锁定收益。

(一)套利精细化下单-控制交易滑点
案例一:套利下单精细控制

套利两腿合约的活跃程度不同,流动性较低的合约在成交时伴随着较大的滑点,甚至产生瘸腿,反噬盈利。算法交易可同时监控两腿合约的委托状态,当一腿合约交易不活跃,成交困难时,可迅速调整委托顺序和委托价格,优先委托流动性低的一腿确保其优先成交,再委托流动性高的一腿,降低瘸腿风险。

如下图,根据套利价差图表判断可套利区间,由算法交易精细化管理委托过程,根据两腿合约的活跃度设定委托先后顺序,确保双边成交,控制滑点锁定盈利。

思路解析:

/*
根据套利价差图表计算均线和标准差,以N倍标准差构建可套利区间的上轨和下轨用于做多和做空;
根据套利对两腿的活跃度确定委托先后顺序,确保双边成交,避免瘸腿。
*/

编写示例:

Data
   CODA:"m2001"; //第一腿合约A
   CODB:"m1909"; //第二腿合约B
Vars
   Numeric N; //下单手数
   Numeric X; //循环变量
   Numeric UDP; //上下轨比例
   Numeric SHA; //A平仓参数
   Numeric SHB; //B平仓参数
   Numeric NEWPA; //A最新价
   Numeric NEWPB; //B最新价
   Numeric BIDPA; //A买一价
   Numeric ASKPA; //A卖一价
   Numeric BIDPB; //B买一价
   Numeric ASKPB; //B卖一价
   Numeric BIDVB; //B买一量
   Numeric ASKVB; //B卖一量
   Numeric BSVB; //B买一量和
   Numeric ASVB; //B卖一量和
   Numeric MAA; //A平均值
   Numeric MAB; //B平均值
   Numeric SDA; //A标准差
   Numeric SDB; //B标准差
   Numeric UPLA; //A上轨
   Numeric UPLB; //B上轨
   Numeric DNLA; //A下轨
   Numeric DNLB; //B下轨
   Numeric TKNA; //A数据区长度
   Numeric TKNB; //B数据区长度
   Numeric BRPA; //A多头可用持仓
   Numeric SRPB; //B空头可用持仓
   Numeric OPFLG; //模型处理标志
   Numeric BKDFLGA; //A买开处理标志
   Numeric SPDFLGA; //A卖平处理标志
   Numeric SKDFLGB; //B卖开处理标志
   Numeric BPDFLGB; //B买平处理标志
   Var_TickData TKDA; //A数据区
   Var_TickData TKDB; //B数据区
   NumericArray TKPA; //A数据价格
   NumericArray TKPB; //B数据价格
   Global_Numeric BCFLG; //多头处理标志
   Global_Numeric BKIDA; //A买开委托
   Global_Numeric SPIDA; //A卖平委托
   Global_Numeric BKFLGA; //A买开标志
   Global_Numeric SPFLGA; //A卖平标志
   Global_Numeric SKIDB; //B卖开委托
   Global_Numeric BPIDB; //B买平委托
   Global_Numeric SKFLGB; //B卖开标志
   Global_Numeric BPFLGB; //B买平标志
Begin
//------------------------处理开启------------------------//
If(CODA.A_IsExchangeOpen() == 1) //如果A是开盘状态
{
   If(CODB.A_IsExchangeOpen() == 1) //如果B是开盘状态
   {
      OPFLG = 1; //开启模型处理
   }
}
//------------------------变量赋值------------------------//
If(OPFLG == 1) //变量赋值
{
   N = 2; //下单手数
   UDP = 1.645; //上下轨比例
   NEWPA = CODA.Price("New"); //A最新价
   NEWPB = CODB.Price("New"); //B最新价
   BIDPA = CODA.Price("Bid1"); //A买一价
   ASKPA = CODA.Price("Ask1"); //A卖一价
   BIDPB = CODB.Price("Bid1"); //B买一价
   ASKPB = CODB.Price("Ask1"); //B卖一价
   BIDVB = CODB.Price("BidVol1");//B买一量
   ASKVB = CODB.Price("AskVol1");//B卖一量
   TKDA = Def_TickData("m2001",1,20);//A数据区
   TKDB = Def_TickData("m1909",1,20);//B数据区
   BRPA = CODA.F_BuyRemainPosition(); //A多头可用持仓
   SRPB = CODB.F_SellRemainPosition(); //B空头可用持仓
   If(CODA.A_IsSHCode() == 1) //如果A是上期所合约
   {
      SHA = Enum_ExitToday; //A平仓参数
   }
   Else //如果A非上期所合约
   {
      SHA = Enum_Exit; //A平仓参数
   }
   If(CODB.A_IsSHCode() == 1) //如果B是上期所合约
   {
      SHB = Enum_ExitToday; //B平仓参数
   }
   Else //如果B非上期所合约
   {
      SHB = Enum_Exit; //B平仓参数
   }
   If(TKDA.State == 1) //如果A数据区有效
   {
      TKNA = TKDA.Num; //A数据区长度
      For X = 0 To TKNA - 1 //遍历A数据区
      {
         TKPA[X] = TKDA[X].TickPrice; //A数据价格
      }
   }
   If(TKDB.State == 1) //如果B数据区有效
   {
      TKNB = TKDB.Num; //B数据区长度
      For X = 0 To TKNB - 1 //遍历B数据区
      {
         TKPB[X] = TKDB[X].TickPrice; //B数据价格
      }
      For X = TKNB - 3 To TKNB - 1 //遍历B数据区
      {
         BSVB = BSVB + TKDB[X].BidVol1;//B买一量和
         ASVB = ASVB + TKDB[X].AskVol1;//B卖一量和
      }
   }
   MAA = AverageArray(TKPA); //A平均值
   MAB = AverageArray(TKPB); //B平均值
   SDA = StandardDevArray(TKPA,1); //A标准差
   SDB = StandardDevArray(TKPB,1); //B标准差
   UPLA = MAA + UDP * SDA;//A上轨
   DNLA = MAA - UDP * SDA;//A下轨
   UPLB = MAB + UDP * SDB;//B上轨
   DNLB = MAB - UDP * SDB;//B下轨
}
//------------------------成交判断------------------------//
If(OPFLG == 1) //成交判断
{
   If(BKFLGA == 1) //如果有A买开委托
   {
      If(F_OrderStatus(BKIDA) == Enum_Filled) //如果A买开委托成交
      {
         Commentary("【多头开仓:A买开委托成交!】");
         BCFLG = 2; //已完成多头开仓
         BKFLGA = 0; //A买开标志归0
      }
   }
   If(SKFLGB == 1) //如果有B卖开委托
   {
      If(F_OrderStatus(SKIDB) == Enum_Filled) //如果B卖开委托成交
      {
         Commentary("【多头开仓:B卖开委托成交!】");
         BKDFLGA = 1; //开启A买开处理
         SKFLGB = 0; //B卖开标志归0
      }
   }
   If(SPFLGA == 1) //如果有A卖平委托
   {
      If(F_OrderStatus(SPIDA) == Enum_Filled) //如果A卖平委托成交
      {
         Commentary("【多头平仓:A卖平委托成交!】");
         BCFLG = 0; //多头处理标志归0
         SPFLGA = 0; //A卖平标志归0
      }
   }
   If(BPFLGB == 1) //如果有B买平委托
   {
      If(F_OrderStatus(BPIDB) == Enum_Filled) //如果B买平委托成交
      {
         Commentary("【多头平仓:B买平委托成交!】");
         SPDFLGA = 1; //开启A卖平处理
         BPFLGB = 0; //B买平标志归0
      }
   }
}
//------------------------套利处理------------------------//
If(OPFLG == 1) //套利处理
{
   If(BCFLG == 0) //如果未执行多头开仓
   {
      If((NEWPA > UPLA && NEWPB > UPLB) || (NEWPA < DNLA && NEWPB < DNLB)) //如果满足多头开仓条件
      {
         If(BIDVB >= ASKVB / 3 && BSVB < ASVB * 2) //如果满足多头开仓条件
         {
            Commentary("【多头开仓:满足开仓条件!】");
            SKDFLGB = 1; //开启B卖开处理
            BCFLG = 1; //已执行多头开仓
         }
      }
   }
   Else If(BCFLG == 2) //如果已完成多头开仓
   {
      If((NEWPA > DNLA && NEWPA < UPLA) && (NEWPB > DNLB && NEWPB < UPLB)) //如果满足多头平仓条件
      {
         Commentary("【多头平仓:满足平仓条件!】");
         BPDFLGB = 1; //开启B买平处理
         BCFLG = 3; //已执行多头平仓
      }
   }
}
//------------------------委托处理------------------------//
If(OPFLG == 1) //委托处理
{
   If(BKDFLGA == 1) //如果已开启A买开处理
   {
      If(BKFLGA == 0) //如果没有A买开委托
      {
         Commentary("【多头开仓:A买开委托发出!】");
         BKIDA = CODA.A_SendOrder(Enum_Buy,Enum_Entry,N,ASKPA); //发出A买开委托
         BKFLGA = 1; //已发出A买开委托
      }
   }
   If(SKDFLGB == 1) //如果已开启B卖开处理
   {
      If(SKFLGB == 0) //如果没有B卖开委托
      {
         Commentary("【多头开仓:B卖开委托发出!】");
         SKIDB = CODB.A_SendOrder(Enum_Sell,Enum_Entry,N,BIDPB); //发出B卖开委托
         SKFLGB = 1; //已发出B卖开委托
      }
   }
   If(SPDFLGA == 1) //如果已开启A卖平处理
   {
      If(BRPA > 0) //如果有A多头可用持仓
      {
         Commentary("【多头平仓:A卖平委托发出!】");
         SPIDA = CODA.A_SendOrder(Enum_Sell,SHA,BRPA,BIDPA); //发出A卖平委托
         SPFLGA = 1; //已发出A卖平委托
      }
   }
   If(BPDFLGB == 1) //如果已开启B买平处理
   {
      If(SRPB > 0) //如果有B空头可用持仓
      {
         Commentary("【多头平仓:B买平委托发出!】");
         BPIDB = CODB.A_SendOrder(Enum_Buy,SHB,SRPB,ASKPB); //发出B买平委托
         BPFLGB = 1; //已发出B买平委托
      }
   }
}
End

编写规则:

(1)套利合约不支持基于Tick图数据的策略;
(2)以价差K线图为基础的趋势套利策略,不支持使用含有资金管理思路的函数,如:Money、LastOffSetProfit、SetDealPercent函数等。

(二)套利退场策略-妥善处理各腿持仓

很多交易者在套利交易过程中,往往更重视入场策略,通过设定不同的委托方式保证交易成功,但是任何一种委托方式,都有可能面临交易过程中价差偏移的风险,那么如何规避这种风险呢?我们不妨尝试制定一套退场策略。

在套利分批下单过程中,一旦价差偏离超过可承受滑点范围后,马上终止交易、暂停后续批次委托,并且根据实际情况,处理单边持仓:当单边持仓亏损时,马上进行平仓止损,降低瘸腿风险。当单边持仓盈利时,则对另一腿合约进行追价委托,尽快配成套利对,用单边的盈利弥补价差偏离的成本。如下图,策略运行时前台显示信号点位,由算法在后台自动执行精细化的下单方案。

思路解析:

/*
设定价差偏离可承受范围
当价差偏离超过此范围,立即终止交易,暂停委托,并对当前的持仓进行退场处理:
单边持仓亏损,立即平仓止损;
单边持仓盈利,对另一腿合约配对;
*/

编写示例:

Data
   CODA:"m2001"; //第一腿合约A
   CODB:"m1909"; //第二腿合约B
Vars
   Numeric N; //下单手数
   Numeric T; //时间间隔
   Numeric PLM; //偏离价位倍数
   Numeric SHA; //A平仓参数
   Numeric SHB; //B平仓参数
   Numeric KCP; //开仓条件价差
   Numeric PCP; //平仓条件价差
   Numeric NOW; //当前时间
   Numeric NPC; //最新价差
   Numeric NEWPA; //A最新价
   Numeric NEWPB; //B最新价
   Numeric BIDPA; //A买一价
   Numeric ASKPA; //A卖一价
   Numeric BIDPB; //B买一价
   Numeric ASKPB; //B卖一价
   Numeric ASKVA; //A卖一量
   Numeric BIDVB; //B买一量
   Numeric MINPA; //A最小变动价位
   Numeric BPLA; //A多头持仓盈亏
   Numeric SPLB; //B空头持仓盈亏
   Numeric BRPA; //A多头可用持仓
   Numeric SRPB; //B空头可用持仓
   Numeric OPFLG; //模型处理标志
   Numeric BKDFLGA; //A买开处理标志
   Numeric SPDFLGA; //A卖平处理标志
   Numeric SKDFLGB; //B卖开处理标志
   Numeric BPDFLGB; //B买平处理标志
   Global_Numeric NPCA; //记录价差
   Global_Numeric BCFLG; //多头处理标志
   Global_Numeric CDFLG; //撤单处理标志
   Global_Numeric BKIDA; //A买开委托
   Global_Numeric SPIDA; //A卖平委托
   Global_Numeric BKFLGA; //A买开标志
   Global_Numeric SPFLGA; //A卖平标志
   Global_Numeric BKDELA; //A买开撤单标志
   Global_Numeric BKSMA; //A买开委托总手数
   Global_Numeric BKMA; //A买开委托手数
   Global_Numeric SPMA; //A卖平委托手数
   Global_Numeric BKTA; //A买开委托时间
   Global_Numeric SKIDB; //B卖开委托
   Global_Numeric BPIDB; //B买平委托
   Global_Numeric SKFLGB; //B卖开标志
   Global_Numeric BPFLGB; //B买平标志
   Global_Numeric SKDELB; //B卖开撤单标志
   Global_Numeric SKSMB; //B卖开委托总手数
   Global_Numeric SKMB; //B卖开委托手数
   Global_Numeric BPMB; //B买平委托手数
   Global_Numeric SKTB; //B卖开委托时间
Begin
//------------------------处理开启------------------------//
   If(CODA.A_IsExchangeOpen() == 1) //如果A是开盘状态
   {
      If(CODB.A_IsExchangeOpen() == 1) //如果B是开盘状态
      {
         OPFLG = 1; //开启模型处理
      }
   }
//------------------------变量赋值------------------------//
   If(OPFLG == 1) //变量赋值
   {
      N = 20; //下单手数
      T = 5; //时间间隔
      PLM = 3; //偏离价位倍数
      KCP = 5; //开仓条件价差
      PCP = 10; //平仓条件价差
      NOW = CurrentTime(); //当前时间
      NEWPA = CODA.Price("New"); //A最新价
      NEWPB = CODB.Price("New"); //B最新价
      BIDPA = CODA.Price("Bid1"); //A买一价
      ASKPA = CODA.Price("Ask1"); //A卖一价
      BIDPB = CODB.Price("Bid1"); //B买一价
      ASKPB = CODB.Price("Ask1"); //B卖一价
      ASKVA = CODA.Price("AskVol1"); //A卖一量
      BIDVB = CODB.Price("BidVol1"); //B买一量
      MINPA = CODA.Price("MinPrice"); //A最小变动价位
      NPC = NEWPA - NEWPB; //最新价差
      BPLA = CODA.F_BuyProfitLoss(); //A多头持仓盈亏
      SPLB = CODB.F_SellProfitLoss(); //B空头持仓盈亏
      BRPA = CODA.F_BuyRemainPosition(); //A多头可用持仓
      SRPB = CODB.F_SellRemainPosition(); //B空头可用持仓
      If(CODA.A_IsSHCode() == 1) //如果A是上期所合约
      {
         SHA = Enum_ExitToday; //A平仓参数
      }
      Else //如果A非上期所合约
      {
         SHA = Enum_Exit; //A平仓参数
      }
      If(CODB.A_IsSHCode() == 1) //如果B是上期所合约
      {
         SHB = Enum_ExitToday; //B平仓参数
      }
      Else //如果B非上期所合约
      {
         SHB = Enum_Exit; //B平仓参数
      }
   }
//------------------------成交判断------------------------//
   If(OPFLG == 1) //成交判断
   {
      If(BKFLGA == 1) //如果有A买开委托
      {
         If(F_OrderStatus(BKIDA) == Enum_Filled) //如果A买开委托成交
         {
         Commentary("【多头开仓:A买开委托成交!】");
         If(BKDELA == 0 || BKDELA == 1) //如果非撤单处理撤单
         {
         If(BKSMA > 0) //如果有剩余A买开委托手数
         {
         BKDFLGA = 1; //开启A买开处理
         }
         }
         Else If(BKDELA == 2) //如果是撤单处理撤单
         {
         BPDFLGB = 2; //开启B买平处理
         }
         BKFLGA = 0; //A买开标志归0
         BKDELA = 0; //A买开撤单标志归0
         }
         Else If(F_OrderStatus(BKIDA) == Enum_Canceled) //如果A买开委托已撤
         {
         Commentary("【多头开仓:A买开委托已撤!】");
         If(BKDELA == 1) //如果是追价处理撤单
         {
         If(F_OrderFilledLot(BKIDA) > 0) //如果A买开委托部分成交
         {
         BKMA = BKMA - F_OrderFilledLot(BKIDA); //A买开委托手数
         }
         If(BKMA > 0) //如果A买开委托手数大于0
         {
         Commentary("【多头开仓:A买开委托追价!】");
         BKIDA = CODA.A_SendOrder(Enum_Buy,Enum_Entry,BKMA,ASKPA); //发出A买开委托
         BKTA = NOW; //A买开委托时间
         }
         }
         Else If(BKDELA == 2) //如果是撤单处理撤单
         {
         BPDFLGB = 2; //开启B买平处理
         BKFLGA = 0; //A买开标志归0
         }
         BKDELA = 0; //A买开撤单标志归0
      }
      Else If(F_OrderStatus(BKIDA) == Enum_Declared || F_OrderStatus(BKIDA) == Enum_FillPart) //如果A买开委托挂单
      {
         If(BKDELA == 0) //如果未撤单
         {
         If(CDFLG == 1 && TimeDiff(BKTA,NOW) >= T) //如果已开启追价处理,且时间间隔T秒
         {
            Commentary("【多头开仓:A买开委托撤单!】");
            CODA.F_DeleteOrder(F_OrderContractNo(BKIDA)); //撤掉A买开委托挂单
            BKDELA = 1; //已发出撤掉A买开委托挂单
         }
         Else If(CDFLG == 2) //如果已开启撤单处理
         {
            Commentary("【多头开仓:A买开委托撤单!】");
            CODA.F_DeleteOrder(F_OrderContractNo(BKIDA)); //撤掉A买开委托挂单
            BKDELA = 2; //已发出撤掉A买开委托挂单
         }
         }
      }
      }
   If(SKFLGB == 1) //如果有B卖开委托
   {
      If(F_OrderStatus(SKIDB) == Enum_Filled) //如果B卖开委托成交
      {
         Commentary("【多头开仓:B卖开委托成交!】");
            If(SKDELB == 0 || SKDELB == 1) //如果非撤单处理撤单
         {
            If(SKSMB > 0) //如果有剩余B卖开委托手数
            {
            SKDFLGB = 1; //开启B卖开处理
            }
         }
         Else If(SKDELB == 2) //如果是撤单处理撤单
         {
            SPDFLGA = 2; //开启A卖平处理
         }
         SKFLGB = 0; //B卖开标志归0
         SKDELB = 0; //B卖开撤单标志归0
      }
      Else If(F_OrderStatus(SKIDB) == Enum_Canceled) //如果B卖开委托已撤
      {
         Commentary("【多头开仓:B卖开委托已撤!】");
         If(SKDELB == 1) //如果是追价处理撤单
         {
            If(F_OrderFilledLot(SKIDB) > 0) //如果B卖开委托部分成交
            {
            SKMB = SKMB - F_OrderFilledLot(SKIDB); //B卖开委托手数
            }
            If(SKMB > 0) //如果B卖开委托手数大于0
            {
            Commentary("【多头开仓:B卖开委托追价!】");
               SKIDB = CODB.A_SendOrder(Enum_Sell,Enum_Entry,SKMB,BIDPB); //发出B卖开委托
            SKTB = NOW; //B卖开委托时间
            }
         }
         Else If(SKDELB == 2) //如果是撤单处理撤单
         {
            SPDFLGA = 2; //开启A卖平处理
            SKFLGB = 0; //B卖开标志归0
         }
         SKDELB = 0; //B卖开撤单标志归0
      }
      Else If(F_OrderStatus(SKIDB) == Enum_Declared || F_OrderStatus(SKIDB) == Enum_FillPart) //如果B卖开委托挂单
      {
         If(SKDELB == 0) //如果未撤单
         {
            If(CDFLG == 1 && TimeDiff(SKTB,NOW) >= T) //如果已开启追价处理,且时间间隔T秒
            {
            Commentary("【多头开仓:B卖开委托撤单!】");
            CODB.F_DeleteOrder(F_OrderContractNo(SKIDB)); //撤掉B卖开委托挂单
            SKDELB = 1; //已发出撤掉B卖开委托挂单
            }
            Else If(CDFLG == 2) //如果已开启撤单处理
            {
            Commentary("【多头开仓:B卖开委托撤单!】");
            CODB.F_DeleteOrder(F_OrderContractNo(SKIDB)); //撤掉B卖开委托挂单
            SKDELB = 2; //已发出撤掉B卖开委托挂单
            }
         }
      }
      }
      If(SPFLGA == 1) //如果有A卖平委托
      {
      If(F_OrderStatus(SPIDA) == Enum_Filled) //如果A卖平委托成交
         {
         Commentary("【多头平仓:A卖平委托成交!】");
         SPFLGA = 0; //A卖平标志归0
         }
      }
      If(BPFLGB == 1) //如果有B买平委托
      {
         If(F_OrderStatus(BPIDB) == Enum_Filled) //如果B买平委托成交
         {
         Commentary("【多头平仓:B买平委托成交!】");
         BPFLGB = 0; //B买平标志归0
         }
      }
   }
//------------------------套利处理------------------------//
   If(OPFLG == 1) //套利处理
   {
      If(BCFLG == 0) //如果未执行多头开仓
      {
      If(NPC <= KCP) //如果满足多头开仓条件
      {
         Commentary("【多头开仓:满足开仓条件!】");
         NPCA = NPC; //记录价差
         BKSMA = N; //A买开委托总手数
         SKSMB = N; //B卖开委托总手数
         BKDFLGA = 1; //开启A买开处理
         SKDFLGB = 1; //开启B卖开处理
         CDFLG = 0; //撤单处理标志归0
         BCFLG = 1; //已执行多头开仓
      }
      }
      Else If(BCFLG == 1) //如果已执行多头开仓
      {
         If((BKFLGA == 0 && BKSMA == 0) && (SKFLGB == 0 && SKSMB == 0)) //如果已完成多头开仓
         {
         Commentary("【多头开仓:多头开仓完成!】");
         BCFLG = 2; //已完成多头开仓
         }
         Else If(BKFLGA == 0 && BKSMA == 0) //如果A已完成多头开仓
         {
         If(Abs(NPC - NPCA) > PLM * MINPA) //如果价差偏离过大
         {
         If(BPLA > 0) //如果A多头持仓盈利
         {
         CDFLG = 1; //开启追价处理
         }
         Else If(BPLA < 0) //如果A多头持仓亏损
         {
         CDFLG = 2; //开启撤单处理
         }
         }
      }
      Else If(SKFLGB == 0 && SKSMB == 0) //如果B已完成多头开仓
      {
         If(Abs(NPC - NPCA) > PLM * MINPA) //如果价差偏离过大
         {
         If(SPLB > 0) //如果B空头持仓盈利
         {
         CDFLG = 1; //开启追价处理
         }
         Else If(SPLB < 0) //如果B空头持仓亏损
         {
         CDFLG = 2; //开启撤单处理
         }
         }
      }
   }
   If(BCFLG == 2) //如果已完成多头开仓
   {
      If(NPC >= PCP) //如果满足多头平仓条件
      {
         Commentary("【多头平仓:满足平仓条件!】");
         SPDFLGA = 1; //开启A卖平处理
         BPDFLGB = 1; //开启B买平处理
         BCFLG = 3; //已执行多头平仓
         }
      }
   }
//------------------------委托处理------------------------//
   If(OPFLG == 1) //委托处理
   {
      If(BKDFLGA == 1) //如果已开启A买开处理
      {
         If(BKFLGA == 0) //如果没有A买开委托
         {
            BKMA = Max(Min(BKSMA,ASKVA),1); //A买开委托手数
            BKSMA =             BKSMA - BKMA; //A买开委托总手数
            Commentary("【委托手数:" + Text(BKMA) + "手!】");
            Commentary("【剩余手数:" + Text(BKSMA) + "手!】");
            Commentary("【多头开仓:A买开委托发出!】");
            BKIDA = CODA.A_SendOrder(Enum_Buy,Enum_Entry,BKMA,ASKPA); //发出A买开委托
            BKTA = NOW; //A买开委托时间
            BKFLGA = 1; //已发出A买开委托
         }
      }
      If(SKDFLGB == 1) //如果已开启B卖开处理
      {
         If(SKFLGB == 0) //如果没有B卖开委托
         {
            SKMB = Max(Min(SKSMB,BIDVB),1); //B卖开委托手数
            SKSMB = SKSMB - SKMB; //B卖开委托总手数
            Commentary("【委托手数:" + Text(SKMB) + "手!】");
            Commentary("【剩余手数:" + Text(SKSMB) + "手!】");
            Commentary("【多头开仓:B卖开委托发出!】");
            SKIDB = CODB.A_SendOrder(Enum_Sell,Enum_Entry,SKMB,BIDPB); //发出B卖开委托
            SKTB = NOW; //B卖开委托时间
            SKFLGB = 1; //已发出B卖开委托
         }
      }
      If(SPDFLGA > 0) //如果已开启A卖平处理
      {
         If(SPFLGA == 0) //如果没有A卖平委托
         {
            If(BRPA > 0) //如果有A多头可用持仓
            {
            If(SPDFLGA == 1) //如果是多头平仓卖平
            {
             SPMA = BRPA; //A卖平委托手数
            }
            Else If(SPDFLGA == 2) //如果是单腿平仓卖平
            {
            SPMA = BRPA - SRPB; //A卖平委托手数
            }
            If(SPMA > 0) //如果A卖平委托手数大于0
            {
            Commentary("【多头平仓:A卖平委托发出!】");
            SPIDA = CODA.A_SendOrder(Enum_Sell,SHA,SPMA,BIDPA); //发出A卖平委托
            SPFLGA = 1; //已发出A卖平委托
            }
            }
         }
      }
      If(BPDFLGB > 0) //如果已开启B买平处理
      {
         If(BPFLGB == 0) //如果没有B买平委托
            {
            If(SRPB > 0) //如果有B空头可用持仓
            {
            If(BPDFLGB == 1) //如果是多头平仓买平
            {
            BPMB = SRPB; //B买平委托手数
               }
               Else If(BPDFLGB == 2) //如果是单腿平仓买平
            {
               BPMB = SRPB - BRPA; //B买平委托手数
            }
            If(BPMB > 0) //如果B买平委托手数大于0
            {
            Commentary("【多头平仓:B买平委托发出!】");
            BPIDB = CODB.A_SendOrder(Enum_Buy,SHB,BPMB,ASKPB); //发出B买平委托
               BPFLGB = 1; //已发出B买平委托
            }
            }
         }
      }
   }
End