外汇EA编写教程:蒙特卡罗方法在强化学习中的应用

简要总结了前人的研究成果和改进算法的方法

在前一篇文章中,我们讨论了随机决策森林算法,并提出了一种简单的基于强化学习的自学习算法。nbsp;nbsp;

该方法的主要优点概括如下:

  • 易于开发交易算法和高“学习”速度。强化学习(RL)可以很容易地集成到任何事务EA中,并加速其优化。

同时,这种方法有一个主要缺点:

  • 该计算法容易程度优化(过度拟合)。换句话说,它的特点是对结果分布未知的一般情况的弱泛化。这意味着,它不是在寻找金融工具在整个历史时期的真实的基本市场模型,而是根据当前的市场情况进行过度拟合,而全球模型仍然处于对训练有素的代理人的“理解”的另一面。然而,遗传优化也有同样的缺点,并且在大量变量下工作较慢。

克服过度拟合有两种主要方法:

  • 功能工程或构造属性。该方法的主要目标是选择这些特征和目标变量来描述低误差的一般情况。换言之,目的是通过使用预测因素列举的统计和经济计量方法来寻找可能的规律。在非平稳市场中,这一任务相当复杂,对于某些策略来说是不可解决的。但是,我们应该尽量选择最好的策略。
  • 在应用中,通过修改算法层次,利用正则化对模型进行粗化处理。在最后一篇文章中,我们记得在RDF中,这里应用了参数R。正则化允许训练样本和测试样本之间的误差平衡,从而在可能的情况下提高新数据模型的稳定性。

强化学习
的改进方法

上述技术以原始方式包含在算法中。一方面,属性是通过枚举价格增量并选择几个最佳值来构造的。另一方面,通过调整R参数选择新数据分类误差最小的模型。nbsp;

此外,还有一个同时创建多个RL代理的新机会。您可以在理论上设置不同的设置,以提高新数据模型的稳定性。模型枚举是使用蒙特卡罗方法(随机标记提取)在优化器中执行的,而最佳模型被写入一个文件以供进一步使用。

创建crlagent基类

为了方便起见,库是基于OOP的,这使得连接到EA和声明所需数量的RL代理变得容易。

在这里,我将描述一些类字段,以深入了解程序中的交互结构。

//+------------------------------------------------------------------+
//|RL 代理的基类                                                       |
//+------------------------------------------------------------------+
class CRLAgent
  {
public:
                     CRLAgent(string,int,int,int,double, double);
                    ~CRLAgent(void);
   static int        agentIDs;

   void              updatePolicy(double,double&[]); //在每次交易后更新学习者原则
   void              updateReward();                 //在关闭一个交易后更新收益
   double            getTradeSignal(double&[]);      //从训练好的代理或者随机接收交易信号
   int               trees;
   double            r;
   int               features;
   double            rferrors[], lastrferrors[];
   string            Name;

前三种方法用于形成学习者(代理)政策(策略),更新奖励和接收来自训练有素的代理的交易信号。在第一篇文章中对它们进行了详细描述。nbsp;

上面将进一步声明定义随机林设置的辅助字段、属性数(输入)、存储模型错误的数组以及代理(代理组)的名称。

private:
   CMatrixDouble     RDFpolicyMatrix;
   CDecisionForest   RDF;
   CDFReport         RDF_report;

   double            RFout[];
   int               RDFinfo;
   int               agentID;
   int               numberOfsamples;
   void              getRDFstructure();
   double            getLastProfit();
   int               getLastOrderType();
   void              RecursiveElimination();
   double            bestFeatures[][2];
   int               bestfeatures_num;
   double            prob_shift;
   bool random;
  };

进一步阐述了参数学习策略的保存矩阵、随机森林对象和存储错误的辅助对象。nbsp;nbsp;

提供以下静态变量以存储代理的唯一ID:

static int CRLAgent::agentIDs=0;

构造函数在开始工作之前初始化所有变量:

