市场及其全局模式中的物理学

Evgeniy Ilin | 23 二月, 2021

介绍

在本文中,我们将试图了解如何将市场物理学用于自动交易。数学语言意味着从抽象性和不确定性到预测性的转变。这允许使用明确的公式或标准进行操作,而不是使用一些近似和模糊的值,以提高所创建系统的质量。我不会发明任何理论或模式,但我只会使用已知的事实,逐步将这些事实转化为数学分析的语言。没有数学,市场物理学也是不可能存在的,因为我们产生的信号就是数学实体。许多人试图在没有任何统计分析或使用非常有限的统计数据的情况下创造各种各样的理论和公式,这往往不足以得出如此大胆的结论。只有实践才是检验真理的标准。首先,我将尝试进行一些反思,然后,基于这些反思,我将创建一个专家顾问(EA),随后将进行EA测试。


价格以及它提供了什么

任何市场环境都意味着各种产品的存在,在货币市场上,产品就是货币。货币是指拥有某种产品或信息的权利,在世界范围内被设定为基准。例如,看一下 EURUSD 及其图表的当前值,当前图表值得意思是 USD/EUR = CurrentPrice. 或者: USD =  EUR*CurrentPrice, 也就是说一欧元中包含的美元数量。换言之,该值表示每种货币权重的比率,当然,假定每种货币都有某种共同的等价交换,即某种共同的商品或其他东西。价格是在订货簿中形成的,订货簿的动态性决定了价格的变动。应该永远记住,我们永远无法考虑到价格形成的所有因素。例如,俄罗斯商品期货交易所是与外汇交易市场相联系的,并且相互影响。我不是这方面的专家,但我能理解一切都是有约束的,数据通道越多越好。在我看来,最好不要深入到这样的细节中去,而应该把注意力集中在那些影响价格的简单事情上。

任何依赖关系都可以表示为许多变量的函数,就像任何报价一样。最初的价格是:

换句话说,价格是时间的函数。无法为每一对货币或任何其他工具可靠地确定函数的形式,因为这将需要无限的时间。但是这种表示形式什么都给不了我们。然而,价格具有双重性质,因为它既有可预测的成分,也有随机成分。可预测的部分不是函数本身,而是它的一阶导数。将此函数表示为某些术语是没有意义的,因为它没有用于交易的目的。但如果我们考虑它的一阶导数,有以下几点:

在这里,第一项反映了可以用数学分析的方法进行分析的部分,第二项是不可预测的部分。根据这个公式,我们可以说不可能100%准确地预测运动的大小和方向。没有必要考虑最后一项是什么,因为我们无法确定它。但是我们可以判断第一项。考虑到值函数是离散的,我们不能应用微分运算,可以假设这个项可以用不同的形式表示。但是相反,我们可以取一段时间的平均导数“st”。当应用于价格时,这将是条形图的持续时间;当应用于报价点(tick)时,它是两个报价点之间的最短时间。

换言之,我们假设价格的可预测部分可能取决于之前的条形图或刻度,以及其他货币对的价格数据、其他交易所和世界事件的数据。不过,应该理解的是,就算是这部分价格也无法100%准确预测,我们只能计算出它的一些特征。这样的特征只能是一个概率或一个随机变量的参数,如数学上的期望值、方差、标准差等数量的概率论。用数学期望操作足以使交易有利可图。经过时间和仔细思考,我们可以得出这样的结论:不仅可以用这个逻辑来分析市场。问题是,价格的可预测部分是根据市场参与者的活动而发展的。我们可以抛弃各种市场参数,除了市场参与者自己创造的因素。当然,所有这些都会导致我们的分析方法的可靠性降低,但这大大简化了模型。在这里,“st”值越小,我们的公式描述市场就越准确。

上述函数描述了当前所有未平仓买入和卖出头寸的交易量差异。这些仓位的一部分相互补偿,而其余仓位是独立的。由于仓位是开放的,它们象征着一段时间后关闭的承诺。我们都知道买会使价格上涨,卖会使价格下跌。唯一知道价格走向的方法是衡量未平仓的成交量,并估计这些仓位的方向,只考虑未平仓的市场订单。

市场的波动性实际上与这个简单的事实有关。这只是一个更普遍的头寸波动过程的特例,即多头和空头的行为。

在处理柱形时,也可以考虑到一个柱里面有4个价格,这可以给我们提供更好的公式。更多的数据意味着更准确的分析,这就是为什么必须考虑所有价格数据的原因。但是,我不喜欢计算每一个 tick,因为这样会使算法慢十倍。此外,不同经纪商的 tick 数据可能不同。相反,大多数经纪商的开盘价和收盘价几乎相同。让我们修改交易量函数以考虑所有价格数据:

我们可以给这个函数添加更多的变量,比如时间、一周中的几天、几个月和几周,但是这会产生很多与特定市场区域相关的函数,而我们的目的是确定一般的市场物理学。我们将知道它是不能被打破的,因此只要市场存在,它就可以被使用。这个公式的另一个优点是它的多货币性。

实际上,使用这种表示类型没有意义,因为我们需要确切地知道如何以及基于什么数据来构建这个函数。我们不能只写这个函数的形式并确定依赖关系。但是,这些表达式可以帮助我们初步了解如何进行分析,以及如何进行以下假设。任何一组逻辑条件最终都可以表示为这样一个函数。相反,函数本身可以转化为一组条件。我们用哪种形式并不重要,理解它才是重要的。任何算法都可以简化为一个公式。有时,将信号描述为条件或条件系统比构建超复杂函数更容易。另一个大问题是如何建立这样一个功能。

在一个真实的交易系统中,我们不能一次分析整个历史,而只能分析一段固定的时间。这种分析有4种可能的方法,我将为它们命名并解释:

第一个选项假设我们使用一个特定值或一组值。一个例子是一个指标或我们自己的公式。这种方法的优点是 MetaTrader 4/5 终端中提供了一个大型工具箱。此外,市场和网络上有许多基于流行市场理论的指标。这种方法的缺点是,在大多数情况下,我们无法根据指标的工作原理来理解。即使我们理解了,这种理解也没有任何价值。

在第二种选择中,我们不使用我们不了解的数据或没有用处的数据。相反,我们可以试着模拟市场上的订单,这样我们就知道我们的系统在某种程度上能够描述一个方向上有多少个空头头寸,另一个方向上有多少个空头头寸。这些信息可以产生必要的预测,从而从全局的角度对市场进行精确的描述。这是机器学习的唯一选择。

