通过指定的幻数计算总持仓量的最佳方法

简介

MetaTrader 5 客户端允许并行处理多个事务。 EA 交易。这很简单 – 只需打开几张图表。,然后将 EA 交易附在他们身上。。如果每个 EA 使用相同的交易品种与他人交易。 EA 独立交易,会很好的。 EA 在交易中没有这样的问题。。

第一,它允许 EA 交易与测试性能和Optimizati完全一致。。仓库设置条件可能取决于所建立的WA的大小。。如果一些 EA 交易使用相同的交易品种。,它们相互作用。。

第二个或许更重要的是允许。 EA 交易依据在 EA 在交易中实施的交易策略使用不同的资本管理。最后 – 能够监控每一个 EA 必要时关闭事务的结果。 EA 交易。

1. 计算位置的一般原则

在建造仓库时,你可以把它传递给 OrderSend() 函数的 MqlTradeRequest 指定结构中的魔法变量数。,马克用神奇的数字。。执行订单时,事务也用魔术数字标记订单。。此外,历史记录中的交易分析,我们可以看看差异。 EA 建立交易。

总位置的计算方法相当简单。:举例而言,如果你执行购买 手工贸易,然后别人买。 手,再卖出 手,则总持仓量将等于 +-=+ 手。我们加上购买量。,减销量,就得到总持仓量。

在总持仓量等于 0 计算在开始时非常重要。。第一个也是最明显的时间点是开一个账户。。换言之,你可以用它。 HistorySelect() 函数请求帐户的所有事务历史记录,函数的第一个参数等于第一个参数。 0(最不可能的时间),第二个参数的值是 TimeCurrun()(服务器的最新已知时间):

HistorySelect(0,TimeCurrent()); // 加载历史数据

接着,从头到尾贯穿整个历史。,对于具有指定幻数的每个事务,加买量,减销量。这也是一个解决办法。,但在实践中,这笔交易的历史记录可能非常巨大。。这可能会产生重大影响。 EA 交易速度,特别是在测试和优化期间。,这样他们就不能实际使用。 EA 交易。我们需要找出ToTa的交易历史中的最后时刻。。

为此,我们必须先读完整个历史,找出总数。 P的净位置的最后时刻为零。。找到这个时间点之后,,我们把它保持在一个变量(固定存储时间)。之后,EA 事务将从保存的时间开始记录事务历史记录。。一个更好的解决方案是将该时间点保存在CLI的全局变量中。,而不是 EA 交易的变量,因为在后一种情况下,分离 EA 事务将破坏变量。。

在此类情况下,即使 EA 交易已经开始,你还需要载入最少必要的历史记录。,而不是整个交易的历史。。很多 EA 交易可以在相同的交易品种上交易。,所以我们将与所有 EA 事务共享这个全局变量(包含最新的零栈)。。

让我们偏离主题。,考虑客户端全局变量的使用。,这允许几个 EA 交易使用相同的交易品种。(可能具有不同的参数),避免 EA 由不同事务实例创建的重复名称。

2. 使用客户端的全局变量

MQL5 语言有 MQL5InfoString() 函数,允许获取有关 mql5 程序的不同信息。

以获取有关文件名的信息,使用 MQL5_PROGRAM_NAME 标识符调用此函数。:

MQL5InfoString(MQL5_PROGRAM_NAME); // EA 名

因此,我们拿一个吧。 EA 交易的名称作为全局变量名称的开头。一个 EA 事务可以处理几种类型的事务。;这意味着我们需要添加交易品种的名称(交易)。。几个 EA 事务可以处理相同的事务种类。,但是时间框架不同(不同的设置),针对这些情况,我们需要使用魔法数字。。因此,我们还增加了魔法数。。

举例而言,如果 EA 在事务中存储变量。 Magic_N 其中的神奇数,我们将其添加到全局变量的名称。。

所有全局变量的名称都是这样的。:

gvp=MQL5InfoString(MQL5_PROGRAM_NAME)+"_"+_Symbol+"_"+IntegerToString(Magic_N)+"_"; // EA名称和商号 
                                                                            // 它的神奇数

其中 GVP(全局变量前缀)是在公共VaR中声明的字符串变量。。

我想澄清这个术语,以避免全局变量的混淆。,因为它们是编程中使用(全局变量在所有FU中都可见),而函数的局部变量仅在内部功能部可见)。

