三、 期货量化编写举例
(一)趋势策略+算法下单

很多成功的量化投资者每年算一笔账,在滑点上的损失比交的手续费还要多。同时趋势策略中固有的信号处理机制难以满足用户日益丰满的思路,越来越多的投资者将研究重心转移到用算法模型对信号和下单的精细化控制方向上。

算法交易可以接管策略信号和委托过程,我们可以完全抛开系统默认的信号处理机制,重新制定一套适合当前策略的信号处理方式,对下单过程精细化管理。

1、案例一:策略模型+信号控制算法

指令价模型可以定位到更好的入场点,但也会出现信号消失的问题。太晚入场,会失去好的入场时机,导致策略收益下降;过早入场,可能会频繁出现信号消失,导致恢复持仓成本增加。我们需要找到一个平衡点,使信号消失成本更低同时还能获得更多的收益。

如下图,我们用算法交易接管趋势策略的信号,结合模型信号消失的特点自定义一套信号执行方案:出信号立即下单,当信号消失达到一定时长后再恢复持仓,算法交易动态统计给出每根K线上的信号消失时间和消失频率,我们通过调整信号的确认时间便可以达到降低信号消失成本同时提高整体收益的效果。

思路解析:
/*
趋势策略均线交叉开平仓,出现信号立刻下单,信号消失且连续T秒没有再次出现则恢复持仓
*/

编写示例:
Vars
   Numeric N; //下单手数
   Numeric T; //时间间隔
   Numeric SH; //平仓参数
   Numeric MA3; //3周期均线
   Numeric MA5; //5周期均线
   Numeric MA10; //10周期均线
   Numeric KCP; //K线位置
   Numeric SIGID; //指令序号
   Numeric NOW; //当前时间
   Numeric BIDP; //买一价
   Numeric ASKP; //卖一价
   Numeric BRP; //多头可用持仓
   Numeric SRP; //空头可用持仓
   Numeric OPFLG; //模型处理标志
   Numeric BKDFLG; //买开处理标志
   Numeric SKDFLG; //卖开处理标志
   Numeric BPDFLG; //买平处理标志
   Numeric SPDFLG; //卖平处理标志
   Global_Numeric SIGIDA; //记录指令序号
   Global_Numeric KCPA; //记录K线位置
   Global_Numeric KCPB; //记录K线位置
   Global_Numeric SIGF; //信号类型标志
   Global_Numeric SIGCF; //当前信号类型
   Global_Numeric SIGCN; //信号出现次数
   Global_Numeric SIGXN; //信号消失次数
   Global_Numeric SIGXT; //信号消失时间
   Global_Numeric SIGFLG; //信号处理标志
   Global_Numeric BKID; //买开委托
   Global_Numeric SKID; //卖开委托
   Global_Numeric BPID; //买平委托
   Global_Numeric SPID; //卖平委托
   Global_Numeric BKFLG; //买开标志
   Global_Numeric SKFLG; //卖开标志
   Global_Numeric BPFLG; //买平标志
   Global_Numeric SPFLG; //卖平标志
   Global_Numeric BKM; //买开委托手数
   Global_Numeric SKM; //卖开委托手数
   Global_Numeric BPM; //买平委托手数
   Global_Numeric SPM; //卖平委托手数
Setting
   SignalNoTrading:1; //出信号不下单
Begin
//------------------------处理开启------------------------//
   If(A_IsExchangeOpen() == 1) //如果是开盘状态
   {
         If(RunStart() == 1) //如果已初始化成功
         {
            OPFLG = 1; //开启模型处理
         }
   }
//------------------------变量赋值------------------------//
   If(OPFLG == 1) //变量赋值
   {
      N = 2; //下单手数
      T = 10; //时间间隔
      KCP = CurrentBar; //K线位置
      NOW = CurrentTime(); //当前时间
      BIDP = Price("Bid1"); //买一价
      ASKP = Price("Ask1"); //卖一价
      BRP = F_BuyRemainPosition(); //多头可用持仓
      SRP = F_SellRemainPosition(); //空头可用持仓
      If(A_IsSHCode() == 1) //如果是上期所合约
      {
         SH = Enum_ExitToday; //平仓参数
      }
      Else //如果非上期所合约
      {
         SH = Enum_Exit; //平仓参数
      }
   }
//------------------------信号发出------------------------//
   If(1) //信号发出
   {
      MA3 = Ma(Close,3); //3周期均线
      MA5 = Ma(Close,5); //5周期均线
      MA10 = Ma(Close,10); //10周期均线
      PlotLine("Ma3",Ma3); //3周期均线
      PlotLine("Ma5",Ma5); //5周期均线
      PlotLine("Ma10",Ma10); //10周期均线
      If(Cross(Ma5,Ma10) == 1 && MarketPosition == 0) //如果满足做多条件
      {
         BK; //发出做多信号
      }
      Else If(CrossDown(Ma3,Ma10) == 1 && MarketPosition == 1) //如果满足平多条件
      {
         SP; //发出平多信号
      }
      Else If(CrossDown(Ma5,Ma10) == 1 && MarketPosition == 0) //如果满足做空条件
      {
         SK; //发出做空信号
      }
      Else If(Cross(Ma3,Ma10) == 1 && MarketPosition == -1) //如果满足平空条件
      {
         BP; //发出平空信号
      }
   }