数学是指对一些基本规律的理解或对某些数学原理的知识,这些知识允许利用任何报价,而不管当前的市场情况如何。事实上,任何函数,包括离散函数,都具有某些可以利用的特性。当然,这里我们假设依赖不是混沌的(在我们的例子中,外汇不是混沌的,所以任何报价都可以被利用)。在下一篇文章中,我们将分析一个几乎人人都知道的原则,但是知道和能够使用是两码事。这种方法的优点是,如果我们成功地构建了一个系统,我们就不必担心它在未来的表现。 

第四种方法是最先进的方法,因为机器学习可以充分利用任何数据。你的计算能力越强,分析的质量就越高。这种方法的缺点是,它无助于理解市场物理学。优点是方法简单,以最少的时间获得最高质量的结果。但这种方法不适用于本文。


关于模式

每天的交易意味着大量的术语,每一个都有不同的重要性水平。有些术语经常被使用,尽管不是所有的交易者都明白它们的真正目的。其中一个术语是模式。我将试着用数学的语言来解释它。模式总是与特定的时间段、特定的货币对和图表周期相关联。有些模式很强,这种模式可以是多币种的,也可以是全局性的。理想的模式是圣杯。有一些说明可以应用于任何模式:

如果你仔细阅读每个属性,你就会明白模式是一个公式或一组条件,它们最准确地描述了价格在选定时间间隔内的变动。一个模式可能是随机的,特别是如果在一个很短的时间内发现或者如果相关的系统产生了过于乐观的值。了解在短期内测试系统时,发现全局模式的机会往往为零,这一点非常重要。这与样本量有关,样本越小,结果的随机性越高。 

我们已经确定了什么是模式,但是如何有效地使用模式呢?这完全取决于这种模式是如何被发现的和它的质量。如果我们不考虑利用计算能力的分析方法,那么我们就来分析。在我看来,分析无法与任何类型的机器分析竞争——即使是一个优秀的分析师团队也无法处理一台机器可以处理的数据。总之,寻找全局模式的过程需要计算能力。好吧,除了你亲眼看到明显的东西,理解它们的物理原理。


编写最简单的仓位模拟器

为了寻找全局模式,开发一个能够描述市场参与者情绪的专家顾问将是一件有趣的事情。为此,我决定尝试创建一个市场仓位的模拟器,仓位将在靠近市场边缘的价格柱中模拟。有必要假设市场参与者不同,他们订单的权重也不同。同时,应以简单的形式提出这一点,如果一个简单的原型能够取得利润,那么它的原理可以被进一步使用。

逻辑将有条件地分为3个单独的模拟和它们的任何可能的混合组合:

下订单将采用以下逻辑:

订单网格逻辑

这些网格是每个新柱的位置,旨在模拟部分市场参与者的情绪。旧订单网格的状态将根据图表上显示的新柱进行更新。这种方法不是很精确,但是每一订单模式的模拟会导致没完没了的计算。而且,我不太相信订单点(tick)。

相对交易量分布有两种类型,衰减和均匀分布,但仅限于止损和限价订单,市场订单是均匀分布的。如果从长远的角度来看,还可以扩大分布的类型。图示如下:

相对交易量填充类型

在这里,表示订单的线的长度与这个订单的交易量成比例。我认为这样的演示图对每个人来说都是简单易懂的。

在这种情况下,一切都可以使用面向对象的方法来完成。让我们从描述编号列表开始:

enum CLOSE_MODE// how to close orders
   {
   CLOSE_FAST,// fast
   CLOSE_QUALITY// wait for an opposite signal
   };

enum WORK_MODE// operation mode
   {
   MODE_SIMPLE,// slow mode
   MODE_FAST// fast mode
   };

enum ENUM_GRID_WEIGHT//weight fill type for limit and stop orders
   {
   WEIGHT_DECREASE,// with attenuation if moving from the price
   WEIGHT_SAME// the same for the entire grid
   };

enum ENUM_STATUS_ORDER// statuses of orders or positions
   {
   STATUS_VIRTUAL,// stop or limit order
   STATUS_MARKET,// market order
   STATUS_ABORTED// canceled stop or limit order
   };

模拟器将在两种模式下工作,慢速和快速。慢模式主要用于启动阶段的分析,在启动阶段分析中,计算是在最接近市场烛形的前“n”个烛形中进行的。在快速模式下,只对新出现的烛形进行计算。但是,简单的方法是不够的。为了提高算法速度,还需要额外的功能。相当大的计算是在专家顾问初始化时执行的。但是我们只需要在每个烛形上更新一个新烛形的模拟。根据与当前市场价格(也就是每个柱的 Open[i]) 之间的距离,将有两种类型的数量分布,即限价和止损订单。这是因为止损和限价指令的网格在每个柱都打开,具有不同的分布和权重。一段时间后,止损和限价订单变成市场订单。如果在规定的时间内价格未达到要求的价格,止损和限价订单将被取消。

让我们开始从简单到复杂地构建这个模拟,逐渐地把所有的东西放在一起。首先,定义什么是订单:

struct Order// structure symbolizing a player's order
   {
   public:
   double WantedPrice;// desired open price
   int BarsExpirationOpen;// If the order remains for certain number of bars, the player can't wait any more and cancels the order
   int BarsExpirationClose;//If this is a market order and the player does not want to wait, he closes the position
   double UpPriceToClose;//The total upward price movement at which the player closes the order (points)
   double LowPriceToClose;//The total downward price movement at which the player closes the order 
   double VolumeAlpha;// current volume equivalent [0...1]
   double VolumeStart;// starting volume equivalent [0...1]
   int IndexMarket;// the index of the bar on which the virtual market turned into market
   ENUM_STATUS_ORDER Status;// order status
   Order(ENUM_STATUS_ORDER S)// constructor that creates a certain order
      {
      Status=S;
      }
   };

参数不多,每个参数对一般算法都很重要。许多字段适用于任何订单,而其中一些字段仅适用于限价或止损订单。例如,期望价格是市场订单的开盘价,而它恰恰是限价和止损订单的期望价格。

上下收盘价作为止损水平。同时,我们假设网格订单不是完全的订单,这个订单包含了一大堆订单,而它们只是合并成一个订单,以一定的价格以一定的交易量打开。起始量和当前量的变量告诉我们在特定条的特定级别上订单有多重要。