CRLAgent::CRLAgent(string AgentName,int number_of_features, int bestFeatures_number, int number_of_trees,double regularization, double shift_probability) {
   random=false;
   MathSrand(GetTickCount());
   ArrayResize(rferrors,2);
   ArrayResize(lastrferrors,2);
   Name = AgentName;
   ArrayResize(RFout,2);
   trees = number_of_trees;
   r = regularization;
   features = number_of_features;
   bestfeatures_num = bestFeatures_number;
   prob_shift = shift_probability;
   if(bestfeatures_num>features) bestfeatures_num = features;
   ArrayResize(bestFeatures,1);
   numberOfsamples = 0;
   agentIDs++;
   agentID = agentIDs;
   getRDFstructure();
  }

最后,将控制委托给getrdfstructure()方法以执行以下操作:

//+------------------------------------------------------------------+
//|载入学习过的代理                                                     |
//+------------------------------------------------------------------+
CRLAgent::getRDFstructure(void) {   
   string path=_Symbol+(string)_Period+Name+"//";
   if(MQLInfoInteger(MQL_OPTIMIZATION)) {
    if(FileIsExist(path+"RFlasterrors"+(string)agentID+".rl",FILE_COMMON)) {
      int getRDF; 
      do {
        getRDF=FileOpen(path+"RFlasterrors"+(string)agentID+".rl",FILE_READ|FILE_BIN|FILE_ANSI|FILE_COMMON);
        FileReadArray(getRDF,lastrferrors,0);
        FileClose(getRDF);
        }
      while (getRDF<0);   
       }
     else {
       int getRDF;   
       do {
        getRDF=FileOpen(path+"RFlasterrors"+(string)agentID+".rl",FILE_WRITE|FILE_BIN|FILE_ANSI|FILE_COMMON);
        double arr[2];
        ArrayInitialize(arr,1);
        FileWriteArray(getRDF,arr,0);
        FileClose(getRDF);
        }
      while (getRDF<0);
      }
     return;
    }
    
   if(FileIsExist(path+"RFmodel"+(string)agentID+".rl",FILE_COMMON)) {
      int getRDF=FileOpen(path+"RFmodel"+(string)agentID+".rl",FILE_READ|FILE_TXT|FILE_COMMON);
      CSerializer serialize;
      string RDFmodel="";
      while(FileIsEnding(getRDF)==false)
         RDFmodel+=" "+FileReadString(getRDF);

      FileClose(getRDF);
      serialize.UStart_Str(RDFmodel);
      CDForest::DFUnserialize(serialize,RDF);
      serialize.Stop();

      getRDF=FileOpen(path+"Kernel"+(string)agentID+".rl",FILE_READ|FILE_BIN|FILE_ANSI|FILE_COMMON);
         FileReadArray(getRDF,bestFeatures,0);
         FileClose(getRDF);
      
      getRDF=FileOpen(path+"RFerrors"+(string)agentID+".rl",FILE_READ|FILE_BIN|FILE_ANSI|FILE_COMMON);
         FileReadArray(getRDF,rferrors,0);
         FileClose(getRDF);
      
      getRDF=FileOpen(path+"RFlasterrors"+(string)agentID+".rl",FILE_WRITE|FILE_BIN|FILE_ANSI|FILE_COMMON);
         double arr[2];
         ArrayInitialize(arr,1);
         FileWriteArray(getRDF,arr,0);
         FileClose(getRDF);
     }
    else random = true;
  }

如果启动了EA优化,则会在文件中检查上次优化程序迭代期间记录的错误。在每个新的迭代中比较模型误差,以便随后选择最小迭代。

如果在测试模式下启动EA,则从文件中下载经过培训的模型以供进一步使用。此外,将清除模型中的最新错误,并设置默认值等于1,以便从头开始新的优化。

在优化器中进行下一次运行后,学员将接受以下培训:

//+------------------------------------------------------------------+
//|一个代理的学习                                                       |
//+------------------------------------------------------------------+
double CRLAgent::learnAnAgent(void)
  {
   if(MQLInfoInteger(MQL_OPTIMIZATION)) {
      if(numberOfsamples>0) {
         RecursiveElimination();

控制权委托给指定的方法,用于连续选择属性,即价格增量。让我们看看它是如何工作的:

//+------------------------------------------------------------------+
//|矩阵输入的递归特征消除                                                |
//+------------------------------------------------------------------+
CRLAgent::RecursiveElimination(void) {
//特征转换,使每两个特征以不同的滞后返回                            
   ArrayResize(bestFeatures,0);
   ArrayInitialize(bestFeatures,0);                 
   CDecisionForest   mRDF;                         
   CMatrixDouble     m;                             
   CDFReport         mRep;                          
   m.Resize(RDFpolicyMatrix.Size(),3);    
   int modelCounterInitial = 0;          
 
     for(int bf=1;bf<features;bf++) {               
      for(int i=0;i<RDFpolicyMatrix.Size();i++) {   
        m[i].Set(0,RDFpolicyMatrix[i][0]/RDFpolicyMatrix[i][bf]);	                                //用增量填充矩阵(数组零索引价格除以BF移位的价格)  
        m[i].Set(1,RDFpolicyMatrix[i][features]);   
        m[i].Set(2,RDFpolicyMatrix[i][features+1]); 
       }         
      CDForest::DFBuildRandomDecisionForest(m,RDFpolicyMatrix.Size(),1,2,trees,r,RDFinfo,mRDF,mRep);	//训练一个随机森林,其中只使用选定的增量作为预测器         
      ArrayResize(bestFeatures,ArrayRange(bestFeatures,0)+1);
      bestFeatures[modelCounterInitial][0] = mRep.m_oobrelclserror;	                                //保存 oob 集合上的错误  
      bestFeatures[modelCounterInitial][1] = bf;	                                                //保存增量'延迟'
      modelCounterInitial++;                     
     }  
     
  ArraySort(bestFeatures);                                                                              //数组排序 (根据第0维), 这里也就是根据错误 oob                               
  ArrayResize(bestFeatures,bestfeatures_num);                                                           // 只保留最佳的 bestfeatures_num 属性                 
  
  m.Resize(RDFpolicyMatrix.Size(),2+ArrayRange(bestFeatures,0));              
   
  for(int i=0;i<RDFpolicyMatrix.Size();i++) {                                                           // 再次填充矩阵,但是这一次使用最佳属性
    for(int l=0;l<ArrayRange(bestFeatures,0);l++)
      {
       m[i].Set(l,RDFpolicyMatrix[i][0]/RDFpolicyMatrix[i][(int)bestFeatures[l][1]]); 
      }          
    m[i].Set(ArrayRange(bestFeatures,0),RDFpolicyMatrix[i][features]);
    m[i].Set(ArrayRange(bestFeatures,0)+1,RDFpolicyMatrix[i][features+1]);
   }                                                                                                    
      
  CDForest::DFBuildRandomDecisionForest(m,RDFpolicyMatrix.Size(),ArrayRange(bestFeatures,0),2,trees,r,RDFinfo,RDF,RDF_report);  // 根据选定的最佳属性训练随机森林
 }

让我们全面了解代理培训方法:

//+------------------------------------------------------------------+
//|一个代理的学习                                                       |
//+------------------------------------------------------------------+
double CRLAgent::learnAnAgent(void)
  {
   if(MQLInfoInteger(MQL_OPTIMIZATION)) {
      if(numberOfsamples>0) {
         RecursiveElimination();    
         if(RDF_report.m_oobrelclserror<lastrferrors[1]) { 
          string path=_Symbol+(string)_Period+Name+"//";
          //FileDelete(path+"RFmodel"+(string)agentID+".rl",FILE_COMMON);

          CSerializer serialize;
          serialize.Alloc_Start();
          CDForest::DFAlloc(serialize,RDF);
          serialize.SStart_Str();
          CDForest::DFSerialize(serialize,RDF);
          serialize.Stop();

          int setRDF;
          
          do {
           setRDF=FileOpen(path+"RFlasterrors"+(string)agentID+".rl",FILE_WRITE|FILE_BIN|FILE_ANSI|FILE_COMMON);
           if(setRDF<0) continue;
           lastrferrors[0]=RDF_report.m_relclserror;
           lastrferrors[1]=RDF_report.m_oobrelclserror;
           FileWriteArray(setRDF,lastrferrors,0);
           FileClose(setRDF); 
          
           setRDF=FileOpen(path+"RFmodel"+(string)agentID+".rl",FILE_WRITE|FILE_TXT|FILE_COMMON);
           FileWrite(setRDF,serialize.Get_String());
           FileClose(setRDF);
        
           setRDF=FileOpen(path+"RFerrors"+(string)agentID+".rl",FILE_WRITE|FILE_BIN|FILE_ANSI|FILE_COMMON);
           rferrors[0]=RDF_report.m_relclserror;
           rferrors[1]=RDF_report.m_oobrelclserror;
           FileWriteArray(setRDF,rferrors,0);
           FileClose(setRDF);
          
           setRDF=FileOpen(path+"Kernel"+(string)agentID+".rl",FILE_WRITE|FILE_BIN|FILE_ANSI|FILE_COMMON);
           FileWriteArray(setRDF,bestFeatures);
           FileClose(setRDF); 
          }
          while(setRDF<0);        
         }
        }
     }
   return 1-RDF_report.m_oobrelclserror;
  }

在选择了属性和训练代理后,将当前优化过程中的代理分类错误与整个优化过程中保存的最小错误进行了比较。如果当前代理的错误较少,则当前模型将保存为最佳模型,随后的比较将使用模型的错误。nbsp;

蒙特卡罗方法(价格变量随机抽样)应单独考虑:

//+------------------------------------------------------------------+
//| 取得交易信号                                                       |
//+------------------------------------------------------------------+
double CRLAgent::getTradeSignal(double &featuresValues[]) {
   double res=0.5;
   if(!MQLInfoInteger(MQL_OPTIMIZATION) && !random) {
      double kerfeatures[];
      ArrayResize(kerfeatures,ArrayRange(bestFeatures,0));
      ArrayInitialize(kerfeatures,0);
      
      for(int i=0;i<ArraySize(kerfeatures);i++) {
         kerfeatures[i] = featuresValues[0]/featuresValues[(int)bestFeatures[i][1]];
        }
            
      CDForest::DFProcess(RDF,kerfeatures,RFout);
      return RFout[1];
     }
   else {
     if(countOrders()==0) if(rand()/32767.0<0.5) res = 0; else res = 1;
     else {
      if(countOrders(0)!=0) if(rand()/32767.0>prob_shift) res = 0; else res = 1;
      if(countOrders(1)!=0) if(rand()/32767.0<prob_shift) res = 0; else res = 1;
     }
    }  
   return res;
  }

如果EA不在优化模式下,则使用初始化EA时下载的训练模型来接收事务信号。否则,如果优化过程正在进行或没有模型文件,信号将随机出现,没有打开位置(50/50),并且偏移概率将由存在打开顺序的prob_移位变量设置。因此,例如,如果已经有一个公开买入交易,您可以将卖出信号的概率转换为0.1(而不是0.5)。因此,培训集中的样品总数减少,仓库的存放时间延长。同时,当prob_shift&gt;=0.5时,事务数增加。

创建crlagents类

现在,我们可以让多个代理(学习者)在交易系统中执行各种任务。本课程的目的是更方便地管理同种学习者群体。

//+------------------------------------------------------------------+
//|多 RL 代理类                                                        |
//+------------------------------------------------------------------+
class CRLAgents
  {
private:
   struct Agents
     {
      double            inpVector[];
      CRLAgent         *ag;
      double            rms;
      double            oob;
     };

   void              getStatistics();
   string            groupName;
public:
                     CRLAgents(string,int,int,int,int,double,double);
                    ~CRLAgents(void);
   Agents            agent[];
   void              updatePolicies(double);
   void              updateRewards();
   double            getTradeSignal();
   double            learnAllAgents();
   void              setAgentSettings(int,int,int,double);
  };

agents结构接受每个学习者的参数,结构数组包含这些参数的总数。对于单个代理,使用这个特定类也是有意义的。nbsp;nbsp;

构造器获取学习所需的所有参数:

CRLAgents::CRLAgents(string AgentsName,int agentsQuantity,int features, int bestfeatures, int treesNumber,double regularization, double shift_probability)
  {
   groupName=AgentsName;
   ArrayResize(agent,agentsQuantity);
   for(int i=0;i<agentsQuantity;i++) {
      ArrayResize(agent[i].inpVector,features);
      ArrayInitialize(agent[i].inpVector,0);
      agent[i].ag  = new CRLAgent(AgentsName, features, bestfeatures, treesNumber, regularization, shift_probability);
      agent[i].rms = agent[i].ag.rferrors[0];
      agent[i].oob = agent[i].ag.rferrors[1];
     }
  }

包括:代理组的名称、工作人员的数量、每个工作人员的属性数量、最佳选择的属性数量、林中树的数量、标准化参数(分为培训和测试集)和管理的事务数的概率偏差。

如我们所见,具有相同输入和训练和测试错误的学习对象被放置在结构数组中。

代理学习方法调用每个crlagent基类的学习方法,并返回所有代理测试集的平均错误:

//+------------------------------------------------------------------+
//|所有代理的学习                                                       |
//+------------------------------------------------------------------+
double CRLAgents::learnAllAgents(void){
   double err=0;
   for(int i=0;i<ArraySize(agent);i++)
      err+=agent[i].ag.learnAnAgent();
  return err/ArraySize(agent);
 }

当使用蒙特卡罗方法迭代模型时,该误差被用作可视化误差扩散的自定义优化标准。

当在一个子组中创建一定数量的学习者时,他们的设置保持不变。因此,有一种方法来调整每个学习者的参数:

//+------------------------------------------------------------------+
//|调整代理的设置                                                       |
//+------------------------------------------------------------------+
CRLAgents::setAgentSettings(int agentNumber,int features,int bestfeatures,int treesNumber,double regularization,double shift_probability) {
   agent[agentNumber].ag.features=features;
   agent[agentNumber].ag.bestfeatures_num=bestfeatures;
   agent[agentNumber].ag.trees=treesNumber;
   agent[agentNumber].ag.r=regularization;
   agent[agentNumber].ag.prob_shift=shift_probability;
   ArrayResize(agent[agentNumber].inpVector,features);
   ArrayInitialize(agent[agentNumber].inpVector,0);
  }

在CRLAgent中,事务信号显示维度学习者的子群的平均信号:

//+------------------------------------------------------------------+
//|取得通用交易信号                                                     |
//+------------------------------------------------------------------+
double CRLAgents::getTradeSignal() {
   double signal[];
   double sig=0;
   ArrayResize(signal,ArraySize(agent));

   for(int i=0;i<ArraySize(agent);i++)
      sig+=signal[i]=agent[i].ag.getTradeSignal(agent[i].inpVector);
   return sig/(double)ArraySize(agent);
  }

最后,获得统计数据的方法示出了测试人员中测试和训练所有代理的错误数据:

//+------------------------------------------------------------------+
//|取得代理的统计数据                                                   |
//+------------------------------------------------------------------+
void CRLAgents::getStatistics(void)
  {
   double arr[];
   double arrrms[];
   ArrayResize(arr,ArraySize(agent));
   ArrayResize(arrrms,ArraySize(agent));

   for(int i=0;i<ArraySize(agent);i++) {
      arrrms[i]=agent[i].rms;
      arr[i]=agent[i].oob;
     }

   Print(groupName+" TRAIN LOSS");
   ArrayPrint(arrrms);
   Print(groupName+" OOB LOSS");
   ArrayPrint(arr);
  }

基于RL Monte-Carlo开发库的事务机器人开发

现在我们只需要编写一个简单的EA来演示库功能。让我们从第一个案例开始,其中只有一个代理被用来接受交易工具的收盘价的培训。

#include <RL Monte Carlo.mqh>
input int       number_of_passes = 10;
input double    shift_probab = 0,5;
input double    regularize=0.6;
sinput int      number_of_best_features = 5;
sinput double   treshhold = 0.5;
sinput double   MaximumRisk=0.01;
sinput double   CustomLot=0;

CRLAgents *ag1=new CRLAgents("RlMonteCarlo",1,500,number_of_best_features,50,regularize,shift_probab);

包含开发库并定义需要优化的输入(输入参数)。PosiByoFixPASS用于确定终端优化器中的转数,而不是在任何地方。由于出入口是由工人随机选择的,所以在多次通过并定义最小误差后,可以实现最优策略。通过次数越多,获得最优策略的概率越高。

上面概述了其余的设置,并将其直接传递给创建的模型。在这里,我们创建一个属于rlmontecolo组的单一代理。将500个属性传递给输入,并选择五个最佳属性。该模型将有50个决策树,其中训练集和测试集之间的间隔为0.6(r参数),没有概率偏移。

在ontester函数中,自定义的优化标准(所有学习者测试样本的平均误差)在初始训练后返回:

//+------------------------------------------------------------------+
//| EA 交易 OnTester 函数                                             |
//+------------------------------------------------------------------+
double OnTester() {
   if(MQLInfoInteger(MQL_OPTIMIZATION)) return ag1.learnAllAgents();
   else return NULL;
  }

在反初始化过程中,将删除学习者并释放其记忆:

//+------------------------------------------------------------------+
//| EA 交易去初始化函数                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   delete ag1;
  }

预测器的矢量填充如下:

//+------------------------------------------------------------------+
//| 计算 Tsignal                                                      |
//+------------------------------------------------------------------+
void calcTsignal() {
   Tsignal=0;
   for(int i=0;i<ArraySize(ag1.agent);i++) {
      CopyClose(_Symbol,0,1,ArraySize(ag1.agent[i].inpVector),ag1.agent[i].inpVector);
      ArraySetAsSeries(ag1.agent[i].inpVector,true);
     }
   Tsignal=ag1.getTradeSignal();
  }

在这种情况下,最终的500个收盘价很容易实现。您可能还记得,在模型中,数组零与其他元素(具有一定滞后)的比率被视为一个预测器,因此数组被设置为按顺序接收收盘价。然后调用事务信号采集方法。

最后一个函数是贸易函数:

//+------------------------------------------------------------------+
//| 设置订单                                                           |
//+------------------------------------------------------------------+
void placeOrders() {
   for(int b=OrdersTotal()-1; b>=0; b--)
     if(OrderSelect(b,SELECT_BY_POS)==true) {
        if(OrderType()==0 && Tsignal>0.5) if(OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),0,Red)) {ag1.updateRewards();}
        if(OrderType()==1 && Tsignal<0.5) if(OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),0,Red)) {ag1.updateRewards();}
      }
   
   if(countOrders(0)!=0 || countOrders(1)!=0) return;
   if(Tsignal<0.5-treshhold && (OrderSend(Symbol(),OP_BUY,lotsOptimized(),SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0,0,NULL,OrderMagic,INT_MIN)>0)) { ag1.updatePolicies(Tsignal); }
   if(Tsignal>0.5+treshhold && (OrderSend(Symbol(),OP_SELL,lotsOptimized(),SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0,0,NULL,OrderMagic,INT_MIN)>0)) { ag1.updatePolicies(Tsignal); }
  }