但在这里。,我们有不同的情况。 – 术语全局变量指的是客户端的全局变量(SP)。,通过 GlobalVariable…() 函数用法。讨论编程中使用的全局变量时,我们将使用公共变量这个词。。局部变量也引用局部变量。。

全局变量是非常有用的。,因为它们是 EA 事务初始化(EA) 交易、客户端和计算机重启)之后仍然保存它们的值,但是在测试模式下,必须清除所有变量(或在优化过程中删除以前的传递)。在实际操作中应该使用的全局变量是分隔符。;测试过程中创建的全局变量必须在测试后删除。。但是你不应该修改或删除。 EA 事务创建的全局变量。

使用 AccountInfoInteger() 功能与使用 ACCOUNT_TRADE_MODE 标识符调用函数。,你可以区分当前的模式。:测试程序、演示或实际帐户。

让我们给全局变量添加一个前缀。:”d” – 使用演示帐号,”r” – 使用实际帐户,”t” – 策略测试程序中的工作:

gvp=MQL5InfoString(MQL5_PROGRAM_NAME)+"_"+_Symbol+"_"+IntegerToString(Magic_N)+"_"; // EA 姓名和商号
                                                                            // 和 EA 的幻数
if(AccountInfoInteger(ACCOUNT_TRADE_MODE)==ACCOUNT_TRADE_MODE_DEMO))
  {
   gvp=gvp+"d_"; // 演示帐户
  }
if(AccountInfoInteger(ACCOUNT_TRADE_MODE)==ACCOUNT_TRADE_MODE_REAL)
  {
   gvp=gvp+"r_"; // 实际
  }
if(MQL5InfoInteger(MQL5_TESTING))
  {
   gvp=gvp+"t_"; // 测试
  } 

功能应该来自 EA 交易的 OnInit() 函数调用。

如前文所述,在测试期间应该删除全局变量。,换言之,我们需要 EA 交易的 OnDeinit() 函数删除全局变量的函数:

void fDeleteGV()
  {
   if(MQL5InfoInteger(MQL5_TESTING)) // 测试模式
     {
      for(int i=GlobalVariablesTotal()-1;i>=0;i--) // 检查所有全局变量 (从后面向前)
        {
         if(StringFind(GlobalVariableName(i),gvp,0)==0) // 搜索指定的前缀
           {
            GlobalVariableDel(GlobalVariableName(i)); // 删除变量
           }
        }
     }
  }

目前是不可能的。 MetaTrader 5 内部中断测试,这不能保证。 OnDeinit() 函数的执行,然而,它可能会发生在未来。。我们不知道我们是否会在中断策略测试PRO之后执行 OnDeinit() 函数,所以我们是 EA 当事务开始运行时删除全局变量。 – 在 OnInit() 内部功能。

我们得到了它 OnInit() 和 OnDeinit() 函数的以下代码:

intOnInit()
  {
   fCreateGVP(); // 为客户端终端全局变量名称创建前缀
   fDeleteGV();  // 在测试中工作时,删除全局变量
   return(0);
  }

voidOnDeinit(constint 原因)
  {
   fDeleteGV();  // 在测试中工作时,删除全局变量
  }

我们还可以通过创建函数来简化全局变量的使用。 GlobalVariableSet(gvp+…)。

设置全局变量的值:

void fGVS(string aName,double 雪崩)
  {
   GlobalVariableSet(gvp+aName,雪崩);
  }

函数获取全局变量的值:

double fGVG(string 阿纳姆)
  {
   return(GlobalVariableGet(gvp+阿纳姆));
  }

删除全局变量的函数:

void fGVD(string 阿纳姆)
  {
   GlobalVariableDel(gvp+阿纳姆);
  }

我们已经讨论了全局变量。,但这还不是全部。。

我们需要为交易创造全局变量的可能性。,并在帐户和策略测试程序中提供不同的操作。。这些全局变量的名称不应该由 EA 交易名称和魔术数。

让我们为全局变量前缀声明另一个变量。,命名为 “Commom_gvp”。接着,使用帐户时,其值为 “COMMON”,使用策略测试过程时,它的价值与变量 gvp 相同的(在策略重新开始之前或之后删除变量)。

最后,准备全局变量前缀的函数具有以下形式:

void fCreateGVP()
  {
   gvp=MQL5InfoString(MQL5_PROGRAM_NAME)+"_"+_Symbol+"_"+IntegerToString(Magic_N)+"_";
   Commom_gvp="COMMOM_"; // 所有 EA 公共变量前缀
   if(AccountInfoInteger(ACCOUNT_TRADE_MODE)==ACCOUNT_TRADE_MODE_DEMO)
     {
      gvp=gvp+"d_";
     }
   if(AccountInfoInteger(ACCOUNT_TRADE_MODE)==ACCOUNT_TRADE_MODE_REAL)
     {
      gvp=gvp+"r_";
     }
   if(MQL5InfoInteger(MQL5_TESTING))
     {
      gvp=gvp+"t_";
      Commom_gvp=gvp; // 用于测试, 变量有这样的前缀。 
                      // 测试将被删除。
     }
  }

有些人可能认为全局变量的前缀不包括e。 – 演示与实际账户分离,测试时间。 “t” 前缀,虽然它可以被添加来代表我们。 EA 交易策略测试程序中的工作的字符 “t” 来实现。但我是这样做的。。我们不知道未来和分析。 EA 在交易中需要做什么?。

储存并不像他们说的那么悲伤。。

上述功能意味着客户端处理帐户。,在工作期间,帐目没有变化。。禁止进入 EA 交易期间更改帐户。当然,如果需要,您可以通过向全局VA的名称添加帐户来解决此问题。。

另一件非常重要的事情。!全局变量名称的长度不得超过 63 个字符。因此,不是给你的。 EA 事务指定太长的名称。

我们已经完成了全局变量的讨论。,现在是考虑这篇文章主题的时候了。:根据指定的幻数计算位置的数目。。

3. 计算位置

首先,让我们使用它。 GlobalVariableCheck() 函数检查是否有一个全局变量含有最后一个零持仓量时间的相关信息(为了简单起见,如果没有既定位置,我们称之为零位。。

如果有这样的变量 – 让我们来自存储在VARI中的时间开始加载事务历史。,否则,我们将加载整个历史记录。:

if(GlobalVariableCheck(Commom_gvp+sSymbol+"_HistStTm")) // 保存位置 "零" 时间
  {
   pLoadHistoryFrom=(datetime)GlobalVariableGet(Commom_gvp+pSymbol+"_HistStTm"); // 初始化时间设置 
                                                                             // 只选择所需的历史数据。
  }
else
 {
   GlobalVariableSet(Commom_gvp+sSymbol+"_HistStTm",0);
 }
if(!HistorySelect(sLoadHistoryFrom,TimeCurrent())) // 载入必要的合同历史部分
  { 
   return(假)
  } 

接下来,我们定义了交易品种的总净位置。:

double CurrentVolume=fSymbolLots(pSymbol);

使用 fSymbolLots() 确定位置的函数。

获得职位的方法有几种。:例如,您可以使用它。 PositionSelect() 函数完成。如果函数返回 false,这意味着没有位置(位置等于零)。。如果函数返回 true,你可以用它。 PositionGetDouble() 功能与 POSITION_VOLUME 标识符保持。使用 PositionGetInteger() 功能与 POSITION_TYPE 标识符确定商店的类型(买卖)。长筒仓,函数返回正值。,短仓,函数返回负值。。

完整的函数是这样的。:

double fSymbolLots(string 不对称的)
  {
   if(PositionSelect(符号),1000)) // 成功选址, 所以它存在。
     {
      switch(PositionGetInteger(POSITION_TYPE)) // 根据方向返回正负
        {
         casePOSITION_TYPE_BUY:
            return(NormalizeDouble(PositionGetDouble(POSITION_VOLUME),2));
            break;
         casePOSITION_TYPE_SELL:
            return(NormalizeDouble(-PositionGetDouble(POSITION_VOLUME),2));
            break;
        }
     }
   else
     {
      return(0);
     }
  }

此外,您可以通过遍历所有仓位来确定交易品种的总持仓量,职位数量 PositionsTotal() 函数确定。之后,使用 PositionGetSymbol() 查找必要事务种类的函数,单独使用 PositionGetDouble() 功能与 POSITION_VOLUME 标识符和 PositionGetInteger() 功能与 POSITION_TYPE 标识符确定位置和方向。。

在这个例子中,就绪函数具有以下形式: 