起始交易量是订单设置时的交易量,当前交易量是事件进一步发展时的交易量,重要的是买卖订单数量的比例,而不是某些订单的利润,交易信号将基于这些考虑产生。当然,我们可以提出其他信号,但这需要一些其他的考虑。还要注意的是,订单达到一定水平时不会关闭,但关闭会在每个柱逐渐发生,以尽量模拟事件的真实发展。

接下来,我们需要为每个柱定义存储。柱将存储在此柱打开的订单:

class OrderBox// Order box of a specific bar
   {
   public:
   Order BuyStopOrders[];
   Order BuyLimitOrders[];
   Order BuyMarketOrders[];
   Order SellStopOrders[];
   Order SellLimitOrders[];
   Order SellMarketOrders[];
   
   OrderBox(int OrdersToOneBar)
      {
      ArrayResize(BuyStopOrders,OrdersToOneBar);
      ArrayResize(BuyLimitOrders,OrdersToOneBar);
      ArrayResize(BuyMarketOrders,OrdersToOneBar);
      ArrayResize(SellStopOrders,OrdersToOneBar);
      ArrayResize(SellLimitOrders,OrdersToOneBar);
      ArrayResize(SellMarketOrders,OrdersToOneBar);      
      for ( int i=0; i<ArraySize(BuyStopOrders); i++ )// Set types for all orders
         {
         BuyStopOrders[i]=Order(STATUS_VIRTUAL);
         BuyLimitOrders[i]=Order(STATUS_VIRTUAL);
         BuyMarketOrders[i]=Order(STATUS_MARKET);
         SellStopOrders[i]=Order(STATUS_VIRTUAL);
         SellLimitOrders[i]=Order(STATUS_VIRTUAL);
         SellMarketOrders[i]=Order(STATUS_MARKET);         
         }
      }
   };

这里一切都很简单,六种订单类型,由数组描述,这样做是为了避免混淆。这个类不会以它的纯形式使用,它只是一个砖形。

接下来,将所有柱的公共存储定义为一个对象,稍后将从中执行继承。这里的技术非常简单。

class BarBox// Storage for all orders
   {
   protected:
   OrderBox BarOrders[];
   
   BarBox(int OrdersToOneBar,int BarsTotal)
      {
      ArrayResize(BarOrders,BarsTotal);
      for ( int i=0; i<ArraySize(BarOrders); i++ )// Set types for all orders
         {
         BarOrders[i]=OrderBox(OrdersToOneBar);
         }
      }   
   };

这只是一个存储柱形数据(订单),没有更多。到目前为止,一切都很简单。到了后面,事情会变得更加复杂一些。

在为订单确定了方便的数据存储之后,我们需要确定如何以及根据哪些规则创建订单,特定订单类型的重要性等。为此,我创建了以下类:

class PositionGenerator:public BarBox// Inherit class from the box to avoid the need to include it as an internal member and to avoid multiple references
   {
   protected:
   double VolumeAlphaStop;// importance of volumes of STOP orders
   double VolumeAlphaLimit;// importance of volumes of LIMIT orders
   double VolumeAlphaMarket;// importance of volumes of MARKET orders
   double HalfCorridorLimitStop;// step of the corridor of Limit and Stop orders in points
   int ExpirationOpenLimit;// after how many bars the volumes of the grid of limit orders for opening will completely attenuate
   int ExpirationOpenStop;// after how many bars the volumes of the grid of stop orders for opening will completely attenuate
   int ExpirationClose;// after how many bars the volumes of orders for closing will completely attenuate
   int ProfitPointsCorridorPart;// half corridor size for the profit of all orders
   int LossPointsCorridorPart;// half corridor size for the loss of all orders
   int OrdersToOneBar;// orders of one type per 1 bar
   ENUM_GRID_WEIGHT WeightStopLimitFillingType;
   
   PositionGenerator( ENUM_GRID_WEIGHT WeightStopLimitFillingType0
                     ,int HalfCorridorLimitStop0,int OrdersToOneBar0,int BarsTotal0
                     ,int ExpirationOpenLimit0,int ExpirationOpenStop0
                     ,int ExpirationClose0
                     ,int ProfitPointsCorridorPart0,int LossPointsCorridorPart0
                     ,double VolumeAlphaStop0,double VolumeAlphaLimit0,double VolumeAlphaMarket0) 
                     : BarBox(OrdersToOneBar0,BarsTotal0)
      {
      VolumeAlphaStop=VolumeAlphaStop0;
      VolumeAlphaLimit=VolumeAlphaLimit0;
      VolumeAlphaMarket=VolumeAlphaMarket0;
      OrdersToOneBar=OrdersToOneBar0;
      HalfCorridorLimitStop=double(HalfCorridorLimitStop0)/double(OrdersToOneBar);
      ExpirationOpenLimit=ExpirationOpenLimit0;
      ExpirationOpenStop=ExpirationOpenStop0;
      ExpirationClose=ExpirationClose0;
      ProfitPointsCorridorPart=ProfitPointsCorridorPart0;
      LossPointsCorridorPart=LossPointsCorridorPart0;
      OrdersToOneBar=OrdersToOneBar0;
      WeightStopLimitFillingType=WeightStopLimitFillingType0;
      }
   private:
   
   double CalcVolumeDecrease(double TypeWeight,int i,int size)// attenuation volume
      {
      if ( size > 1 )
         {
         double K=1.0/(1.0-size);
         double C=1.0;
         return TypeWeight*K*i+C;
         }
      else return 0.0;
      }
      
   double CalcVolumeSimple(double TypeWeight)// equal volume
      {
      return TypeWeight;
      }
   
   void RebuildStops()// rebuild stop orders
      {
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
         {
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyStopOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
            BarOrders[j].BuyStopOrders[i].WantedPrice=Open[j+1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].BuyStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].BuyStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
            BarOrders[j].BuyStopOrders[i].VolumeStart=BarOrders[j].BuyStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyStopOrders[i].UpPriceToClose=BarOrders[j].BuyStopOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyStopOrders[i].LowPriceToClose=BarOrders[j].BuyStopOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
            BarOrders[j].BuyStopOrders[i].BarsExpirationClose=ExpirationClose;
       
            BarOrders[j].SellStopOrders[i].Status=STATUS_VIRTUAL;
            BarOrders[j].SellStopOrders[i].WantedPrice=Open[j+1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].SellStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].SellStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
            BarOrders[j].SellStopOrders[i].VolumeStart=BarOrders[j].SellStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellStopOrders[i].UpPriceToClose=BarOrders[j].SellStopOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellStopOrders[i].LowPriceToClose=BarOrders[j].SellStopOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
            BarOrders[j].SellStopOrders[i].BarsExpirationClose=ExpirationClose;                    
            }         
         }      
      }
      
   void RebuildLimits()// rebuild limit orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
         {
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyLimitOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
            BarOrders[j].BuyLimitOrders[i].WantedPrice=Open[j+1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].BuyLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].BuyLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
            BarOrders[j].BuyLimitOrders[i].VolumeStart=BarOrders[j].BuyLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyLimitOrders[i].UpPriceToClose=BarOrders[j].BuyLimitOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyLimitOrders[i].LowPriceToClose=BarOrders[j].BuyLimitOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
            BarOrders[j].BuyLimitOrders[i].BarsExpirationClose=ExpirationClose;            
       
            BarOrders[j].SellLimitOrders[i].Status=STATUS_VIRTUAL;
            BarOrders[j].SellLimitOrders[i].WantedPrice=Open[j+1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].SellLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].SellLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
            BarOrders[j].SellLimitOrders[i].VolumeStart=BarOrders[j].SellLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellLimitOrders[i].UpPriceToClose=BarOrders[j].SellLimitOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellLimitOrders[i].LowPriceToClose=BarOrders[j].SellLimitOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
            BarOrders[j].SellLimitOrders[i].BarsExpirationClose=ExpirationClose;
            }         
         }      
      }
      
   void RebuildMarkets()// rebuild market orders
      {
      int size=ArraySize(BarOrders[0].BuyMarketOrders);
      double MarketStep;
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         MarketStep=(High[j+1]-Low[j+1])/double(OrdersToOneBar);
            
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyMarketOrders[i].Status=STATUS_MARKET;// reset status to initial
            BarOrders[j].BuyMarketOrders[i].WantedPrice=Low[j+1]+MarketStep*i;// prices of the order grid
            BarOrders[j].BuyMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
            BarOrders[j].BuyMarketOrders[i].VolumeStart=BarOrders[j].BuyMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyMarketOrders[i].UpPriceToClose=BarOrders[j].BuyMarketOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyMarketOrders[i].LowPriceToClose=BarOrders[j].BuyMarketOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyMarketOrders[i].BarsExpirationClose=ExpirationClose;
               
            BarOrders[j].SellMarketOrders[i].Status=STATUS_MARKET;
            BarOrders[j].SellMarketOrders[i].WantedPrice=High[j+1]-MarketStep*i;// prices of the order grid
            BarOrders[j].SellMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
            BarOrders[j].SellMarketOrders[i].VolumeStart=BarOrders[j].SellMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellMarketOrders[i].UpPriceToClose=BarOrders[j].SellMarketOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellMarketOrders[i].LowPriceToClose=BarOrders[j].SellMarketOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellMarketOrders[i].BarsExpirationClose=ExpirationClose;
            } 
         }      
      }

   ///// Fast methods
   void RebuildStopsFast()// rebuild stop orders
      {
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyStopOrders[i]=BarOrders[j-1].BuyStopOrders[i];
            BarOrders[j].SellStopOrders[i]=BarOrders[j-1].SellStopOrders[i];
            BarOrders[j].SellStopOrders[i].IndexMarket++;
            }
         }
         
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyStopOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
         BarOrders[0].BuyStopOrders[i].WantedPrice=Close[1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].BuyStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].BuyStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
         BarOrders[0].BuyStopOrders[i].VolumeStart=BarOrders[0].BuyStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyStopOrders[i].UpPriceToClose=BarOrders[0].BuyStopOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;//upper border to close
         BarOrders[0].BuyStopOrders[i].LowPriceToClose=BarOrders[0].BuyStopOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
         BarOrders[0].BuyStopOrders[i].BarsExpirationClose=ExpirationClose;
       
         BarOrders[0].SellStopOrders[i].Status=STATUS_VIRTUAL;
         BarOrders[0].SellStopOrders[i].WantedPrice=Close[1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].SellStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].SellStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
         BarOrders[0].SellStopOrders[i].VolumeStart=BarOrders[0].SellStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellStopOrders[i].UpPriceToClose=BarOrders[0].SellStopOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellStopOrders[i].LowPriceToClose=BarOrders[0].SellStopOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
         BarOrders[0].SellStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
         BarOrders[0].SellStopOrders[i].BarsExpirationClose=ExpirationClose;                    
         }               
      }
      
   void RebuildLimitsFast()// rebuild limit orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyLimitOrders[i]=BarOrders[j-1].BuyLimitOrders[i];
            BarOrders[j].SellLimitOrders[i]=BarOrders[j-1].SellLimitOrders[i];
            BarOrders[j].SellLimitOrders[i].IndexMarket++;
            }         
         }
      
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyLimitOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
         BarOrders[0].BuyLimitOrders[i].WantedPrice=Open[1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].BuyLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].BuyLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
         BarOrders[0].BuyLimitOrders[i].VolumeStart=BarOrders[0].BuyLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyLimitOrders[i].UpPriceToClose=BarOrders[0].BuyLimitOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
         BarOrders[0].BuyLimitOrders[i].LowPriceToClose=BarOrders[0].BuyLimitOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
         BarOrders[0].BuyLimitOrders[i].BarsExpirationClose=ExpirationClose;            
       
         BarOrders[0].SellLimitOrders[i].Status=STATUS_VIRTUAL;
         BarOrders[0].SellLimitOrders[i].WantedPrice=Open[1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].SellLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].SellLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
         BarOrders[0].SellLimitOrders[i].VolumeStart=BarOrders[0].SellLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellLimitOrders[i].UpPriceToClose=BarOrders[0].SellLimitOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellLimitOrders[i].LowPriceToClose=BarOrders[0].SellLimitOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower order to close
         BarOrders[0].SellLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
         BarOrders[0].SellLimitOrders[i].BarsExpirationClose=ExpirationClose;
         }        
      }
      
   void RebuildMarketsFast()// rebuild market orders
      {
      int size=ArraySize(BarOrders[0].BuyMarketOrders);
      double MarketStep;
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyMarketOrders[i]=BarOrders[j-1].BuyMarketOrders[i];
            BarOrders[j].SellMarketOrders[i]=BarOrders[j-1].SellMarketOrders[i];
            }         
         }
      MarketStep=(High[1]-Low[1])/double(OrdersToOneBar);
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyMarketOrders[i].Status=STATUS_MARKET;// reset status to initial
         BarOrders[0].BuyMarketOrders[i].WantedPrice=Low[1]+MarketStep*i;// prices of the order grid
         BarOrders[0].BuyMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
         BarOrders[0].BuyMarketOrders[i].VolumeStart=BarOrders[0].BuyMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyMarketOrders[i].UpPriceToClose=BarOrders[0].BuyMarketOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
         BarOrders[0].BuyMarketOrders[i].LowPriceToClose=BarOrders[0].BuyMarketOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyMarketOrders[i].BarsExpirationClose=ExpirationClose;
               
         BarOrders[0].SellMarketOrders[i].Status=STATUS_MARKET;
         BarOrders[0].SellMarketOrders[i].WantedPrice=High[1]-MarketStep*i;// prices of the order grid
         BarOrders[0].SellMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
         BarOrders[0].SellMarketOrders[i].VolumeStart=BarOrders[0].SellMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellMarketOrders[i].UpPriceToClose=BarOrders[0].SellMarketOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellMarketOrders[i].LowPriceToClose=BarOrders[0].SellMarketOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
         BarOrders[0].SellMarketOrders[i].BarsExpirationClose=ExpirationClose;
         }         
      }   
   
   protected:
   void CreateNewOrders()// create new orders at each candlestick
      {
      if ( VolumeAlphaStop != 0.0 ) RebuildStops();
      if ( VolumeAlphaLimit != 0.0 ) RebuildLimits();
      if ( VolumeAlphaMarket != 0.0 ) RebuildMarkets();
      }
   
   void CreateNewOrdersFast()//
      {
      if ( VolumeAlphaStop != 0.0 ) RebuildStopsFast();
      if ( VolumeAlphaLimit != 0.0 ) RebuildLimitsFast();
      if ( VolumeAlphaMarket != 0.0 ) RebuildMarketsFast();      
      }
   
   public:   
   virtual void Update()// state updating function (will be expanded in child classes)
      {
      CreateNewOrders();
      }
      
   virtual void UpdateFast()// fast state update
      {
      CreateNewOrdersFast();
      }      
   };