//------------------------信号处理------------------------//
   If(OPFLG == 1) //信号处理
   {
      If(KCP != KCPB) //如果是新K线
      {
         If(SIGCN > 0) //如果上根K线出现信号
         {
            Commentary("【上根K线信号出现次数:" + Text(SIGCN) + "次!】");
            Commentary("【上根K线信号消失次数:" + Text(SIGXN) + "次!】");
            If(SIGFLG == 2) //如果信号已消失
            {
            Commentary("【距离信号消失时间:" + Text(TimeDiff(SIGXT,NOW)) + "秒!】");
            }
         }
         SIGCN = 0; //信号出现次数
         SIGXN = 0; //信号消失次数
         KCPB = KCP; //记录K线位置
      }
      SIGID = F_CurrentSigIndex; //指令序号
      If(SIGID != 0) //如果当笔行情发出指令
      {
         If(SIGID != SIGIDA || KCP != KCPA) //如果当前信号是未处理过的新信号
         {
            SIGIDA = SIGID; //记录指令序号
            KCPA = KCP; //记录K线位置
             If(F_CurrentSig == Sig_BK) //如果信号类型为BK
            {
            Commentary("【BK信号!】");
            BKDFLG = 1; //开启BK信号买开处理
            SIGF = 1; //BK信号已发出
            }
            Else If(F_CurrentSig == Sig_SP) //如果信号类型为SP
            {
            Commentary("【SP信号!】");
            SPDFLG = 1; //开启SP信号卖平处理
            SIGF = 2; //SP信号已发出
            }
            Else If(F_CurrentSig == Sig_SK) //如果信号类型为SK
            {
            Commentary("【SK信号!】");
            SKDFLG = 1; //开启SK信号卖开处理
            SIGF = 3; //SK信号已发出
            }
            Else If(F_CurrentSig == Sig_BP) //如果信号类型为BP
            {
            Commentary("【BP信号!】");
            BPDFLG = 1; //开启BP信号买平处理
            SIGF = 4; //BP信号已发出
            }
            SIGCN = SIGCN + 1; //信号出现次数
         }
      }
      If(KCP == KCPA) //如果是当根K线
      {
         If(SIGCF != SIGF) //如果是新的信号类型
         {
            SIGFLG = 1; //信号已发出
            SIGCF = SIGF; //当前信号类型
         }
         If(SIGFLG == 1) //如果信号已出现
         {
            If(F_CurrentSig == 0) //如果信号消失
            {
            If(SIGCF == 1) //如果当前是BK信号
            {
            Commentary("【BK信号消失!】");
            }
            Else If(SIGCF == 2) //如果当前是SP信号
            {
            Commentary("【SP信号消失!】");
            }
            Else If(SIGCF == 3) //如果当前是SK信号
            {
            Commentary("【SK信号消失!】");
            }
            Else If(SIGCF == 4) //如果当前是BP信号
            {
            Commentary("【BP信号消失!】");
            }
            SIGIDA = 0; //记录指令序号归0
            SIGXT = NOW; //信号消失时间
            SIGXN = SIGXN + 1; //信号消失次数
            SIGFLG = 2; //信号已消失
            }
         }
      }
      If(SIGFLG == 2) //如果信号已消失
      {
         If(TimeDiff(SIGXT,NOW) <= T) //如果时间间隔T秒内
         {
            If(F_CurrentSig > 0) //如果信号出现
            {
            If(SIGCF == 1) //如果当前是BK信号
            {
            Commentary("【BK信号重现!】");
            }
            Else If(SIGCF == 2) //如果当前是SP信号
            {
            Commentary("【SP信号重现!】");
            }
            Else If(SIGCF == 3) //如果当前是SK信号
            {
            Commentary("【SK信号重现!】");
            }
            Else If(SIGCF == 4) //如果当前是BP信号
            {
            Commentary("【BP信号重现!】");
            }
            Commentary("【距离信号消失时间:" + Text(TimeDiff(SIGXT,NOW)) + "秒!】");
            SIGFLG = 1; //信号已发出
            }
         }
         Else If(TimeDiff(SIGXT,NOW) > T) //如果时间间隔T秒
         {
            If(SIGCF == 1) //如果当前是BK信号
            {
            Commentary("【BK信号取消!】");
            SPDFLG = 2; //开启BK信号卖平处理
            }
            Else If(SIGCF == 2) //如果当前是SP信号
            {
            Commentary("【SP信号取消!】");
            BKDFLG = 2; //开启SP信号买开处理
            }
            Else If(SIGCF == 3) //如果当前是SK信号
            {
            Commentary("【SK信号取消!】");
            BPDFLG = 2; //开启SK信号买平处理
            }
            Else If(SIGCF == 4) //如果当前是BP信号
            {
            Commentary("【BP信号取消!】");
            SKDFLG = 2; //开启BP信号卖开处理
            }
            Commentary("【距离信号消失时间:" + Text(TimeDiff(SIGXT,NOW)) + "秒!】");
            SIGFLG = 0; //信号已取消
         }
      }
   }
