五、期货量化运行详解
(一)期货模组实现自动的头寸管理、风险控制

模组中每个运行的模型称为单元,各自分配一定量的资金运行下单。模组采用这种独立的单元管理策略,可以实现更高端、智能的资金管理和风险控制。

为了分散风险,投资者通常会选择多品种、多策略、多周期组合交易,软件能否保证各模型有序执行,并准确无误的计算每个模型的交易数据则至关重要。模组为每个单元分配独立的资金,用来管理当前策略的持仓和资金变化,各单元独立运行,为交易保驾护航。

如下图,在一个分区内同时运行3个单元,各个单元之间独立运行互不干扰。在运行模组界面可以看到各个单元的持仓、资金、下单方向和分区的合计持仓、可用资金等基本信息,可基于单元的历史运行效果显示连续的理论资金曲线和真实资金曲线。

模组还支持查看每一个分区的组合资金曲线,如下图的黑色资金曲线,表示的是“螺纹-趋势+震荡”交易组合的实际资金曲线,直观反映交易组合的整体收益情况。

TIPS:运行单元和实盘账户的关系
Wh9的大部分客户,通常会在一个合约上运行不同特点的多个模型,组合交易分散风险。模组中每个运行的模型称为单元,所有单元之间独立运行。

1、单元的资金与实盘账户的资金是不同的
单元的资金是由用户随意分配的,和实盘账户资金没有直接关系。
大多数情况下,单元的资金之和不超过账户总资金数。用户在分配单元资金时会参考实盘账户的总资金量,把实盘账户的总资金,按照风险分散的逻辑,合理分配到各个单元。

2、单元的持仓与实盘账户的持仓也是不同的
单元的持仓,是这个单元的模型出信号自动下单的结果。
在用户不进行手动交易的情况下,各个单元持仓之和等于实盘账户的总持仓。

以下是模组的三个典型应用
1、模组实现资金管理方法

仓位管理和风险控制是资金管理的重中之重,模组平台独立的单元管理,为投资者在策略中实施资金管理提供了便利。可以直接获取当前运行模型的盈亏和资金变化,一些复杂的账户资金管理操作都可以在模组中通过量化语句轻松管控。

思路1:通过资金管理函数控制独立运行单元开仓头寸

行情波动反复无常,你还在使用固定手数进行下单?运行模组中使用独立的单元,管理策略的资金,投资者可以按照当前运行单元中的资金比例下单或者按资金使用率下单,来合理控制开仓头寸。

关键字:SetDealPercent 按当前单元资金比例下单
用法:写入Setting字段下表示每次按单元的理论资金的fPercent比例下单。
计算公式:fPercent比例可下单手数=(前期可用资金+平仓释放的保证金+平仓盈亏)*fPercent/(最新价*保证金比例*交易单位)。
例如:Setting
    SetDealPercent:20; //每次按当时可用资金的20%下单

如下图,根据当前单元可用资金20%的比例开仓,贴合账户盈利情况科学合理的设计头寸大小。

思路2:通过资金管理函数对运行单元进行风险控制

行情的异常波动我们很难在模型中全部都量化出来并加以限制,但是行情波动带来的影响会直接体现在资金的变化上,那么是否可以调用到策略的资金来控制进出场呢?运行模组有专门的运行单元统计资金和持仓,在编写策略时可直接调用到当前单元的资金权益,配合策略优化函数灵活设计进出场条件。

关键字:MoneyTot 返回当前单元的理论权益
MoneyTot=模组当前单元可用资金+持仓保证金,模型进行仓位控制、下单手数等资金管理时使用。
例如:If(MoneyTot<HHV(MoneyTot,0)*0.95) Sell; //权益回撤一定幅度时平仓止损

如下图,是当运行单元资金回撤一定幅度时止损,实时跟踪单元资金变动,及时避免资金回撤带来的风险,锁住账户盈利。

2、理论持仓、单元持仓二套持仓管理机制

受制于市场流动性、期货撮合成交机制、网络速度等因素,量化信号不可能100%按照模型里设定的价格方式完美成交。鉴于此,模组使用理论账户和运行单元,对理论上的信号、持仓和信号执行的实际持仓,分别管理。

(1)理论持仓和单元持仓的概念

什么是理论持仓,什么是单元持仓?他们之间又有什么样的执行关系呢?通俗点来说:按照模型计算的理论上应该执行的信号即为理论信号,根据理论信号计算得出的资金和持仓分别为理论资金和理论持仓;

模型运行时根据理论信号执行真实的委托,并将真实的成交结果反映到运行单元中,实际交易产生的资金和持仓则为实际资金和单元持仓。

如下图是理论账户和运行单元的关系示例。

二套持仓管理,保障各个单元有条不紊的运行,各单元的资金得到有效的监控。投资者对比理论账户和运行单元的持仓和资金,也可以清楚了解到策略的执行效果和真实交易的滑点成本大小等。

在下图的模组界面中,①为理论信号,②为按照理论信号计算的理论持仓,③为单元持仓,④为理论资金曲线,⑤为实际资金曲线。