“阈值”参数单独引入,允许设置信号激活阈值。例如,如果购买信号概率小于0.6,订单将不会打开。

优化RL蒙特卡罗交易员EA

让我们看看可以优化的设置:

记住,传递的次数不会将任何值传递给学习者;相反,它只是设置优化器传递的次数。假设您已经决定了其他设置,现在您只需要使用基于蒙特卡洛的枚举。在这种情况下,您应该只根据这个标准进行优化。如果需要,您仍然可以优化剩下的四个设置。

当前版本的另一个特点是,不必禁用测试代理,因为优化器中的进程彼此独立,并且保存模型的顺序并不重要。

让我们通过发布价格和使用上面M15指定的设置来优化EA两个月。应选择“自定义最大值”作为优化标准。当达到优化准则的可接受值时,可随时停止优化过程:

例如,我在第44步停止优化,因为其中一个最好的模型超过了精度阈值0.6。这意味着试样的分类误差小于0.4。记住,模型越好,误差越小,但是为了遗传算法的正确操作(如果你想使用它),误差是相反的。

您可以在“优化”选项卡中检查最佳模型设置,并根据最大自定义条件对值进行排序:

在这种情况下,最优模型的概率偏差为0.1,R参数为0.2(训练集仅为整个事务矩阵的20%,而80%为测试子集)。