//------------------------成交判断------------------------//
   If(OPFLG == 1) //成交判断
   {
      If(BKFLG > 0) //如果有买开委托
      {
         If(F_OrderStatus(BKID) == Enum_Filled) //如果买开委托成交
         {
            If(BKFLG == 1) //如果是BK信号买开委托
            {
            Commentary("【BK信号:买开委托成交!】");
            }
            Else If(BKFLG == 2) //如果是SP信号买开委托
            {
            Commentary("【SP信号:买开委托成交!】");
            }
            BKFLG = 0; //买开标志归0
         }
      }
      If(SPFLG > 0) //如果有卖平委托
      {
         If(F_OrderStatus(SPID) == Enum_Filled) //如果卖平委托成交
         {
            If(SPFLG == 1) //如果是SP信号卖平委托
            {
            Commentary("【SP信号:卖平委托成交!】");
            }
            Else If(SPFLG == 2) //如果是BK信号卖平委托
            {
            Commentary("【BK信号:卖平委托成交!】");
            }
            SPFLG = 0; //卖平标志归0
         }
      }
      If(SKFLG > 0) //如果有卖开委托
      {
         If(F_OrderStatus(SKID) == Enum_Filled) //如果卖开委托成交
         {
            If(SKFLG == 1) //如果是SK信号卖开委托
            {
            Commentary("【SK信号:卖开委托成交!】");
            }
            Else If(SKFLG == 2) //如果是BP信号卖开委托
            {
            Commentary("【BP信号:卖开委托成交!】");
            }
            SKFLG = 0; //卖开标志归0
         }
      }
      If(BPFLG > 0) //如果有买平委托
      {
         If(F_OrderStatus(BPID) == Enum_Filled) //如果买平委托成交
         {
            If(BPFLG == 1) //如果是BP信号买平委托
            {
            Commentary("【BP信号:买平委托成交!】");
            }
            Else If(BPFLG == 2) //如果是SK信号买平委托
            {
            Commentary("【SK信号:买平委托成交!】");
            }
            BPFLG = 0; //买平标志归0
         }
      }
   }
//------------------------委托处理------------------------//
   If(OPFLG == 1) //委托处理
   {
      If(BKDFLG > 0) //如果已开启买开处理
      {
         If(BKFLG == 0) //如果没有买开委托
         {
            BKM = N - BRP; //买开委托手数
            If(BKM > 0) //如果买开委托手数大于0
            {
            If(BKDFLG == 1) //如果是BK信号买开
            {
            Commentary("【BK信号:买开委托发出!】");
            }
            Else If(BKDFLG == 2) //如果是SP信号买开
            {
            Commentary("【SP信号:买开委托发出!】");
            }
            BKID = A_SendOrder(Enum_Buy,Enum_Entry,BKM,ASKP); //发出买开委托
            BKFLG = BKDFLG; //已发出买开委托
            }
         }
      }
      If(SPDFLG > 0) //如果已开启卖平处理
      {
         If(SPFLG == 0) //如果没有卖平委托
         {
            If(BRP > 0) //如果有多头可用持仓
            {
            SPM = BRP; //卖平委托手数
            If(SPDFLG == 1) //如果是SP信号卖平
            {
            Commentary("【SP信号:卖平委托发出!】");
            }
            Else If(SPDFLG == 2) //如果是BK信号卖平
            {
            Commentary("【BK信号:卖平委托发出!】");
            }
            SPID = A_SendOrder(Enum_Sell,SH,SPM,BIDP); //发出卖平委托
            SPFLG = SPDFLG; //已发出卖平委托
            }
         }
      }
      If(SKDFLG > 0) //如果已开启卖开处理
      {
         If(SKFLG == 0) //如果没有卖开委托
         {
            SKM = N - SRP; //卖开委托手数
            If(SKM > 0) //如果卖开委托手数大于0
            {
            If(SKDFLG == 1) //如果是SK信号卖开
            {
            Commentary("【SK信号:卖开委托发出!】");
            }
            Else If(SKDFLG == 2) //如果是BP信号卖开
            {
            Commentary("【BP信号:卖开委托发出!】");
            }
            SKID = A_SendOrder(Enum_Sell,Enum_Entry,SKM,BIDP); //发出卖开委托
            SKFLG = SKDFLG; //已发出卖开委托
            }
         }
      }
      If(BPDFLG > 0) //如果已开启买平处理
      {
         If(BPFLG == 0) //如果没有买平委托
         {
            If(SRP > 0) //如果有空头可用持仓
            {
            BPM = SRP; //买平委托手数
            If(BPDFLG == 1) //如果是BP信号买平
            {
            Commentary("【BP信号:买平委托发出!】");
            }
            Else If(BPDFLG == 2) //如果是SK信号买平
            {
            Commentary("【SK信号:买平委托发出!】");
            }
            BPID = A_SendOrder(Enum_Buy,SH,BPM,ASKP); //发出买平委托
            BPFLG = BPDFLG; //已发出买平委托
            }
         }
      }
   }
End
注:
趋势策略里写算法模型时,BK/SK/BP/SP/BPK/SPK信号指令仅用于在图表上查看信号标识,下单交易需写入发送委托单函数A_SendOrder,在模组/交易池运行检验下单效果。

2、案例二:策略模型+追价算法