如上图,当策略持续运行,实际资金曲线记录的是当前单元的实际盈亏情况,通过理论资金曲线与实际资金曲线的对比,投资者便能了解到当前单元的滑点成本大小。

(2)如何提高信号执行的成交比率

wh9软件在编写模型时,可针对交易指令指定委托价格方式,来提高成交率,降低信号下单不成交的概率,或者取得有利的价格成交,降低交易成本。

可以对不同的信号设置不同的委托方式,或者极端情况下终止下单,例如,BK(N,Price);//建仓N手,以Price价格发委托;下单价格Price可以指定为最新价/排队价/对手价/自动连续追价/超价/市价/触发价/指定价。

每一个信号可以采用不同委托价格实现不同的目的。例如:要的是便宜的成交价位,不在乎能成交几手,不便宜宁可不成交,可以用排队价;要得是保证全部成交,不在乎成交价位,可以用市价...

(3)持仓匹配校验

模组单元正常运行时,理论持仓和单元持仓也应该是一致的,但是如果网络环境不稳定或委托方式不合适导致不成交,都会影响到单元的运行,所以也建议投资者养成持仓校验的习惯,及时了解持仓匹配情况。

机构投资者运行单元数量较多,一个一个去检查账户持仓是否匹配需要的时间太长,软件提供智能的持仓匹配校验功能,一键查询真实账户持仓和策略持仓是否匹配,同时可以查看运行单元是否正常加载以及加载失败的原因。

操作方法:模组界面工具条,最右边的匹配校验信息按钮调出,如下图。

(4)手动干预的方法

情况一:运行单元盘中运行过程中,自动交易发出了委托形成挂单,长时间未成交

解决办法:可点击如图示“追对手价”按钮进行手动干预,撤掉原有的委托挂单,以当前的对手价重新发送委托(点击一次追一次),以此确保及时成交。

通过这个追价按钮的成交,运行单元会把成交价格自动带入作为权益计算的依据,权益计算会按照追价成交的价格计算。

情况二:实际账户中有持仓,理论持仓有持仓,单元持仓小于理论持仓,该怎么办?

在用户做不到软件持续运行,在交易时段关机了,或者电脑断电非正常关机等情况,重新启动模组一般会出现这个现象。

解决办法:如下图,通过“重置单元持仓”功能,将交易账户中的持仓带入到当前单元,就可以保持理论账户和单元持仓匹配。

通过重置单元持仓,会把输入的价格、持仓数量带入作为权益计算的依据,权益计算会按照你填写的价格/手数计算。

(5)模组的持仓管理机制和TB持仓同步机制的区别

Wh9有理论持仓管理、单元持仓管理二套管理机制。Wh9认可和接受流动性、网络造成的运行单元实际持仓和理论持仓不一致的实际情况,Wh9能管理这种差异,可以根据单元实际持仓绘制模型的实际权益曲线。

TB只有一种理论持仓管理机制,无法管理理论持仓和实际持仓不一致的情况,或者采用简单粗暴的持仓同步方式(延后几秒补仓强制实际持仓和理论持仓一致);或者不去理会实际持仓和理论持仓的不一致。TB只能用理论持仓绘制模型的权益曲线。

因为信号执行是有时效的,TB延后几秒的补仓的成交价格难免和信号价格有出入,会导致模型的权益曲线和实际情况有出入,另外因为延后补仓提高交易成本会降低模型盈利率,甚至因为延后补仓导致亏损。

3、产品申购/赎回管理

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(IOMA) + ",计算出的手数:" + Text(BKCV) + "手!】");
                  If(BKCV > 0) //如果需要加仓
                  {
                     BKDV = BKCV; //买开处理手数
                     BKDFLG = 2; //开启多头加仓买开处理
                  }
                  Else If(BKCV < 0) //如果需要减仓
                  {
                     SPDV = Abs(BKCV); //卖平处理手数
                     SPDFLG = 2; //开启多头减仓卖平处理
                  }
               }
               KPCFLG = 0; //委托处理标志归0
            }
         } 
      } 
   }

... ... //省略部分源码
End

如下图,算法交易模型获取运行单元的申购/赎回信息,在开盘时对所有需要调仓的模组运行单元进行了补仓操作。

模组使用注意事项
(1)保持模组连续运行

只要在交易时段,软件要一直在保持运行,这样才能保证交易信号的连续性。出于节约的目的,在闭市后可以关机,但是一定要在交易重新开市前打开软件,否则就会影响连续性,造成信号和持仓对不上的情况。

量化信号能否正常执行,取决于模组中行情和交易的连续性。运行单元行情连续才能保证信号有序执行,精准下单。要想让模组代替人工执行下单,在有条件的情况下,尽量不要关机,保证电脑24小时不关机连续运行。

注意:正常关闭软件的过程中,软件会自动保存各个单元的状态。但是,如果在软件还在运行过程中直接切断电源,会导致状态丢失,导致下次启动模组时信号持仓不匹配。

(2)保证网络稳定

运行单元在盘中实时接收数据计算信号,网络延迟、数据丢包等问题都会直接影响到运行单元中信号的计算,对后续的执行造成影响。所以运行模组时,一定要保证网络环境的稳定性。