停止优化后,您只需要启用单个测试模式(因为最佳模型被写入文件,并且只上载模型):

让我们滚动浏览两个月前的历史,看看这个模型在整个四个月内是如何工作的:

我们可以看到,结果模型持续了一个月(几乎整个9月),并在8月崩溃。让我们尝试通过将“treshhold”设置为0.2来微调模型:

形势明显好转。提高了模型的准确性,减少了事务处理的次数。如果培训时间长度合适,可以进行更深入的测试。

现在让我们考虑多个学习者的EA变体,比较多代理和单代理方法的效率。

为此,在创建一组代理时添加一个“多”端,这样不同系统的文件就不会混合在一起。此外,设置工作单元的数量,例如,五个:

CRLAgents *ag1=new CRLAgents("RlMonteCarloMulti",5,500,number_of_best_features,50,regularize,shift_probab);

所有代理都是相同的(它们具有相同的设置),您可以在EA初始化功能中分别配置每个工作单元:

//+------------------------------------------------------------------+
//| EA 交易初始化函数                                                  |
//+------------------------------------------------------------------+
int OnInit() {
   ag1.setAgentSettings(0,500,20,50,regularize,shift_probab);
   ag1.setAgentSettings(1,200,15,50,regularize,shift_probab);
   ag1.setAgentSettings(2,100,10,50,regularize,shift_probab);
   ag1.setAgentSettings(3,50,5,50,regularize,shift_probab);
   ag1.setAgentSettings(4,25,2,50,regularize,shift_probab);
   return(INIT_SUCCEEDED);
  }