double fSymbolLots(string 不对称的)
  {
   double TmpLots=0;
   for(int i=0;i<PositionsTotal();i++) // 遍历所有位置
     {
      if(PositionGetSymbol(i)==不对称的) // 我们找到了指定的交易品种的位置。
        {
         TmpLots=PositionGetDouble(POSITION_VOLUME);
         if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
           {
            TmpLots*=-1; // 基于位置类型的马克          }
         break;
        }
     }
   TmpLots=NormalizeDouble(TmpLots,2);
   return(TmpLots);
  }

在确定当前位置之后,,我们将从头到尾进行交易历史。,直到总持仓量等于当前持仓量。

使用 HistoryDealsTotal() 函数来确定事务的选定历史长度。,使用 HistoryDealGetTicket() 用于识别每个事务的文档的功能。,使用 HistoryDealGetInteger() 函数(DEAL_TYPE 标识符表示事务的类型)。 HistoryDealGetDouble()(DEAL_VOLUME 标识符表示交易量)提取交易数据:

double Sum=0; 
int FromI=0;
int FromTicket=0;
for(int i=HistoryDealsTotal()-1;i>=0;i--) // 遍历所有合同 
  {
   ulong ticket=HistoryDealGetTicket(i); // 获得合同号码。
   if(票)!=0)
     {
      switch(HistoryDealGetInteger(票),DEAL_TYPE)) // 基于合同方向的岗位增减
        {
         caseDEAL_TYPE_BUY:
            Sum+=HistoryDealGetDouble(票),DEAL_VOLUME);
            Sum=NormalizeDouble(和),2);
            break;
         caseDEAL_TYPE_SELL:
            Sum-=HistoryDealGetDouble(票),DEAL_VOLUME);
            Sum=NormalizeDouble(和),2);
            break;
        }
      if(CurrentVolume==Sum) // 所有的合同都被扫描过了。
        {
         sLoadHistoryFrom=HistoryDealGetInteger(票),DEAL_TIME); // 保存位置 "零" 时间
         GlobalVariableSet(Commom_gvp+aSymbol+"_HistStTm",sLoadHistoryFrom);
         FromI=i; // 保存索引
         break;
        }
     }
  }

当我们找到这一点,我们将时间存储到将在以后加载交易历史记录时使用的全局变量(历史记录中的交易索引存储在 FromI 在变量中)。

在索引中 FromI 交易前,交易品种的总持仓量等于零。

现在,我们来自 FromI 走到历史记录的尽头。,计数指定的幻数的事务量。:

staticdouble sVolume=0;
staticulong sLastTicket=0;
for(int i=FromI;i<HistoryDealsTotal();i++) // 从第一个合同到最后一个合同。
  {
   ulong ticket=HistoryDealGetTicket(i);   // 取合约的单号
   if(票)!=0)
     {
      if(HistoryDealGetString(票),DEAL_SYMBOL)==不对称的) // 指定交易品种
        {
         long PosMagic=HistoryDealGetInteger(票),DEAL_MAGIC);
         if(PosMagic==aMagic || aMagic==-1) // 指定识别号码
           {
            switch(HistoryDealGetInteger(票),DEAL_TYPE)) // 岗位增减 
                                                       // 根据合同类型
              {
               caseDEAL_TYPE_BUY:
                  sVolume+=HistoryDealGetDouble(票),DEAL_VOLUME);
                  sLastTicket=ticket;
                  break;
               caseDEAL_TYPE_SELL:
                  sVolume-=HistoryDealGetDouble(票),DEAL_VOLUME);
                  sLastTicket=ticket;
                  break;
              }
           }
        }
     }
  } 

循环结束后,我们将根据指定的幻数获得当前位置。,指定的幻数的最后一个事务文档将被存储。 sLastTicket 变量中,交易实施后,含有指定幻数的总持仓量将等于 sVolume。完成了该函数的初步工作。。

sLoadHistoryFrom、sLastTicket 和 sVolume 变量被声明为静态变量(它们在TH之后存储它们的值)。,这些值将在将来调用函数时使用。。

我们有时间(交易历史的起点)、交易单证、执行交易后的总持仓量将具有当前值。

因为时间是零。,从当前时间遍历节省的时间就足够了。,并执行交易量汇总。,持有该位置和最后一笔交易的文件。。

因此,EA 交易的总持仓量的计算是对最后几笔交易的处理:

if(!HistorySelect(sLoadHistoryFrom,TimeCurrent())) // 要求合同历史到当前时间
  {
   return(假)
  }
for(int i=HistoryDealsTotal()-1;i>=0;i--) // 从结束到前循环
  {
   ulong ticket=HistoryDealGetTicket(i); // 取一个数字
   if(票)!=0)
     {
      if(票)==sLastTicket) // 我们找到了计算好的合同。, 保存奇数并停止循环。
        {
         sLastTicket=HistoryDealGetTicket(HistoryDealsTotal()-1);
         break;
        }
      switch(HistoryDealGetInteger(票),DEAL_TYPE)) // 根据合同类型岗位增减      
        {
         caseDEAL_TYPE_BUY:
            sVolume+=HistoryDealGetDouble(票),DEAL_VOLUME);
            break;
         caseDEAL_TYPE_SELL:
            sVolume-=HistoryDealGetDouble(票),DEAL_VOLUME);
            break;
        }
     }
  }

函数的算法可以表示如下。:

完整的函数:

bool fGetPositionVolume(string aSymbol,int aMagic,double aVolume)
  {
   staticbool FirstStart=false;
   staticdouble sVolume=0;
   staticulong sLastTicket=0;
   staticdatetime sLoadHistoryFrom=0;
   // 当 EA 开始时,功能优先执行
   if(!FirstStart)
     {
      if(GlobalVariableCheck(Commom_gvp+aSymbol+"_HistStTm"))
        {
         sLoadHistoryFrom=(datetime)GlobalVariableGet(Commom_gvp+aSymbol+"_HistStTm");
        }
      else
        {
         GlobalVariableSet(Commom_gvp+aSymbol+"_HistStTm",0);
        }
      if(!HistorySelect(sLoadHistoryFrom,TimeCurrent())) // 如果你不能回来, 
                                                      // 我们将在下一个价格再重复一遍。
        {
         return(假)
        }
      double CurrentVolume=fSymbolLots(不对称的); // 持股总额
      double Sum=0;
      int FromI=0;
      int FromTicket=0;
      // 查找位置为零的最后一次。
      for(int i=HistoryDealsTotal()-1;i>=0;i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(票)!=0)
           {
            switch(HistoryDealGetInteger(票),DEAL_TYPE))
              {
               caseDEAL_TYPE_BUY:
                  Sum+=HistoryDealGetDouble(票),DEAL_VOLUME);
                  Sum=NormalizeDouble(和),2);
                  break;
               caseDEAL_TYPE_SELL:
                  Sum-=HistoryDealGetDouble(票),DEAL_VOLUME);
                  Sum=NormalizeDouble(和),2);
                  break;
              }
            if(CurrentVolume==Sum)
              {
               sLoadHistoryFrom=HistoryDealGetInteger(票),DEAL_TIME);
               GlobalVariableSet(Commom_gvp+aSymbol+"_HistStTm",sLoadHistoryFrom);
               FromI=i;
               break;
              }
           }
        }
      // 计算指定的识别号和转位的位置
      for(int i=FromI;i<HistoryDealsTotal();i++)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(票)!=0)
           {
            if(HistoryDealGetString(票),DEAL_SYMBOL)==不对称的)
              {
               long PosMagic=HistoryDealGetInteger(票),DEAL_MAGIC);
               if(PosMagic==aMagic || aMagic==-1)
                 {
                  switch(HistoryDealGetInteger(票),DEAL_TYPE))
                    {
                     caseDEAL_TYPE_BUY:
                        sVolume+=HistoryDealGetDouble(票),DEAL_VOLUME);
                        sLastTicket=ticket;
                        break;
                     caseDEAL_TYPE_SELL:
                        sVolume-=HistoryDealGetDouble(票),DEAL_VOLUME);
                        sLastTicket=ticket;
                        break;
                    }
                 }
              }
           }
        }
      FirstStart=true;
     }

   // 重新计算合同的地位 (指定交易品种和识别号)
   // , 零保持时间后
   if(!HistorySelect(sLoadHistoryFrom,TimeCurrent()))
     {
      return(假)
     }
   for(int i=HistoryDealsTotal()-1;i>=0;i--)
     {
      ulong ticket=HistoryDealGetTicket(i);
      if(票)!=0)
        {
         if(票)==sLastTicket)
           {
            sLastTicket=HistoryDealGetTicket(HistoryDealsTotal()-1);
            break;
           }
         switch(HistoryDealGetInteger(票),DEAL_TYPE))
           {
            caseDEAL_TYPE_BUY:
               sVolume+=HistoryDealGetDouble(票),DEAL_VOLUME);
               break;
            caseDEAL_TYPE_SELL:
               sVolume-=HistoryDealGetDouble(票),DEAL_VOLUME);
               break;
           }
        }
     }
   aVolume=NormalizeDouble(sVolume,2);;
   return(真)
  }