实际上,这个类只创建Update()和UpdateFast()方法的一个实现,这两个方法很相似,唯一的区别是后者要快得多。这些方法在每个柱上创建新的订单并删除旧的订单,从而为下一个类准备数据,该类将模拟订单生命周期。所有必需的订单参数都在此类中分配,包括类型、未平仓价格、交易量和其他进一步操作所需的重要参数。

下一个类实现订单模拟过程,以及交易所需参数的计算,在此基础上生成信号:

class Simulation:public PositionGenerator // then assemble a simulator of positions (inherited from the position generator)
   {// market parameter calculations will also performed in this class
   protected:
   double BuyPercent;// percent of open Buy positions
   double SellPercent;// percent of open Sell positions
   double StartVolume;// starting total volume of open Buy positions (the same for Buys and Sells)
   double RelativeVolume;// relative volume
   double SummVolumeBuy;// total volume for Buys
   double SummVolumeSell;// total volume for Sells
   
   public:   
   Simulation( ENUM_GRID_WEIGHT WeightStopLimitFillingType0
                     ,int HalfCorridorLimitStop0,int OrdersToOneBar0,int BarsTotal0
                     ,int ExpirationOpenLimit0,int ExpirationOpenStop0
                     ,int ExpirationClose0
                     ,int ProfitPointsCorridorPart0,int LossPointsCorridorPart0
                     ,double VolumeAlphaStop0,double VolumeAlphaLimit0,double VolumeAlphaMarket0) 
   :PositionGenerator(WeightStopLimitFillingType0
                     ,HalfCorridorLimitStop0,OrdersToOneBar0,BarsTotal0
                     ,ExpirationOpenLimit0,ExpirationOpenStop0
                     ,ExpirationClose0
                     ,ProfitPointsCorridorPart0,LossPointsCorridorPart0
                     ,VolumeAlphaStop0,VolumeAlphaLimit0,VolumeAlphaMarket0) 
      {
      CreateNewOrders();
      CalculateStartVolume();// calculate starting volumes
      UpdateVirtual();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarket();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }

   double GetBuyPercent()// get the percentage of open Buy deals
      {
      return BuyPercent;
      }
      
   double GetSellPercent()// get the percentage of open Sell deals
      {
      return SellPercent;
      }
      
   double GetRelativeVolume()// get relative volume
      {
      return RelativeVolume;
      }

   virtual void Update() override
      {
      PositionGenerator::Update();// call everything that was before
      UpdateVirtual();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarket();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }
      
   virtual void UpdateFast() override
      {
      PositionGenerator::UpdateFast();// call everything that was before
      UpdateVirtualFast();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarketFast();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }   
      
   private:
   
   void UpdateVirtual()// update the status of virtual orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int i=SizeBarOrders; i>0; i-- )// update the state of limit orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].BuyLimitOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].BuyLimitOrders[k].WantedPrice >= Low[i] )// if the order is virtual and is inside a candlestick, then it turns into a market one
                     {
                     BarOrders[j].BuyLimitOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].BuyLimitOrders[k].IndexMarket = i;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].SellLimitOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].SellLimitOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].SellLimitOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].SellLimitOrders[k].IndexMarket = i;
                     } 
                 
                  /////// Check for interest expiration of limit players
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].IndexMarket - 1 >= BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen )
                     BarOrders[j].BuyLimitOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                        }
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].IndexMarket - 1 >= BarOrders[j].SellLimitOrders[k].BarsExpirationOpen  )
                     BarOrders[j].SellLimitOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;                  
                        }
                     } 
                  }
               }         
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int i=SizeBarOrders; i>0; i-- )// update the state of limit orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].SellStopOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].SellStopOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].SellStopOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].SellStopOrders[k].IndexMarket = i;
                     }
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].BuyStopOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].BuyStopOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].BuyStopOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].BuyStopOrders[k].IndexMarket = i;
                     }
                  
                  /////// Check for interest expiration of stop and limit players
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].IndexMarket - 1 >= BarOrders[j].BuyStopOrders[k].BarsExpirationOpen  )
                     BarOrders[j].BuyStopOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;                  
                        } 
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].IndexMarket - 1 >= BarOrders[j].SellStopOrders[k].BarsExpirationOpen  )
                     BarOrders[j].SellStopOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;                     
                        }
                     }                                                                       
                  }
               }         
            }
         }               
      }
      
   void UpdateMarket()// update the status of market orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyLimitOrders[k].UpPriceToClose-BarOrders[j].BuyLimitOrders[k].WantedPrice);// with profit
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyLimitOrders[k].WantedPrice-BarOrders[j].BuyLimitOrders[k].LowPriceToClose);// with loss
                        }
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellLimitOrders[k].WantedPrice-BarOrders[j].SellLimitOrders[k].LowPriceToClose);//with profit
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellLimitOrders[k].UpPriceToClose-BarOrders[j].SellLimitOrders[k].WantedPrice);//with loss
                        }
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                     } 
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                     } 
                  }
               }         
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyStopOrders[k].UpPriceToClose-BarOrders[j].BuyStopOrders[k].WantedPrice);// with profit
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyStopOrders[k].WantedPrice-BarOrders[j].BuyStopOrders[k].LowPriceToClose);// with loss
                        }
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellStopOrders[k].WantedPrice-BarOrders[j].SellStopOrders[k].LowPriceToClose);//with profit
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellStopOrders[k].UpPriceToClose-BarOrders[j].SellStopOrders[k].WantedPrice);//with loss
                        }
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                     }
               
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                     }
                  }
               }         
            }
         }
         
      if ( VolumeAlphaMarket != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  /// For obviously market positions
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyMarketOrders[k].UpPriceToClose-BarOrders[j].BuyMarketOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyMarketOrders[k].WantedPrice-BarOrders[j].BuyMarketOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                              
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellMarketOrders[k].WantedPrice-BarOrders[j].SellMarketOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellMarketOrders[k].UpPriceToClose-BarOrders[j].SellMarketOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;                  
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
              
                  /// For obviously market positions
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart/double(BarOrders[j].BuyMarketOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart/double(BarOrders[j].SellMarketOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;               
                  //
                  }
               }         
            }
         }
      }
      
   /// fast methods****   
   void UpdateVirtualFast()// update the status of virtual orders
      {
      int SizeBarOrders=ArraySize(BarOrders);
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].BuyLimitOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].BuyLimitOrders[k].WantedPrice >= Low[1] )// if the order is virtual and is inside a candlestick, then it turns into a market one
                  {
                  BarOrders[j].BuyLimitOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].BuyLimitOrders[k].IndexMarket = 1;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].SellLimitOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].SellLimitOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].SellLimitOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].SellLimitOrders[k].IndexMarket = 1;
                  } 
                  
               /////// Check for interest expiration of limit players
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].IndexMarket - 1 >= BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen )
                  BarOrders[j].BuyLimitOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].IndexMarket - 1 >= BarOrders[j].SellLimitOrders[k].BarsExpirationOpen  )
                  BarOrders[j].SellLimitOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;                  
                     }
                  } 
               }
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {       
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].SellStopOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].SellStopOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].SellStopOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].SellStopOrders[k].IndexMarket = 1;
                  }
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].BuyStopOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].BuyStopOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].BuyStopOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].BuyStopOrders[k].IndexMarket = 1;
                  }
                  
               /////// Check for interest expiration of stop players
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].IndexMarket - 1 >= BarOrders[j].BuyStopOrders[k].BarsExpirationOpen  )
                  BarOrders[j].BuyStopOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;                  
                     } 
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].IndexMarket - 1 >= BarOrders[j].SellStopOrders[k].BarsExpirationOpen  )
                  BarOrders[j].SellStopOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;                     
                     }
                  }                                                                       
               }
            }
         }         
      }
      
   void UpdateMarketFast()// update the status of market orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               // Block for closing when prices change
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyLimitOrders[k].UpPriceToClose-BarOrders[j].BuyLimitOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyLimitOrders[k].WantedPrice-BarOrders[j].BuyLimitOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellLimitOrders[k].WantedPrice-BarOrders[j].SellLimitOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellLimitOrders[k].UpPriceToClose-BarOrders[j].SellLimitOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                  } 
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                  } 
               //
               }
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               // Block for closing when prices change
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyStopOrders[k].UpPriceToClose-BarOrders[j].BuyStopOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyStopOrders[k].WantedPrice-BarOrders[j].BuyStopOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellStopOrders[k].WantedPrice-BarOrders[j].SellStopOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellStopOrders[k].UpPriceToClose-BarOrders[j].SellStopOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                  }
               
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                  }
               //
               }
            }
         }
         
       if ( VolumeAlphaMarket != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               /// For obviously market positions
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                  {
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyMarketOrders[k].UpPriceToClose-BarOrders[j].BuyMarketOrders[k].WantedPrice);// with profit
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyMarketOrders[k].WantedPrice-BarOrders[j].BuyMarketOrders[k].LowPriceToClose);// with loss
                  }
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                              
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                  {
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellMarketOrders[k].WantedPrice-BarOrders[j].SellMarketOrders[k].LowPriceToClose);// with profit
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellMarketOrders[k].UpPriceToClose-BarOrders[j].SellMarketOrders[k].WantedPrice);// with loss
                  }
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;                  
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
             
               /// For obviously market positions
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
               BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart/double(BarOrders[j].BuyMarketOrders[k].BarsExpirationClose);
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
               BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart/double(BarOrders[j].SellMarketOrders[k].BarsExpirationClose);
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;               
               //
               }
            }
         }                          
      }      
   ///******
      
   void CalculateStartVolume()// calculate the starting total volume of all positions (relative to it we will estimate market fullness)
      {
      StartVolume=0;
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyStopOrders[i].VolumeStart;
               }
            }        
         }
         
      if ( VolumeAlphaLimit != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyLimitOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyLimitOrders[i].VolumeStart;
               }         
            }
         }
         
      if ( VolumeAlphaMarket != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyMarketOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyMarketOrders[i].VolumeStart;
               }         
            }
         }         
      }
      
   void CalculateCurrentVolume()// calculate the current total volume of all positions
      {
      SummVolumeBuy=0;
      SummVolumeSell=0;
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               if ( BarOrders[j].BuyStopOrders[i].Status == STATUS_MARKET )
               SummVolumeBuy+=BarOrders[j].BuyStopOrders[i].VolumeAlpha;
               if ( BarOrders[j].SellStopOrders[i].Status == STATUS_MARKET )
               SummVolumeSell+=BarOrders[j].SellStopOrders[i].VolumeAlpha;            
               }         
            }
         }
      
      if ( VolumeAlphaLimit != 0.0 )
         {   
         size=ArraySize(BarOrders[0].BuyLimitOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               if ( BarOrders[j].BuyLimitOrders[i].Status == STATUS_MARKET )
               SummVolumeBuy+=BarOrders[j].BuyLimitOrders[i].VolumeAlpha;
               if ( BarOrders[j].SellLimitOrders[i].Status == STATUS_MARKET )
               SummVolumeSell+=BarOrders[j].SellLimitOrders[i].VolumeAlpha;            
               }         
            }
         }
      
      if ( VolumeAlphaMarket != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyMarketOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               SummVolumeBuy+=BarOrders[j].BuyMarketOrders[i].VolumeAlpha;
               SummVolumeSell+=BarOrders[j].SellMarketOrders[i].VolumeAlpha;
               }         
            }
         }         
      }
      
   void CalculatePercent()// calculate the percentage of Buys and Sells relative to all positions
      {
      if ( (SummVolumeBuy+SummVolumeSell) != 0.0 ) BuyPercent=100.0*SummVolumeBuy/(SummVolumeBuy+SummVolumeSell);
      else BuyPercent=50;
      if ( (SummVolumeBuy+SummVolumeSell) != 0.0 ) SellPercent=100.0*SummVolumeSell/(SummVolumeBuy+SummVolumeSell);
      else SellPercent=50;
      }      
      
   void CalculateRelativeVolume()// calculate relative volumes of Buys and Sells (calculate only uncovered part of positions)
      {
      if ( SummVolumeBuy >= SummVolumeSell ) RelativeVolume=(SummVolumeBuy-SummVolumeSell)/StartVolume;
      else RelativeVolume=(SummVolumeSell-SummVolumeBuy)/StartVolume;
      }                   
   
   };