投资者交易时往往有这样的矛盾:想成交在理想点位但经常不能及时成交,如果追求成交速度又不得不承担一部分滑点成本,如何才能既能保证成交又能使得交易的滑点更小呢?

如下图,我们使用算法交易接管策略委托过程,对下单进行更精细的处理:当行情平稳时采用对价委托;当遭遇极端行情价格出现较大偏离时,针对挂单方向区别处理,对开仓挂单进行撤单,避免出现更大的滑点,对平仓挂单进行市价追价,确保成交迅速离场,如此便可达到降低交易滑点,保证成交效率的效果。

思路解析:
/*
限定价格偏离初始价格的范围,当行情波动平稳时,对价委托连续追价;
当价格偏离超过此范围时,在停止追价后对后续交易进行细化处理:
如果是开仓委托,则撤单终止交易;
如果是平仓委托,则最后一次委托采用市价委托确保成交。
*/

编写示例:
Vars
   Numeric N; //下单手数
   Numeric T; //时间间隔
   Numeric W; //委托价位倍数
   Numeric PLM; //偏离价位倍数
   Numeric SH; //平仓参数
   Numeric MA3; //3周期均线
   Numeric MA5; //5周期均线
   Numeric MA10; //10周期均线
   Numeric KCP; //K线位置
   Numeric SIGID; //指令序号
   Numeric NOW; //当前时间
   Numeric NEWP; //最新价
   Numeric BIDP; //买一价
   Numeric ASKP; //卖一价
   Numeric RLP; //涨停价
   Numeric FLP; //跌停价
   Numeric MINP; //最小变动价位
   Numeric BRP; //多头可用持仓
   Numeric SRP; //空头可用持仓
   Numeric OPFLG; //模型处理标志
   Numeric BKDFLG; //买开处理标志
   Numeric SKDFLG; //卖开处理标志
   Numeric BPDFLG; //买平处理标志
   Numeric SPDFLG; //卖平处理标志
   Global_Numeric SIGIDA; //记录指令序号
   Global_Numeric KCPA; //记录K线位置
   Global_Numeric BKID; //买开委托
   Global_Numeric SKID; //卖开委托
    Global_Numeric BPID; //买平委托
   Global_Numeric SPID; //卖平委托
   Global_Numeric BKFLG; //买开标志
   Global_Numeric SKFLG; //卖开标志
   Global_Numeric BPFLG; //买平标志
   Global_Numeric SPFLG; //卖平标志
   Global_Numeric BKDEL; //买开撤单标志
   Global_Numeric SKDEL; //卖开撤单标志
   Global_Numeric BPDEL; //买平撤单标志
   Global_Numeric SPDEL; //卖平撤单标志
   Global_Numeric BKCP; //买开初始价格
   Global_Numeric SKCP; //卖开初始价格
   Global_Numeric BPCP; //买平初始价格
   Global_Numeric SPCP; //卖平初始价格
   Global_Numeric BKM; //买开委托手数
   Global_Numeric SKM; //卖开委托手数
   Global_Numeric BPM; //买平委托手数
   Global_Numeric SPM; //卖平委托手数
   Global_Numeric BKP; //买开委托价格
   Global_Numeric SKP; //卖开委托价格
   Global_Numeric BPP; //买平委托价格
   Global_Numeric SPP; //卖平委托价格
   Global_Numeric BKT; //买开委托时间
   Global_Numeric SKT; //卖开委托时间
   Global_Numeric BPT; //买平委托时间
   Global_Numeric SPT; //卖平委托时间
Setting
   SignalNoTrading:1; //出信号不下单
Begin
//------------------------处理开启------------------------//
    If(A_IsExchangeOpen() == 1) //如果是开盘状态
    {
If(RunStart() == 1) //如果已初始化成功
{
OPFLG = 1; //开启模型处理
    }
}
//------------------------变量赋值------------------------//
    If(OPFLG == 1) //变量赋值
    {
       N = 2; //下单手数
       T = 5; //时间间隔
       PLM = 3; //偏离价位倍数
       KCP = CurrentBar; //K线位置
       NOW = CurrentTime(); //当前时间
       NEWP = Price("New"); //最新价
       BIDP = Price("Bid1"); //买一价
       ASKP = Price("Ask1"); //卖一价
       RLP = Price("RiseLimit"); //涨停价
       FLP = Price("FallLimit"); //跌停价
       MINP = Price("MinPrice"); //最小变动价位
       BRP = F_BuyRemainPosition(); //多头可用持仓
       SRP = F_SellRemainPosition(); //空头可用持仓
       If(A_IsSHCode() == 1) //如果是上期所合约
       {
           SH = Enum_ExitToday; //平仓参数
       }
       Else //如果非上期所合约
       {
           SH = Enum_Exit; //平仓参数
       }
    }
