
市场及其全局模式中的物理学
介绍
在本文中,我们将试图了解如何将市场物理学用于自动交易。数学语言意味着从抽象性和不确定性到预测性的转变。这允许使用明确的公式或标准进行操作,而不是使用一些近似和模糊的值,以提高所创建系统的质量。我不会发明任何理论或模式,但我只会使用已知的事实,逐步将这些事实转化为数学分析的语言。没有数学,市场物理学也是不可能存在的,因为我们产生的信号就是数学实体。许多人试图在没有任何统计分析或使用非常有限的统计数据的情况下创造各种各样的理论和公式,这往往不足以得出如此大胆的结论。只有实践才是检验真理的标准。首先,我将尝试进行一些反思,然后,基于这些反思,我将创建一个专家顾问(EA),随后将进行EA测试。
价格以及它提供了什么
任何市场环境都意味着各种产品的存在,在货币市场上,产品就是货币。货币是指拥有某种产品或信息的权利,在世界范围内被设定为基准。例如,看一下 EURUSD 及其图表的当前值,当前图表值得意思是 USD/EUR = CurrentPrice. 或者: USD = EUR*CurrentPrice, 也就是说一欧元中包含的美元数量。换言之,该值表示每种货币权重的比率,当然,假定每种货币都有某种共同的等价交换,即某种共同的商品或其他东西。价格是在订货簿中形成的,订货簿的动态性决定了价格的变动。应该永远记住,我们永远无法考虑到价格形成的所有因素。例如,俄罗斯商品期货交易所是与外汇交易市场相联系的,并且相互影响。我不是这方面的专家,但我能理解一切都是有约束的,数据通道越多越好。在我看来,最好不要深入到这样的细节中去,而应该把注意力集中在那些影响价格的简单事情上。
任何依赖关系都可以表示为许多变量的函数,就像任何报价一样。最初的价格是:
- P=P(t)
换句话说,价格是时间的函数。无法为每一对货币或任何其他工具可靠地确定函数的形式,因为这将需要无限的时间。但是这种表示形式什么都给不了我们。然而,价格具有双重性质,因为它既有可预测的成分,也有随机成分。可预测的部分不是函数本身,而是它的一阶导数。将此函数表示为某些术语是没有意义的,因为它没有用于交易的目的。但如果我们考虑它的一阶导数,有以下几点:
- P'(t)=Pa'(t)+Pu'(t)
在这里,第一项反映了可以用数学分析的方法进行分析的部分,第二项是不可预测的部分。根据这个公式,我们可以说不可能100%准确地预测运动的大小和方向。没有必要考虑最后一项是什么,因为我们无法确定它。但是我们可以判断第一项。考虑到值函数是离散的,我们不能应用微分运算,可以假设这个项可以用不同的形式表示。但是相反,我们可以取一段时间的平均导数“st”。当应用于价格时,这将是条形图的持续时间;当应用于报价点(tick)时,它是两个报价点之间的最短时间。
- PaM(t)=(Pa(t)-Pa(t-st))/st - 一段固定时间内的平均价格变动(时间导数)
- Ma(t)=Ma(P(t),P(t-st) + ... + P(t-N*st), D(t),D(t-st) + ... + D(t-N*st),U[1](),U[2](t) + ... + U[N](t) )
- P(t[i]) - 旧的价格(柱形或者报价点数据)
- D(t[i]) - 其他货币对的旧价格值
- U[i](t) - 其他影响市场的未知或已知数值
- Ma(t) - 给定时间点的PaM(t)值的数学期望
换言之,我们假设价格的可预测部分可能取决于之前的条形图或刻度,以及其他货币对的价格数据、其他交易所和世界事件的数据。不过,应该理解的是,就算是这部分价格也无法100%准确预测,我们只能计算出它的一些特征。这样的特征只能是一个概率或一个随机变量的参数,如数学上的期望值、方差、标准差等数量的概率论。用数学期望操作足以使交易有利可图。经过时间和仔细思考,我们可以得出这样的结论:不仅可以用这个逻辑来分析市场。问题是,价格的可预测部分是根据市场参与者的活动而发展的。我们可以抛弃各种市场参数,除了市场参与者自己创造的因素。当然,所有这些都会导致我们的分析方法的可靠性降低,但这大大简化了模型。在这里,“st”值越小,我们的公式描述市场就越准确。
- VMa(t)=VMa(P(t),P(t-st) + ... + P(t-N*st))
- VMa(t)=VBuy(t)-VSell(t)
- VMa(t) - 总交易量
- VBuy(t) - 未平仓的买入订单交易量
- VSell(t) - 未平仓的卖出订单交易量
上述函数描述了当前所有未平仓买入和卖出头寸的交易量差异。这些仓位的一部分相互补偿,而其余仓位是独立的。由于仓位是开放的,它们象征着一段时间后关闭的承诺。我们都知道买会使价格上涨,卖会使价格下跌。唯一知道价格走向的方法是衡量未平仓的成交量,并估计这些仓位的方向,只考虑未平仓的市场订单。
市场的波动性实际上与这个简单的事实有关。这只是一个更普遍的头寸波动过程的特例,即多头和空头的行为。
在处理柱形时,也可以考虑到一个柱里面有4个价格,这可以给我们提供更好的公式。更多的数据意味着更准确的分析,这就是为什么必须考虑所有价格数据的原因。但是,我不喜欢计算每一个 tick,因为这样会使算法慢十倍。此外,不同经纪商的 tick 数据可能不同。相反,大多数经纪商的开盘价和收盘价几乎相同。让我们修改交易量函数以考虑所有价格数据:
- VMa(t)=VMa(O(t),O(t-st) +...+ O(t-N*st) + C(t),C(t-st) + C(t-N*st),H(t),H(t-st)...H(t-N*st),L(t),L(t-st)...L(t-N*st))
我们可以给这个函数添加更多的变量,比如时间、一周中的几天、几个月和几周,但是这会产生很多与特定市场区域相关的函数,而我们的目的是确定一般的市场物理学。我们将知道它是不能被打破的,因此只要市场存在,它就可以被使用。这个公式的另一个优点是它的多货币性。
实际上,使用这种表示类型没有意义,因为我们需要确切地知道如何以及基于什么数据来构建这个函数。我们不能只写这个函数的形式并确定依赖关系。但是,这些表达式可以帮助我们初步了解如何进行分析,以及如何进行以下假设。任何一组逻辑条件最终都可以表示为这样一个函数。相反,函数本身可以转化为一组条件。我们用哪种形式并不重要,理解它才是重要的。任何算法都可以简化为一个公式。有时,将信号描述为条件或条件系统比构建超复杂函数更容易。另一个大问题是如何建立这样一个功能。
在一个真实的交易系统中,我们不能一次分析整个历史,而只能分析一段固定的时间。这种分析有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 中的结果:
我首先为 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也能工作。你只需要改进它。在下一篇文章中,我将介绍另一种类型的多资产市场分析,它更简单、更有效,大家都知道。我们将再次创建一个专家顾问。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/8411
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.