整个代码对 MetaTrader 4 和 MetaTrader 5 都有效,这些类可以在两种平台上编译。当然,在 MetaTrader 5 中,您应该提前实现预定义的数组,与MQL4中相同。我不在这里提供这个代码了,您可以在附加的源代码中查看它。我的代码不是很原创。我们现在需要做的就是实现负责交易的变量和相关功能。两个终端的专家顾问附在下面。

代码是非常资源密集型的,这就是为什么我组织缓慢的逻辑实现开始分析和快速的柱的工作分开来实现。我所有的专家顾问都根据柱形工作,以避免依赖人工产生的价格点或者每一价格点模式测试引起的其他不良后果。当然,我们可以完全避免慢速功能,但在这种情况下,就没有起始阶段的分析了。此外,我不喜欢在类主体之外实现函数,因为在我看来,这会破坏场景的完整性。

最后一个类构造函数将接受以下参数,这些参数将作为输入。如果您愿意,可以进行许多这样的模拟,因为它只是一个类实例:

input bool bPrintE=false;// print market parameters
input CLOSE_MODE CloseModeE=CLOSE_FAST;// order closing mode
input WORK_MODE ModeE=MODE_SIMPLE;// simulation mode
input ENUM_GRID_WEIGHT WeightFillingE=WEIGHT_SAME;// weight distribution type
input double LimitVolumeE=0.5;// significance of limit orders
input double StopVolumeE=0.5;// significance of stop orders
input double MarketVolume=0.5;// significance of market orders
input int ExpirationBars=100;// bars for full expiration of open orders
input int ExpirationOpenStopBars=1000;// patience of a stop player in bars, after which the order is canceled
input int ExpirationOpenLimitBars=1000;// patience of a limit player in bars, after which the order is canceled
input int ProfitPointsCloseE=200;// points to close with profit
input int LossPointsCloseE=400;// points to close with loss
input int HalfCorridorE=500;// half-corridor for limit and stop orders
input int OrdersToOneBarE=50;// orders for half-grid per 1 bar
input int BarsE=250;// bars for analysis
input double MinPercentE=60;// minimum superiority of one trading side in percentage 
input double MaxPercentE=80;// maximum percentage
input double MinRelativeVolumeE=0.0001;// minimum market filling [0...1]
input double MaxRelativeVolumeE=1.00;// maximum market filling [0...1]