//------------------------信号发出------------------------//
    If(1) //信号发出
    {
MA3 = Ma(Close,3); //3周期均线
MA5 = Ma(Close,5); //5周期均线
MA10 = Ma(Close,10); //10周期均线
PlotLine("Ma3",Ma3); //3周期均线
PlotLine("Ma5",Ma5); //5周期均线
PlotLine("Ma10",Ma10); //10周期均线
If(Ref(Cross(Ma5,Ma10),1) == 1 && MarketPosition == 0) //如果满足做多条件
{
BK; //发出做多信号
}
Else If(Ref(CrossDown(Ma3,Ma10),1) == 1 && MarketPosition == 1) //如果满足平多条件
{
SP; //发出平多信号
}
Else If(Ref(CrossDown(Ma5,Ma10),1) == 1 && MarketPosition == 0) //如果满足做空条件
{
SK; //发出做空信号
}
Else If(Ref(Cross(Ma3,Ma10),1) == 1 && MarketPosition == -1) //如果满足平空条件
{
BP; //发出平空信号
}
    }
//------------------------信号处理------------------------//
    If(OPFLG == 1) //信号处理
    {
SIGID = F_CurrentSigIndex; //指令序号
If(SIGID != 0) //如果当笔行情发出指令
{
If(SIGID != SIGIDA || KCP != KCPA) //如果当前信号是未处理过的新信号
{
SIGIDA = SIGID; //记录指令序号
KCPA = KCP; //记录K线位置
If(F_CurrentSig == Sig_BK) //如果信号类型为BK
{
Commentary("【BK信号!】");
BKDFLG = 1; //开启买开处理
}
Else If(F_CurrentSig == Sig_SP) //如果信号类型为SP
{
Commentary("【SP信号!】");
SPDFLG = 1; //开启卖平处理
}
Else If(F_CurrentSig == Sig_SK) //如果信号类型为SK
{
Commentary("【SK信号!】");
SKDFLG = 1; //开启卖开处理
}
Else If(F_CurrentSig == Sig_BP) //如果信号类型为BP
{
Commentary("【BP信号!】");
BPDFLG = 1; //开启买平处理
}
}
}
    }