在这里,我决定不再使事情复杂化,并按500到25的降序排列代理的属性数量。此外,最佳选择属性的数量已从20个减少到2个。其他设置保持不变。您可以更改它们并添加新的优化参数。我鼓励您尝试这些设置,并在下面的评论中分享您的结果。.

您可能还记得,数组在函数中填充了预测值:

//+------------------------------------------------------------------+
//| 计算 Tsignal                                                      |
//+------------------------------------------------------------------+
void calcTsignal() {
   Tsignal=0;
   for(int i=0;i<ArraySize(ag1.agent);i++) {
      CopyClose(_Symbol,0,1,ArraySize(ag1.agent[i].inpVector),ag1.agent[i].inpVector);
      ArraySetAsSeries(ag1.agent[i].inpVector,true);
     }
   Tsignal=ag1.getTradeSignal();
  }

这里,我们只需要根据每个学习者的大小填写inpVector数组的近似价格,因此在这种情况下,函数是通用的,不需要更改。

使用与单个代理相同的设置启动优化:

最好的结果是0.7以上,比第一个好得多。在检测仪中开始运行:

资产负债表上反映的实际结果越来越糟。为什么?让我们来看看最佳的随机事务数,它只有21个!

0

结果就是这样,因为随机抽样会导致多个代理的信号重叠,并减少事务总数。要解决此问题,请将shift-probab参数设置为接近0.5。在这种情况下,每个代理的事务数将更大,从而增加事务总数。另一方面,您可以简单地增加学习周期,但是首先我们应该看看是否可以进一步使用这个模型。设置阈值为0.2,看看会发生什么:

1

至少,虽然交易数量进一步减少,但这种模式不会赔钱。在测试运行之后,在测试日志中显示以下错误:

2018.11.30 01:56:40.441 Core 2  2018.11.28 23:59:59   RlMonteCarlo TRAIN LOSS
2018.11.30 01:56:40.441 Core 2  2018.11.28 23:59:59   0.02703 0.20000 0.09091 0.05714 0.14286
2018.11.30 01:56:40.441 Core 2  2018.11.28 23:59:59   RlMonteCarlo OOB LOSS
2018.11.30 01:56:40.441 Core 2  2018.11.28 23:59:59   0.21622 0.23333 0.21212 0.17143 0.19048

现在让我们在今年年初开始测试这个模型。结果相当稳定:

2

将shift probab设置为0.3,然后在m15上启动优化器,使其在两个月内不携带此参数(以查找事务余额):

3

随着计算复杂性的增加,我决定在优化器中多次迭代后继续使用以下结果:

2018.11.30 02:53:17.236 Core 2  2018.11.28 23:59:59   RlMonteCarloMulti TRAIN LOSS
2018.11.30 02:53:17.236 Core 2  2018.11.28 23:59:59   0.13229 0.16667 0.16262 0.14599 0.20937
2018.11.30 02:53:17.236 Core 2  2018.11.28 23:59:59   RlMonteCarloMulti OOB LOSS
2018.11.30 02:53:17.236 Core 2  2018.11.28 23:59:59   0.45377 0.45758 0.44650 0.45693 0.46120