(3)避免手动干预

模组中各单元独立运行,每个单元分别管理对应策略的持仓和资金,与总账户不存在对应关系,所以手动下的单不能由模组接管。并且手动干预带入的持仓价格可能会和理论数值不符,导致盈亏的差异,从而影响运行单元信号的判断,所以在模组运行时,一定要避免手动干预。

附:【不规范操作的解决办法】
  不规范操作 现象和原因 解决办法
1.未连续运行 非法关机
收盘前关闭软件
开盘后启动软件
1、单元持仓和理论持仓不匹配?
2、模组中不显示单元持仓?
3、实际持仓不能正常带入模组?

(原因:盘后正常关机,模组可以自动带入持仓。但盘中非法操作会导致模组中数据断档,单元的运行条件已经发生改变,所以无法接管之前的信号和持仓;)
如果当前运行的信号和持仓方向一致:
点击模组界面的“重置单元持仓”,把每个单元的持仓都手动带入;

如果当前的运行信号和持仓方向不一致:
在模组监控K线图窗口右键- > “清除历史信号重新运行”,带入之前的持仓;
2.网络不稳定 本地网络不稳定 1、回测有信号,但是运行单元中没有信号?
2、K线主图的数据和运行单元里的数据相差很大?

(原因:主图回测是从文华服务器直接申请的完整、准确的数据计算信号。运行单元中是盘中一笔一笔接收数据计算信号,如果丢包或断网,运行单元中的数据和信号就会受到影响;)
在模组监控K线图窗口右键-> “重新计算历史信号”从服务器申请准确的数据重新计算信号。运行单元后续出信号延续该信号向下执行。

操作建议:此操作只适用于临时解决运行单元信号问题。建议优化网络环境,从根源上解决问题。
3.手动干预 在下单版手动平掉运行单元的持仓
频繁干预单元持仓
1、单元持仓为何提示不匹配?
2、运行单元中显示的盈亏数据,怎么和实际的开平价格计算的盈亏不符?

(原因:模组由独立单元管理资金和持仓,手动开仓运行单元中接管不到;手动平掉单元的持仓,后续运行单元就只出平仓信号,不会真正执行委托;另,手动干预带入的持仓价格可能和理论不符,导致盈亏的差异,从而影响信号的判断;)
模组中不接管手动下单的持仓,如果需要运行单元接管,可参考问题1的解决方法。

操作建议:模组中要避免频繁的手动干预。如果是因为下单效果与预期不一致,建议调整编写思路,完善策略。
附:模组的加载方式

模组运行单元的加载方法详见(模组加载流程)

相关问题解答:
1、模型源码中指令后面写有手数了,加载模型的“交易合约”处也填写了下单手数值,下单手数以哪个为准?
答:源码中写的手数优先级高于加载模型设置的手数,所以如果源码中指令后面有手数,就按照源码中的手数下单,“交易合约”处设置的手数不起作用。当源码中指令后面没有手数的时候,再取加载模型“交易合约”处填写的手数值。
2、模型加载计算慢怎么办?
答:本地秒周期数据量过多会严重影响模型计算的速度,在主窗口K线图上单击鼠标右键—>【重新计算历史信号】,可以灵活选择加载所用的数据量,避免这一问题。
3、为什么下单手数与信号手数不一致?
(1)最后信号为开仓信号;
信号手数 < 当前单元理论资金曲线计算可开手数:下单手数 = 信号手数;
信号手数 > 当前单元理论资金曲线计算可开手数:下单手数 = 可开手数。
例:信号手数为10,下单手数却只有5手。
——根据运行单元分配资金计算,最大可开手为5手,所以即使信号手数为10,实际下单只可以下5手。
(2)最后信号为平仓信号;
信号手数 > 单元持仓 :下单手数 = 单元持仓;
信号手数 < 单元持仓 :下单手数 = 信号手数。
例:信号手数为10,下单手数却只有5手。
——理论持仓为5手,即开仓信号时只开了5手,所以平仓只执行5手;
——理论持仓为10手,但是单元持仓为5手(未初始化进来持仓/手动调仓至5手/账号同步至5手),所以平仓只执行5手。
4、模组单元日志中的信号触发价和信号执行价、滑点分别是什么意思?
信号触发价:发出委托时行情的最新价
信号执行价:信号真实委托的价格
滑点:成交价与信号触发价之间的差值
买入滑点=成交均价-信号触发价
卖出滑点=信号触发价-成交均价
(二)独立算法交易模型运行池自动交易

独立的算法交易模型通常是调用盘口数据或逐笔成交数据结合账户盈利、持仓情况进行日内高频交易策略,不需要以K线图数据为计算依据,因此是在专门的算法交易运行池中加载运行。

案例:算法交易运行池自动交易

如下图,是追涨高频盘口模型在算法交易运行池中的执行效果,算法交易运行池中会记录每一笔单子的真实委托情况,并根据模型中编写的输出语句,输出指定字符串,供投资者分析策略的运行效果,掌握策略的盈利情况。

附:独立的算法模型加载方式

独立算法模型加载方法详见(独立算法交易模型加载流程