//------------------------成交判断------------------------//
    If(OPFLG == 1) //成交判断
    {
If(BKFLG == 1) //如果有买开委托
{
If(F_OrderStatus(BKID) == Enum_Filled) //如果买开委托成交
{
Commentary("【BK信号:买开委托成交!】");
BKFLG = 0; //买开标志归0
BKDEL = 0; //买开撤单标志归0
}
Else If(F_OrderStatus(BKID) == Enum_Canceled) //如果买开委托已撤
{
Commentary("【BK信号:买开委托已撤!】");
If(BKDEL == 1) //如果是价格偏离过大撤单
{
BKFLG = 0; //买开标志归0
}
Else If(BKDEL == 2) //如果是时间间隔T秒追价
{
If(F_OrderFilledLot(BKID) > 0) //如果买开委托部分成交
{
BKM = BKM - F_OrderFilledLot(BKID); //买开委托手数
}
If(BKM > 0) //如果买开委托手数大于0
{
BKP = ASKP; //买开委托价格
Commentary("【BK信号:买开委托追价!】");
BKID = A_SendOrder(Enum_Buy,Enum_Entry,BKM,BKP); //发出买开委托
BKT = NOW; //买开委托时间
}
}
BKDEL = 0; //买开撤单标志归0
}
Else If(F_OrderStatus(BKID) == Enum_Declared || F_OrderStatus(BKID) == Enum_FillPart) //如果买开委托挂单
{
If(BKDEL == 0) //如果未撤单
{
If(Abs(NEWP - BKCP) > PLM * MINP) //如果价格偏离过大
{
Commentary("【BK信号:价格偏离过大!】");
Commentary("【BK信号:买开委托撤单!】");
F_DeleteOrder(F_OrderContractNo(BKID)); //撤掉买开委托挂单
BKDEL = 1; //已发出撤掉买开委托挂单
}
Else If(TimeDiff(BKT,NOW) >= T) //如果时间间隔T秒
{
Commentary("【BK信号:买开委托撤单!】");
F_DeleteOrder(F_OrderContractNo(BKID)); //撤掉买开委托挂单
BKDEL = 2; //已发出撤掉买开委托挂单
}
}
}
}
If(SPFLG == 1) //如果有卖平委托
{
If(F_OrderStatus(SPID) == Enum_Filled) //如果卖平委托成交
{
Commentary("【SP信号:卖平委托成交!】");
SPFLG = 0; //卖平标志归0
SPDEL = 0; //卖平撤单标志归0
}
Else If(F_OrderStatus(SPID) == Enum_Canceled) //如果卖平委托已撤
{
Commentary("【SP信号:卖平委托已撤!】");
If(F_OrderFilledLot(SPID) > 0) //如果卖平委托部分成交
{
SPM = SPM - F_OrderFilledLot(SPID); //卖平委托手数
}
If(BRP > 0 && SPM > 0 && SPM <= BRP) //如果卖平委托手数不超过多头可用持仓
{
If(SPDEL == 1) //如果是价格偏离过大追价
{
SPP = FLP; //卖平委托价格
}
Else If(SPDEL == 2) //如果是时间间隔T秒追价
{
SPP = BIDP; //卖平委托价格
SPT = NOW; //卖平委托时间
SPDEL = 0; //卖平撤单标志归0
}
Commentary("【SP信号:卖平委托追价!】");
SPID = A_SendOrder(Enum_Sell,SH,SPM,SPP); //发出卖平委托
}
}
Else If(F_OrderStatus(SPID) == Enum_Declared || F_OrderStatus(SPID) == Enum_FillPart) //如果卖平委托挂单
{
If(SPDEL == 0) //如果未撤单
{
If(Abs(NEWP - SPCP) > PLM * MINP) //如果价格偏离过大
{
Commentary("【SP信号:价格偏离过大!】");
Commentary("【SP信号:卖平委托撤单!】");
F_DeleteOrder(F_OrderContractNo(SPID)); //撤掉卖平委托挂单
SPDEL = 1; //已发出撤掉卖平委托挂单
} Else If(TimeDiff(SPT,NOW) >= T) //如果时间间隔T秒
{
Commentary("【SP信号:卖平委托撤单!】");
F_DeleteOrder(F_OrderContractNo(SPID)); //撤掉卖平委托挂单
SPDEL = 2; //已发出撤掉卖平委托挂单
}
}
}
}
If(SKFLG == 1) //如果有卖开委托
{
If(F_OrderStatus(SKID) == Enum_Filled) //如果卖开委托成交
{
Commentary("【SK信号:卖开委托成交!】");
SKFLG = 0; //卖开标志归0
SKDEL = 0; //卖开撤单标志归0
}
Else If(F_OrderStatus(SKID) == Enum_Canceled) //如果卖开委托已撤
{
Commentary("【SK信号:卖开委托已撤!】");
If(SKDEL == 1) //如果是价格偏离过大撤单
{
SKFLG = 0; //卖开标志归0
}
Else If(SKDEL == 2) //如果是时间间隔T秒追价
{
If(F_OrderFilledLot(SKID) > 0) //如果卖开委托部分成交
{
SKM = SKM - F_OrderFilledLot(SKID); //卖开委托手数
}
If(SKM > 0) //如果卖开委托手数大于0
{
SKP = BIDP; //卖开委托价格
Commentary("【SK信号:卖开委托追价!】");
SKID = A_SendOrder(Enum_Sell,Enum_Entry,SKM,SKP); //发出卖开委托
SKT = NOW; //卖开委托时间
}
}
SKDEL = 0; //卖开撤单标志归0
}
Else If(F_OrderStatus(SKID) == Enum_Declared || F_OrderStatus(SKID) == Enum_FillPart) //如果卖开委托挂单
{
If(SKDEL == 0) //如果未撤单
{
If(Abs(NEWP - SKCP) > PLM * MINP) //如果价格偏离过大
{
Commentary("【SK信号:价格偏离过大!】");
Commentary("【SK信号:卖开委托撤单!】");
F_DeleteOrder(F_OrderContractNo(SKID)); //撤掉卖开委托挂单
SKDEL = 1; //已发出撤掉卖开委托挂单
}
Else If(TimeDiff(SKT,NOW) >= T) //如果时间间隔T秒
{
Commentary("【SK信号:卖开委托撤单!】");
F_DeleteOrder(F_OrderContractNo(SKID)); //撤掉卖开委托挂单
SKDEL = 2; //已发出撤掉卖开委托挂单
}
}
}
}
If(BPFLG == 1) //如果有买平委托
{
If(F_OrderStatus(BPID) == Enum_Filled) //如果买平委托成交
{
Commentary("【BP信号:买平委托成交!】");
BPFLG = 0; //买平标志归0
BPDEL = 0; //买平撤单标志归0
}
Else If(F_OrderStatus(BPID) == Enum_Canceled) //如果买平委托已撤
{
Commentary("【BP信号:买平委托已撤!】");
If(F_OrderFilledLot(BPID) > 0) //如果买平委托部分成交
{
BPM = BPM - F_OrderFilledLot(BPID); //买平委托手数
}
If(SRP > 0 && BPM > 0 && BPM <= SRP) //如果买平委托手数不超过空头可用持仓持仓
{
If(BPDEL == 1) //如果是价格偏离过大追价
{
BPP = RLP; //买平委托价格
}
Else If(BPDEL == 2) //如果是时间间隔T秒追价
{
BPP = ASKP; //买平委托价格
BPT = NOW; //买平委托时间
BPDEL = 0; //买平撤单标志归0
}
Commentary("【BP信号:买平委托追价!】");
BPID = A_SendOrder(Enum_Buy,SH,BPM,BPP); //发出买平委托
}
}
Else If(F_OrderStatus(BPID) == Enum_Declared || F_OrderStatus(BPID) == Enum_FillPart) //如果买平委托挂单
{
If(BPDEL == 0) //如果未撤单
{
If(Abs(NEWP - BPCP) > PLM * MINP) //如果价格偏离过大
{
Commentary("【BP信号:价格偏离过大!】");
Commentary("【BP信号:买平委托撤单!】");
F_DeleteOrder(F_OrderContractNo(BPID)); //撤掉买平委托挂单
BPDEL = 1; //已发出撤掉买平委托挂单
}
Else If(TimeDiff(BPT,NOW) >= T) //如果时间间隔T秒
{
Commentary("【BP信号:买平委托撤单!】");
F_DeleteOrder(F_OrderContractNo(BPID)); //撤掉买平委托挂单
BPDEL = 2; //已发出撤掉买平委托挂单
}
}
}
}
    }
