量化软件——赫兹MT5函子与幺半群

概述
我们继续研究范畴论,针对函子进行更多研究。到目前为止,我们已经见识过了范畴论在实现智能尾随类和智能信号类的自定义实例中的应用,故此我们将在本文中研究其在智能资金类中的应用。所有这些类都出自 Meta Editor IDE,并与 MQL5 向导一起使用,从而可以最少的编码量来拼装智能交易系统。

在交易系统设计方面,持仓规模是热点问题之一。在任何智能系统的初步测试中得到的结果对它都非常敏感,通常建议将其全部排除在外(使用固定保证金或固定手数),或者如果您必须要用它,请您在已经拥有相应的入场信号时将其添加到最后,这样就会与您的退出方法达良好的平衡。尽管如此,我们将尝试基于智能系统资金类的自定义实例所预测的止损设置理想的持仓规模。

函子是范畴之间的桥梁,它不仅捕获了每个范畴中对象之间的差异,还捕获了它们的态射差异。我们已经能够见识过,在查看图论和线性序范畴时,如何使用这些捕获的信息来预测波动率和市场趋势的变化。回顾图论和线性序本身不是范畴,但因为存在关键范畴公理故而被视作范畴。

理解交易中的函子和幺半群
如果我们快速回顾一下到目前为止所涵盖的一些基本原理,对象(在前面的文章中称为域)是单元格,或构建的范畴模块。在一个范畴中,对象之间具有称为态射的映射,就像您拥有的链接对象的态射一样,故函子链接范畴亦如此。

因此,由函子提供的范畴之间的链接在进行预测时很实用,因为协域范畴是一个时间序列,而我们的主题正是预测它。在我们的上一篇文章中曾为我们决定是做多还是做空标普 500 指数提供了信息。

然而,与上一篇文章中函子将图形链接到线性序不同的是,我们将把幺半群作为域范畴。如前所述,我们在进行交易的每一步都利用幺半群作为决策关键。由于策略的差异,这些步骤必然与其它交易者所用的步骤不同,包括选择时间帧、选择回溯区间、选择所用的应用价格、以及选择一个在产生读数时可协同所选时间帧、回溯区间和应用价格的指标。最后的选择是交易行动,即我们是否给定指标值,我们跟顺其趋势、或与其价位相逆。因此,与这些决策中的每一个对应的幺半群都已编号,且每个幺半群的二元运算负责在遍历所有集合值后从每个集合中选择相应的数值。


函子作为多层感知器(MLP)
多层感知器在交易中的作用怎样强调都不为过。关于神经网络的大量相关文献都清晰地证明了为什么它们已经、并且越来越变得不可或缺。对于大多数交易者来说,尽管它们的用途是预测证券价格的下一个趋势,这挺好。然而,在我看来,可能被忽视的是选择(也许是监管)网络的输入数据。是的,您想预测一个时间序列,但您的预测基于哪个数据流,为什么?这也许听起来小事一桩,但这可能就是为什么许多依据大数据训练的网络,其它因素不变,实际运行时不如它们在测试运行中的表现。

因此,正如我们在第 9 篇文章中曾用到的非常基本的交易系统,每个步骤中都用幺半群来告知决策,以及随后的其它一些类似步骤,我们将对本文做同样的事情,唯一的例外是最后一步将被省略,保留四个步骤。省略的第五步,其幺半群设置是顺势亦或逆势交易,于此无关。我们的多层感知器(MLP)随之用到剩余的四个幺半群的每个输出值作为输入。我们的 MLP 训练后的目标输出,将作为持仓的理想止损点。这个止损间隙的大小与持仓交易的手数成反比,因此它将作为我们持仓规模的关键指标。

由此,这就是我们如何基于预测止损间隙得到的持仓规模:

         //output from MLP forecast
         double _stoploss_gap=_y_output[0];
         
         //printf(__FUNCSIG__+" ct call: "+DoubleToString(_stoploss_gap));
      
         sl=m_symbol.Ask()+fabs(_stoploss_gap);
         
         //--- select lot size
         double _ct_1_lot_loss=(_stoploss_gap/m_symbol.TickSize())*m_symbol.TickValue();
         double lot=((m_percent/100.0)*m_account.FreeMargin())/_ct_1_lot_loss;
         
         //--- calculate margin requirements for 1 lot
         if(m_account.FreeMarginCheck(m_symbol.Name(),ORDER_TYPE_SELL,lot,m_symbol.Bid())<0.0)
         {
            printf(__FUNCSIG__" insufficient margin for sl lot! ");
            lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,m_symbol.Bid(),m_percent);
         }
         
         //--- return trading volume
         return(Optimize(lot));
首先,我们计算一手亏损持仓覆盖预测止损间隙招致的回撤亏损或货币价值。这是用间隙除以跳价大小再乘以跳价价值。如果我们在开新仓时取 “m_percent” 百分比分配保证金,其为开仓允许的最大回撤百分比,那么我们的手数将是该百分比除以 100,再乘以我们的可用保证金,再除以每手亏损。换言之,在最大幅度回撤金额中,我们可以承受每手亏损多少?


针对持仓规调整的幺半群操作
故此,如同之前的文章,对每个幺半群制定决策的编码是由一个函数处理,即 “Operate” 函数,并且取决于输入幺半群的操作方法,它涉及从幺半群集的数值中进行选择。我们案例中所用的操作方法非常初级,编号为 6 个,其中我们只用到了 4 个,因为加法和乘法要求 0 和 1 始终存在于幺半群中,这在我们的案例中是不可能的。我们高亮显示此枚举和函数的代码如下:

//+------------------------------------------------------------------+
//| Enumeration for Monoid Operations                                |
//+------------------------------------------------------------------+
enum EOperations
  {
      OP_FURTHEST=5,
      OP_CLOSEST=4,
      OP_MOST=3,
      OP_LEAST=2,
      OP_MULTIPLY=1,
      OP_ADD=0
  };

//+------------------------------------------------------------------+
//|   Operate function for executing monoid binary operations        |
//+------------------------------------------------------------------+
void CMoneyCT::Operate(CMonoid<double> &M,EOperations &O,int IdenityIndex,int &OutputIndex)
   {
      OutputIndex=-1;
      //
      double _values[];
      ArrayResize(_values,M.Cardinality());ArrayInitialize(_values,0.0);
      //
      for(int i=0;i<M.Cardinality();i++)
      {
         m_element.Let();
         if(M.Get(i,m_element))
         {
            if(!m_element.Get(0,_values[i]))
            {
               printf(__FUNCSIG__+" Failed to get double for 1 at: "+IntegerToString(i+1));
            }
         }
         else{ printf(__FUNCSIG__+" Failed to get element for 1 at: "+IntegerToString(i+1)); }
      }
      
      //
      
      if(O==OP_LEAST)
      {
         ...
      }
      else if(O==OP_MOST)
      {
         ...
      }
      else if(O==OP_CLOSEST)
      {
         ...
      }
      else if(O==OP_FURTHEST)
      {
         ...
      }
   }
现在,因为我们感兴趣的是持仓规模,而非预测市场趋势的波动性,因此最终的“动作”幺半群及其决策可以用函子代替。故此,将执行前四个幺半群,从而有助于决定指标读数,来指导持仓规模。我们将坚持使用 RSI 和布林带指标,后者像以前一样正则化,从而产生一个介于 0 和 100 之间的 RSI 值。因此,即使这个指标读数是三个早期幺半群的结果,它也将与它们配对,来创建一组四个值,这些值构成了我们多层感知器的输入。因此,需要我们如上一篇文章中所做的那样,将时间帧和应用价格的输入规范化为可由 MLP 处理的数字格式。

因此,要重申一个幺半群,它只是一个集合、一个二元运算和一个衡点元素,简单地允许从该集合中选择一个由二元运算定义的元素。通过选择时间帧、回溯区间和应用价格,我们得到了指标的输入,其归一化值 (0-100) 将作为 MLP 中的第四个输入。

在前面的文章中介绍了选择时间帧、回溯区间、应用价格和指标所涉及的步骤细节,并附上了更新的代码。尽管如此,以下是如何从每个相应函数得到输出:

         ENUM_TIMEFRAMES _timeframe_0=SetTimeframe(m_timeframe,0);
         int _lookback_0=SetLookback(m_lookback,_timeframe_0,0);
         ENUM_APPLIED_PRICE _appliedprice_0=SetAppliedprice(m_appliedprice,_timeframe_0,_lookback_0,0);
         double _indicator_0=SetIndicator(_timeframe_0,_lookback_0,_appliedprice_0,0);

集成函子和幺半群,实现综合持仓规模
为了正确驾驭我们的 MLP,我们需要适当地训练它。在上一篇文章中,训练是在初始化时完成的,如果所选网络设置可用,则加载最有利可图的网络权重,并将其用作调整权重的训练过程的起点。对于本文,在初始化之前或初始化时不执行预训练。取而代之,对于每根新柱线,网络都会得到训练。一次一根柱线。这并不是说这是正确的方式,而只是展示了在训练 MLP 或网络时,其所拥有的众多选择。但这意味着,由于初始权重始终是随机的,因此相同的智能系统设置必然会在不同的测试运行中产生非常不同的结果。作为变通,运行可盈利测试将把其权重写入文件,并在下一次运行开始时采用类似的网络设置(隐藏层中的项目数量),加载这些权重,并作为测试运行的初始权重。网络读写函数仍然是专有的,因此这里只提供对其函数库的引用,因为读者要自行实现函数库。

故此,幺半群和 MLP 的协同作用是这里真正呈现的内容,因为可以说它们中的任何一个都可以单独得到停止距离预测。理想情况下,这需要一个控制来进行验证,这意味着我们需要有单独的智能系统,这些智能系统仅实现幺半群,且只有 MLP,并比较所有三组结果。不幸的是,这对本文来说是不可行的,不过,源代码展示了这两个想法,因此邀请读者探索和验证(或反驳?)这种协同作用的想法。

由此,将两者集成在一起的代码如下:

      m_open.Refresh(-1);
      m_high.Refresh(-1);
      m_close.Refresh(-1);
      
      CMLPTrain _train;
      
      int _info=0;
      CMLPReport _report;
      CMatrixDouble _xy;_xy.Resize(1,__INPUTS+__OUTPUTS);
      
      _xy[0].Set(0,RegularizeTimeframe(_timeframe_1));
      _xy[0].Set(1,_lookback_1);
      _xy[0].Set(2,RegularizeAppliedprice(_appliedprice_1));
      _xy[0].Set(3,_indicator_1);
      //
      int _x=StartIndex()+1;
      
      double _sl_1=m_high.GetData(_x)-m_low.GetData(_x);
      
      if(m_open.GetData(_x)>m_close.GetData(_x))
      {
         _sl_1=m_high.GetData(_x)-m_open.GetData(_x);
      }
      
      double _stops=(2.0*(m_symbol.Ask()-m_symbol.Bid()))+((m_symbol.StopsLevel()+m_symbol.FreezeLevel())*m_symbol.Point());
      
      _xy[0].Set(__INPUTS,fmax(_stops,_sl_1));
      
      _train.MLPTrainLM(m_mlp,_xy,1,m_decay,m_restarts,_info,_report);
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值