&nbsp;测试集上的误差仍然相当大,但在0.2的阈值下,模型在四个月内显示盈利能力,尽管它在测试数据中显示出相当大的不稳定性。nbsp;

4

请记住,所有学习者都接受过相同数据(接近价格)的培训,因此没有理由添加新数据。总之,这是添加新代理的简单示例。nbsp;

结论

强化学习可能是机器学习中最有趣的方法之一。人们总是倾向于认为人工智能可以在自主学习的同时解决金融市场的交易问题。同时,为了创造这样一个“奇迹”,人们应该对机器学习、统计学和概率论有广泛的了解。蒙特卡罗方法和实验数据采用最小误差选择模型,大大改善了本文第一部分提供的模型。这个型号再也不合身了。

应根据交易数量和最小分类误差选择最佳模型。理想情况下,训练和测试集误差应大致相等,且不应达到0.5(一半的示例预测误差)。nbsp;

本文是由Meta卫星软件公司在HTTPS://www. MQL5.COM/RU/TorsLe/477 7中从俄语原文
中翻译而来的。

附加文件>下载zip rLnMuntE.CARLO.MQH(17.26 KB),RLMMONTEXCARROLUTHARER .MQ5(10.33 KB),RLMMONTEXCARLUROTRORIER多MQ5(5.47 KB)

 

 


MyFxtop迈投(www.myfxtop.com)-靠谱的外汇跟单社区,免费跟随高手做交易!

 

免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经(www.myfxtop.cn)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。

風險提示

MyFxtops邁投所列信息僅供參考,不構成投資建議,也不代表任何形式的推薦或者誘導行為。MyFxtops邁投非外匯經紀商,不接觸妳的任何資金。 MYFXTOPS不保證客戶盈利,不承擔任何責任。從事外彙和差價合約等金融產品的槓桿交易具有高風險,損失有可能超過本金,請量力而行,入市前需充分了解潛在的風險。過去的交易成績並不代表以後的交易成績。依據各地區法律法規,MyFxtops邁投不向中國大陸、美國、加拿大、朝鮮居民提供服務。

邁投公眾號

聯繫我們

客服QQ:981617007
Email: service@myfxtop.com

MyFxtops 邁投