//------------------------委托处理------------------------//
    If(OPFLG == 1) //委托处理
    {
If(BKDFLG == 1) //如果已开启买开处理
{
If(BKFLG == 0) //如果没有买开委托
{
BKM = N; //买开委托手数
BKP = ASKP; //买开委托价格
BKCP = BKP; //买开初始价格
Commentary("【BK信号:买开委托发出!】");
BKID = A_SendOrder(Enum_Buy,Enum_Entry,BKM,BKP); //发出买开委托
BKT = NOW; //买开委托时间
BKFLG = 1; //已发出买开委托
}
}
If(SPDFLG == 1) //如果已开启卖平处理
{
If(SPFLG == 0) //如果没有卖平委托
{
If(BRP > 0) //如果有多头可用持仓
{
SPM = BRP; //卖平委托手数
SPP = BIDP; //卖平委托价格
SPCP = SPP; //卖平初始价格
Commentary("【SP信号:卖平委托发出!】");
SPID = A_SendOrder(Enum_Sell,SH,SPM,SPP); //发出卖平委托
SPT = NOW; //卖平委托时间
SPFLG = 1; //已发出卖平委托
}
}
}
If(SKDFLG == 1) //如果已开启卖开处理
{
If(SKFLG == 0) //如果没有卖开委托
{
SKM = N; //卖开委托手数
SKP = BIDP; //卖开委托价格
SKCP = SKP; //卖开初始价格
Commentary("【SK信号:卖开委托发出!】");
SKID = A_SendOrder(Enum_Sell,Enum_Entry,SKM,SKP); //发出卖开委托
SKT = NOW; //卖开委托时间
SKFLG = 1; //已发出卖开委托
}
}
If(BPDFLG == 1) //如果已开启买平处理
{
If(BPFLG == 0) //如果没有买平委托
{
If(SRP > 0) //如果有空头可用持仓
{
BPM = SRP; //买平委托手数
BPP = ASKP; //买平委托价格
BPCP = BPP; //买平初始价格
Commentary("【BP信号:买平委托发出!】");
BPID = A_SendOrder(Enum_Buy,SH,BPM,BPP); //发出买平委托
BPT = NOW; //买平委托时间
BPFLG = 1; //已发出买平委托
}
}
}
    }
End

相关问题解答:
1、Wh9编写语法:
2、常用系统函数说明:
3、Wh9常见编写和机制说明:
(二)独立算法交易策略

独立的算法交易模型不以K线数据为基础,直接调用盘口数据或交易账户信息构建策略。可通过盘口报价和逐笔成交数据挖掘市场信息,调用交易账户的持仓信息、挂单信息、委托回报等对委托过程进行精细化处理,对多个账号批量下单等智能管控。

独立的算法交易模型实现个性化下单需求

软件中提供几种默认的止盈止损策略,但有时还是无法完全满足用户的多样性需求。例如,想要在盈利达到一定数值时再启动跟踪止盈策略,系统的跟踪止盈策略是实现不了的,这时我们可以用算法模型结合账户持仓详情,编制属于自己的止盈策略。

案例:独立算法交易模型实现个性化止盈止损

如下图,是自定义的跟踪止盈算法策略,用独立算法交易模型调用合约盘口价格和账户中的合约持仓价格、数量,实时对比监测,当盈利达到一定值时再启动跟踪止盈,实现灵活的止盈止损效果。

思路解析:
/*
止盈思路:买开后,动态价差达到三个点以上,启动跟踪止盈策略
止损思路:买开后,动态价差达到三个点以上,启动跟踪止损策略
*/

编写示例:
Data
    data0:"m1905"; 
Vars 
    Global_Numeric N;//下单手数 
    Global_Numeric M1; //价位倍数1 
    Global_Numeric M2; //价位倍数2 
    Global_Numeric M3; //价位倍数3 
    Global_Numeric BID; //买一价 
    Global_Numeric ASK; //卖一价 
    Global_Numeric NEWP; //最新价 
    Global_Numeric MINP; //最小变动价位 
    Global_Numeric BKC; //做多条件 
    Global_Numeric BKID; //买开委托 
    Global_Numeric BKFLG; //买开标志 
    Global_Numeric BKAP; //买开委托成交均价 
    Global_Numeric BHP; //多头最高价 
    Global_Numeric SPID; //卖平委托 
    Global_Numeric SPFLG; //卖平标志 
    Global_Numeric BRP; //多头可用持仓 
    Global_Numeric BZYFLG; //多头止盈标志 