事务种类和魔术数被传递回R的函数。。如果成功,返回 true,否则返回 false。

成功时,它将请求的数量返回到传递给函数的变量。 aVolume。在函数中声明的静态变量不允许使用这个具有不同参数(交易品种和幻数)的函数。

在 MQL4 中,可以使用不同的名称创建此函数的副本。,然后复制另一对交易品种魔术麻木。,或变量 FirstStart、sVolume、sLastTicket、sLoadHistoryFrom 作为公共变量的声明 – 对于每一对交易品种-魔术数,并把它们传递给函数来解决这个问题。。

在 MQL5 中,它也可以以同样的方式实现。,但是 MQL5 有一个更方便的特点。 – 类,在这样的地方,使用类是非常合理的。。课堂时间的使用,我们必须为每一对事务创建每个类的实例-MAG。,数据将存储在每个类实例中。。

让我们发表一个声明。 PositionVolume 类。在内部功能声明为静态变量的所有变量,将宣布为 私人(私人),除了 Volume 变量外,我们不会 EA 交易直接由他们使用。。但是,只有在执行计算功能之后,我们才需要它。。我们也发表了声明。 Symbol 和 Magic 变量 – 把它们传递给函数是不可能的。,只初始化类实例。。

一个类有两个公共函数。:初始化函数和用于计算位置的函数,以及一个用于确定总持仓量的私有函数:

class PositionVolume
  {
private:
   string            pSymbol;
   int               pMagic;
   bool              pFirstStart;
   ulong             pLastTicket;
   double            pVolume;
   datetime         pLoadHistoryFrom;
   double            SymbolLots();
public:
   void Init(string aSymbol,int 阿莫伊)
     {
      pSymbol=aSymbol;
      pMagic=aMagic;
      pFirstStart=false;
      pLastTicket=0;
      pVolume=0;
     }
   bool              GetVolume(double  &aVolume);
  }; 
bool PositionVolume::GetVolume(double  &aVolume)
  {
   if(!pFirstStart)
     {
      if(GlobalVariableCheck(Commom_gvp+pSymbol+"_HistStTm"))
        {
         pLoadHistoryFrom=(datetime)GlobalVariableGet(Commom_gvp+pSymbol+"_HistStTm");
        }
      else
        {
         GlobalVariableSet(Commom_gvp+pSymbol+"_HistStTm",0);
        }
      if(!HistorySelect(pLoadHistoryFrom,TimeCurrent()))
        {
         return(假)
        }
      double CurrentVolume=fSymbolLots(pSymbol);
      double Sum=0;
      int FromI=0;
      int FromTicket=0;
      for(int i=HistoryDealsTotal()-1;i>=0;i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(票)!=0)
           {
            switch(HistoryDealGetInteger(票),DEAL_TYPE))
              {
               caseDEAL_TYPE_BUY:
                  Sum+=HistoryDealGetDouble(票),DEAL_VOLUME);
                  Sum=NormalizeDouble(和),2);
                  break;
               caseDEAL_TYPE_SELL:
                  Sum-=HistoryDealGetDouble(票),DEAL_VOLUME);
                  Sum=NormalizeDouble(和),2);
                  break;
              }
            if(CurrentVolume==Sum)
              {
               pLoadHistoryFrom=HistoryDealGetInteger(票),DEAL_TIME);
               GlobalVariableSet(Commom_gvp+pSymbol+"_HistStTm",pLoadHistoryFrom);
               FromI=i;
               break;
              }
           }
        }
      for(int i=FromI;i<HistoryDealsTotal();i++)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(票)!=0)
           {
            if(HistoryDealGetString(票),DEAL_SYMBOL)==pSymbol)
              {
               long PosMagic=HistoryDealGetInteger(票),DEAL_MAGIC);
               if(PosMagic==pMagic || pMagic==-1)
                 {
                  switch(HistoryDealGetInteger(票),DEAL_TYPE))
                    {
                     caseDEAL_TYPE_BUY:
                        pVolume+=HistoryDealGetDouble(票),DEAL_VOLUME);
                        pLastTicket=ticket;
                        break;
                     caseDEAL_TYPE_SELL:
                        pVolume-=HistoryDealGetDouble(票),DEAL_VOLUME);
                        pLastTicket=ticket;
                        break;
                    }
                 }
              }
           }
        }
      pFirstStart=true;
     }
   if(!HistorySelect(pLoadHistoryFrom,TimeCurrent()))
     {
      return(假)
     }
   for(int i=HistoryDealsTotal()-1;i>=0;i--)
     {
      ulong ticket=HistoryDealGetTicket(i);
      if(票)!=0)
        {
         if(票)==pLastTicket)
           {
            break;
           }
         if(HistoryDealGetString(票),DEAL_SYMBOL)==pSymbol)
           {
            long PosMagic=HistoryDealGetInteger(票),DEAL_MAGIC);
            if(PosMagic==pMagic || pMagic==-1)
              {
               switch(HistoryDealGetInteger(票),DEAL_TYPE))
                 {
                  caseDEAL_TYPE_BUY:
                     pVolume+=HistoryDealGetDouble(票),DEAL_VOLUME);
                     break;
                  caseDEAL_TYPE_SELL:
                     pVolume-=HistoryDealGetDouble(票),DEAL_VOLUME);
                     break;
                 }
              }
           }
        }
     }
   if(HistoryDealsTotal()>0)
     {
      pLastTicket=HistoryDealGetTicket(HistoryDealsTotal()-1);
     }
   pVolume=NormalizeDouble(pVolume,2);
   aVolume=pVolume;
   return(真)
  }