我不会在这里提供与交易相关的变量,因为一切都简单明了。 

以下是我实现交易的功能:

void Trade()
   {
   if ( Area0 == NULL )
      {
      CalcAllMQL5Values();
      Area0 = new Simulation(WeightFillingE,HalfCorridorE,OrdersToOneBarE,BarsE
       ,ExpirationOpenLimitBars,ExpirationOpenStopBars,ExpirationBars,ProfitPointsCloseE,LossPointsCloseE
       ,StopVolumeE,LimitVolumeE,MarketVolume);      
      }
   
   switch(ModeE)
      {
      case MODE_SIMPLE:
         Area0.Update();// update simulation
      case MODE_FAST:
         Area0.UpdateFast();// fast update simulation
      }
   
   if (bPrintE)
      {
      Print("BuyPercent= ",Area0.GetBuyPercent());
      Print("SellPercent= ",Area0.GetSellPercent());
      Print("RelativeVolume= ",Area0.GetRelativeVolume());
      }
      
   if ( CloseModeE == CLOSE_FAST && Area0.GetBuyPercent() > 50.0 )
      {
      if ( !bInvert ) CloseBuyF();
      else CloseSellF();
      }
      
   if ( CloseModeE == CLOSE_FAST && Area0.GetSellPercent() > 50.0 )
      {
      if ( !bInvert ) CloseSellF();
      else CloseBuyF();
      }      
      
   if ( Area0.GetBuyPercent() > MinPercentE && Area0.GetBuyPercent() < MaxPercentE 
   && Area0.GetRelativeVolume() >= MinRelativeVolumeE && Area0.GetRelativeVolume() <= MaxRelativeVolumeE )
      {
      if ( !bInvert )
         {
         CloseBuyF();
         SellF();
         }
      else
         {
         CloseSellF();
         BuyF();
         }   
      }
      
   if ( Area0.GetSellPercent() > MinPercentE && Area0.GetSellPercent() < MaxPercentE 
   && Area0.GetRelativeVolume() >= MinRelativeVolumeE && Area0.GetRelativeVolume() <= MaxRelativeVolumeE )
      {
      if ( !bInvert )    
         {
         CloseSellF();
         BuyF();
         }  
      else
         {
         CloseBuyF();
         SellF();
         }
      }
   }

如果需要的话,可以创造更好的交易条件和更复杂的功能,但到目前为止,我并不认为这有什么意义。我总是试图把交易和逻辑部分分开。逻辑在对象中实现,模拟对象在第一次触发时在交易函数中动态创建;在去初始化过程中删除。这是因为MQL5中的预定义数组不可用,必须人工创建它们以确保类操作与MQL4类似。


如何找到合适的设置?