以下是关于什么是公寓的详细介绍https://www.mql5.com/zh/articles/8274
谢谢--我看了之后哈哈大笑。我尤其对 "混乱市场 "的定义感到好笑。原来,触发保护性订单的概率取决于市场,而不是其规模!
那么,什么是平盘--给出一个数学定义?
谢谢 - 读完后,我笑了。我尤其被 "混乱市场 "的定义逗乐了。原来,触发保护令的概率取决于市场,而不是保护令的大小!
那么,什么是平缓市场--给出一个数学定义
我已经给了你一篇文章的链接。你笑了。这不能怪你。扁平的定义是图形化的。但我们也可以给出这些过程的标量特征。如果我们采取固定的步数并考虑参考分布(在市场混乱的条件下的分布),我们考虑参考分布中的模平均价格变动,然后我们考虑市场上现有分布中的模平均价格变动,那么趋势就是后者大于参考分布。持平的情况则恰恰相反。平均变动模数应小于参考变动模数。您还可以得出类似于买入或卖出的运动系数,加上升系数,减下降系数。顺便说一句,如果您还不明白,本文还包含一个实现这两个特征的指标示例。满意了吗? 还是想让我用 "Paints "把公式扔给你?现在我要问你一个问题。你想从文章中找到什么?
我已经给了你文章链接。你笑了这不能怪你。平面是用图形定义的。但我们也可以给出这些过程的标量特征。如果我们采取固定的步数并考虑参考分布(在市场混乱的条件下的分布),我们考虑参考分布中的模平均价格变动,然后我们考虑市场上现有分布中的模平均价格变动,那么趋势就是后者大于参考分布。持平的情况则恰恰相反。平均变动模数应小于参考变动模数。您还可以得出类似于买入或卖出的运动系数,加上升系数,减下降系数。顺便说一句,如果您还不明白,本文还包含一个实现这两个特征的指标示例。满意了吗? 还是想让我用 "Paints "把公式扔给你?现在我要问你一个问题。你想从文章中找到什么?
在这篇文章中,我在寻找物理学与它有什么关系的解释。这与物理学无关。
在第一篇文章中,我对 "混乱市场 "的定义感兴趣--这与触发保护令的概率有着有趣的联系。我隐约觉得,随着订单规模的减小,任何市场的 "混乱 "程度都会增加.....。
在这篇文章中,我想解释的是物理学与此有什么关系。物理学与此无关。
在第一篇文章中,我对 "混乱市场 "的定义很感兴趣--这与触发保护性订单的概率有着有趣的联系。我隐约觉得,随着订单规模的减小,任何市场的 "混乱 "程度都会增加.....。
这只能通过实验来验证。在所有范围内都与随机性有区别,但一般来说,几乎 100%的地方都会转向平缓,因为人们在买入时会成群结队地买入,在卖出时也会成群结队地卖出,因此会出现波浪,进入和退出是两个半波。在很多情况下,这都是偶然的,我们无法可靠地确定波浪中的内容。我制作的那些实验性 Expert Advisors 能够提供约 20-40 个点的预期,同时在全球范围内贯穿历史。这种机制在任何地方和多种货币中都有效。如果您能正确地检测这些波浪和过滤信号,如果您还添加了马丁平均法......只是这是一个严肃的项目,我还没有时间。有类似的方法。马克西姆-罗曼诺夫(Maxim Romanov)也有类似的方法,但他使用的是更高的 TFs。顺便说一下,这是真的。我主要在 M5 上推广