Begin 
    N = 2; //下单手数 
    M1 = 3; //价位倍数1 
    M2 = 1; //价位倍数2 
    M3 = 3; //价位倍数3 
    BKC = 1; //做多条件 
    BID = Price("Bid1"); //买一价 
    ASK = Price("Ask1"); //卖一价 
    NEWP = Price("New"); //最新价 
    MINP = Price("MinPrice");//最小变动价位 
    BRP = F_BuyRemainPosition(); //多头可用持仓
   if(A_IsExchangeOpen() == 1) //如果当前状态是开盘 
    { 
       //----------------------成交判断--------------------//
      if(BKFLG == 1) //如果有买开委托 
       { 
          if(F_OrderStatus(BKID) == Enum_Filled) //如果买开委托成交 
          { 
             Commentary("【多头开仓:买开委托成交!】"); 
             BKAP = F_OrderFilledPrice(BKID); //买开委托成交均价 
             BKFLG = 2; //买开委托已成交 
          } 
       }
      if(SPFLG > 0) //如果有卖平委托 
       { 
          if(F_OrderStatus(SPID) == Enum_Filled) //如果卖平委托成交 
          { 
             if(SPFLG == 1) //如果是多头止盈卖平委托 
             { 
                Commentary("【多头止盈:卖平委托成交!】"); 
             } 
             else if(SPFLG == 2) //如果是多头止损卖平委托 
             { 
                Commentary("【多头止损:卖平委托成交!】"); 
             } 
             BKFLG = 0; //买开标志归0 
             SPFLG = 0; //卖平标志归0 
             BZYFLG = 0; //多头止盈标志归0 
          } 
       }
      //----------------------委托处理--------------------//
      if(BKFLG == 0) //如果没有买开委托 
       { 
          if(BKC == 1) //如果满足做多条件 
          { 
             Commentary("【多头开仓:买开委托发出!】"); 
             BKID = A_SendOrder(Enum_Buy,Enum_Entry,N,ASK); //以对价发出N手的买开委托 
             BKFLG = 1; //已发出买开委托 
          } 
       }
      if(BKFLG == 2 && SPFLG == 0) //如果买开委托已成交,且没有卖平委托 
       { 
          if(BZYFLG == 0) //如果多头止盈未开启 
          { 
             if(NEWP >= BKAP + M1 * MINP) //如果最新价大于等于买开委托成交均价加M1个价位
               { 
                Commentary("【多头止盈:多头止盈开启!】"); 
                BHP = NEWP; //多头最高价设为最新价 
                BZYFLG = 1; //多头止盈开启 
             } 
          } 
          else if(BZYFLG == 1) //如果多头止盈已开启 
          { 
             BHP = max(NEWP,BHP); //多头最高价 
             if(NEWP <= BHP - M2 * MINP) //如果最新价小于等于多头最高价减M2个价位 
             { 
                if(BRP > 0) //如果有多头可用持仓 
                { 
                   Commentary("【多头止盈:卖平委托发出!】"); 
                   SPID = A_SendOrder(Enum_Sell,Enum_Exit,BRP,BID); //以对价发出多头可用持仓手数的卖平委托 
                   SPFLG = 1; //已发出多头止盈卖平委托 
                   BZYFLG = 2; //多头止盈已卖平 
                } 
             } 
          } 
          if(BZYFLG != 2) //如果多头止盈未卖平
            { 
             if(NEWP <= BKAP - M3 * MINP) //如果最新价小于等于买开委托成交均价减M3个价位 
             { 
                Commentary("【多头止损:卖平委托发出!】"); 
                SPID = A_SendOrder(Enum_Sell,Enum_Exit,BRP,BID); //以对价发出多头可用持仓手数的卖平委托 
                SPFLG = 2; //已发出多头止损卖平委托 
             } 
          } 
       } 
    } 
End

相关问题解答:
1、算法交易可否定义参数?
答:算法交易不可以定义参数。
2、算法交易模型是否支持定义序列变量?
答:不支持,因序列变量在每个BAR 只能有一个值,这个值在行情更新时会不断刷新,直到最后一个tick才能将值保存下来,因此,序列变量无法记录盘中每个tick运行公式产生的数据,例如,我们要是想对每个tick计数,用序列变量就做不到。
3、Wh9委托索引的取值是怎样的?
答:A_SendOrder函数支持返回委托单索引,数值型。
通常与F_OrderStatus(返回某个委托单的状态)函数连用,判断某个委托单的委托状态,实现对不同委托状态的委托单的差异化处理。
参考如下格式取得委托单索引:
BKID =data0. A_SendOrder(Enum_Buy,Enum_Entry,2,data0.Price("New"));
4、枚举值都有哪些函数?
答:
Enum_AmericanOption 返回美式期权的枚举值
Enum_Buy 返回买卖状态的买入枚举值
Enum_CallOption 返回看涨期权的枚举值
Enum_Canceled 返回委托状态的已撤单枚举值
Enum_Canceling 返回委托状态的正在撤单枚举值
Enum_Declare 返回委托状态的正在申报枚举值
Enum_Declared 返回委托状态的已申报枚举值
Enum_Deleted 返回委托状态的已废除枚举值
Enum_Entry 返回开平仓状态的开仓枚举值
Enum_EuropeanOption 返回欧式期权的枚举值
Enum_Exit 返回开平仓状态的平仓枚举值
Enum_ExitToday 返回开平仓状态的平今仓枚举值
Enum_Filled 返回委托状态的全部成交枚举值
Enum_FillPart 返回委托状态的部分成交枚举值
Enum_PutOption 返回看跌期权的枚举值
Enmu_Sell 返回买卖状态的卖出枚举值
示例: 
A_SendOrder(Enum_Sell,Enum_Exit,data0.F_BuyRemainPosition(),data0.Price("bid1"));//对当前公式应用的交易账户对应合约发出卖出平仓委托,以买一价平公式应用交易账户当前多头可用持仓
F_GetLastOpenOrderIndex(Enum_Buy,Enum_Entry));//返回公式应用对应的交易帐户中当前合约最后一个买开委托的未成交委托单索引