根据我的经验,我可以说最好是手动选择设置。此外,我建议在第一阶段忽略在低时间段运行的专家顾问的点差,并具有较小的数学期望-这将有助于您在一开始就不要错过有效迹象。MetaTrader 4 非常适合这个目的。一个成功的搜索总是紧跟着修订、编辑等,努力增加最终的数学期望和利润系数(信号强度)。此外,理想情况下,输入数据的结构应允许独立的操作模式。换句话说,一个设置应该对系统性能有最独立的影响,尽管其他设置的值不同。这种方法可以通过设置平衡设置来增强整体信号,平衡设置将所有找到的信号组合在一起。这样的实现并不总是可能的,但是在我们的例子中,它是适用的,因为我们分别分析每个订单类型。


测试专家顾问

这个专家顾问是从头开始写的,没有任何准备。所以这个EA代码对我来说是新的。我有一个类似的EA,但它更简单,有一个完全不同的逻辑。我想强调这一点,因为这篇文章的目的是要表明,任何有一些正确的基础知识的想法,即使它没有完全描述市场物理,也有非常高的机会表现出一些成效。如果系统显示出基本的性能能力,我们就可以测试它,找到在这个系统中起作用的东西,并进入市场理解的下一个层次。下一个层次假设你将自己开发更好质量的专家顾问,

在测试专家顾问时,我不得不花几天时间耐心地选择交易参数。每件事都很枯燥和漫长,但我设法找到了有效的设置。当然,这些设置非常弱,仅使用一种订单类型执行模拟,但这是故意的。因为最好单独分析特定的订单类型如何影响信号,然后尝试模拟其他订单类型。以下是我在 MetaTrader 4 中的结果:

EURUSD 2010.01.01 -2020.11.01

我首先为 MetaTrader 4 创建了一个版本,并以尽可能低的点差对其进行了测试。事实是,我们需要看到每一个报价点,以便搜索模式,特别是在较低的时间范围内。在测试 MetaTrader 5 版本时,我们看不到这一点,因为点差,MetaTester 5 可以自行调点差。

这是压力测试和评估真实系统性能的完美工具。应该在最后阶段使用它来测试系统的真实报价点。在我们的例子中,最好从MetaTrader 4开始测试系统。我建议每个人都使用这种方法,因为如果您立即在第五个版本中开始测试,您可能会丢失许多优秀的设置选项,这些选项可以作为更好质量设置的基础。

我不推荐使用优化有很多原因,但主要原因是它是一个简单的参数迭代。如果不手动尝试这些参数,您将无法理解它是如何工作的。如果你拿一台旧收音机,把电动机连到手柄上,然后启动它们,很可能你找不到电台。同样的情况也发生在这里。即使你抓住了什么东西,也很难理解它是什么。

另一个非常重要的方面是订单数量。打开的柱形对应的订单越多,发现的物理学现象就越强,以后不必为它的性能操心。还请记住,发现的模式可能位于点差之内,如果这些时刻不受控制,则会使系统无用!

这就是我们需要 MetaTrader 5 测试器的地方。MetaTrader 5 允许使用真实的报价点测试策略。不幸的是,所有货币对和工具都只在一个相对较近的时期内有真实报价点。我将在过去几年中使用真实的报价点和非常严格的点差要求来测 试 MetaTrader 5 的系统版本,看看该系统在2020年是否能正常工作。但首先,我将在“每个报价点”模式下对以前使用的时段进行测试:

这种测试模式不如使用真实报价点的测试模式好,然而,很明显,只有一小部分的信号从最初的结果留在这里。尽管如此,还是有信号超过了点差,甚至带来了微利。另外,我也不确定测试器从历史中获得的点差。在这次测试中,手数是0.01,这意味着数学期望值是5个点,这甚至比原来的测试结果还要高,尽管图表看起来不是很好。这些数据仍然是可信的,因为在最初的测试中有100000笔交易的巨大样本。

现在让我们看看去年的情况:

在这个测试中,我将手数设置为0.1,因此数学期望值是23.4个点,这是非常好的,考虑到 MetaTrader 4 的初始测试只有3个点的期望值。未来的预期可能会下降,但不会下降很多。因此,这对于盈亏平衡的交易来说还是足够的。

两个终端的专家顾问见以下附件。您可以更改设置,并尝试查找限价和市场订单的有效参数。然后您可以组合集合并设置一些平均参数。不幸的是,我没有足够的时间来充分利用它,所以还有进一步行动的空间。

当然,请注意,它不是一个现成的EA,您可以简单地在图表上启动并享受。使用其他类型的订单测试模拟,然后组合设置并重复这两个测试周期,直到EA显示可靠的交易结果。可能的话,你可以引入一些过滤器或者调整算法本身。从测试中可以看出,进一步的改进是可能的。因此,您可以使用附带的程序并对其进行优化,以获得稳定的结果。而且,我没有找到适合更高时间段的设置。EA在M5上工作得最好,但是也许你可以找到其他的时间框架。而且,我没有时间检查集合在其他货币对上的执行情况。然而,通常这样平缓的线形意味着EA也应该处理其他货币对。如果我有时间,我会尝试继续完善EA。在写这篇文章的时候,我发现了EA中的一些缺陷和错误,所以还有很多工作要做。


结论

模拟器已经证明了对这种分析方法的良好期望。在获得第一个结果之后,是时候考虑如何改进它们,如何使算法现代化,使其更好、更快和更灵活。这种方法的最大优点是其最大的简单性。我不是在讨论逻辑实现,而是从物理的角度讨论这个方法的底层逻辑。

我们不能把影响价格变动的所有因素都考虑进去。但即使至少有一个这样的因素(即使我们不能可靠地描述它),那么即使它不准确的代码描述也会产生某些信号。这些信号的质量可能不是很高,但它们足以从这个想法中产生一些利润。不要试图找到一个理想的公式,这是不可能的,因为你永远不能考虑到所有影响市场的因素。

此外,你不必完全使用我的方法。这篇文章的目的是利用市场的一些物理知识,在我看来,这些知识至少部分地描述了市场,并编写了一个专家顾问来证明这一观点。因此,我开发了一个专家顾问,它表明这样的假设可以作为一个工作系统的基础。

还要考虑到这样一个事实:代码有大大小小的缺陷和错误。即使在这种形式下,EA也能工作。你只需要改进它。在下一篇文章中,我将介绍另一种类型的多资产市场分析,它更简单、更有效,大家都知道。我们将再次创建一个专家顾问。