double PositionVolume::SymbolLots()
  {
   double TmpLots=0;
   for(int i=0;i<PositionsTotal();i++)
     {
      if(PositionGetSymbol(i)==pSymbol)
        {
         TmpLots=PositionGetDouble(POSITION_VOLUME);
         if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
           {
            TmpLots*=-1;
           }
         break;
        }
     }
   TmpLots=NormalizeDouble(TmpLots,2);
   return(TmpLots);
  }

对于每一对交易品种-魔术数字使用这种时间。,必须创建类实例。:

PositionVolume PosVol11;
PositionVolume PosVol12;
PositionVolume PosVol21;
PositionVolume PosVol22;

它应该在 EA 交易的 OnInit() 函数初始化,例如:

(Symbol_1,Magic_1); 
(Symbol_1,Magic_2);
(Symbol_2,Magic_1); 
(Symbol_2,Magic_2);   

之后,您可以根据指定的交易类型和M获得您的持有量。。让我们调用相应的类实例。 GetVolume 函数。

如果成功,它返回 true,并将函数赋值为函数。,通过引用传递的变量:

double Vol11;
double Vol12;
double Vol21;
double Vol22;
(Vol11);
(Vol12);
(Vol21);
(Vol22);

到这里,可以说,它已经完成了。,但是仍然有控制测试。。

4. 控制测试

测试函数的工作,我们使用四个位置的同时处理。 EA 交易:

  1. 使用周期 14 、EURUSD、幻数 1 的 RSI 指标;
  2. 使用周期 21 、EURUSD、幻数 2 的 RSI 指标;
  3. 使用周期 14 、GBPUSD、幻数 1 的 RSI 指标;
  4. 使用周期 21 、GBPUSD、幻数 2 的 RSI 指标;

幻数为 1 的 EA 交易进行 手工贸易,幻数为 2 的 EA 交易进行 手工贸易。

在进行交易时,事务量被添加到 EA 交易的变量,交易前后,使用上述函数来确定每个位置的数量。。 

如果在计算位置时出错,函数生成一个消息。。

可以在本文附录中找到。 EA 事务代码(文件名):)。

总结

EA 交易需要很多功能。,应该以在所有阶段都方便使用的方式实施这些函数。这些函数应该以最好的方式使用计算资源。。

所提出的计算仓库位置的方法满足T:启动时,它只加载最小事务历史。。在工作时,它使用最后的几个事务来重新计算当前位置。。

发表评论

电子邮件地址不会被公开。 必填项已用*标注