市場とそのグローバルパターンの物理学
Evgeniy Ilin | 18 2月, 2021
はじめに
本稿では、市場物理学を自動取引に使用する方法を理解しようとします。数学の言葉は、抽象性と不確実性から予測への移行を意味し、作成されたシステムの品質を向上させるために、近似値やあいまいな値ではなく、明確な式や基準を使用して操作できるようになります。理論やパターンは発明せずに既知の事実のみを使用し、これらの事実を徐々に数学的分析の言語に翻訳していきます。私たちが生成するシグナルは数学的な実体であるため、市場の物理学は数学なしでは不可能です。多くの人々は、統計分析を行わずに、または非常に限られた統計を使用して、さまざまな理論や公式を作成しようとしますが、これは、そのような大胆な結論には不十分なことがよくあります。真実の基準は練習だけです。まず、少し思案してからそれに基づいてエキスパートアドバイザー(EA)を作成します。その後、EAテストをおこないます。
価格とそれが提供するもの
市場の状況は、さまざまな製品の存在を意味します。通貨市場では、製品は通貨です。通貨とは、特定の製品または情報を所有する権利を意味し、世界中でベンチマークとして設定されています。たとえば、EURUSDペアとそのチャートの現在の値について考えてみましょう。現在のチャートの値は、USD/EUR=CurrentPriceです。または: USD = EUR*CurrentPriceです。これは1ユーロに含まれるドルの金額を意味します。言い換えれば、値は各通貨の重みの比率を示しますが、もちろん、各通貨の交換に相当する共通の要素、つまり一般的な商品などがあると想定されます。価格はオーダーブックで形成され、オーダーブックのダイナミクスが価格の動きを決定します。価格形成のすべての要因を考慮に入れることは決してできないことを常に覚えておく必要があります。たとえば、FORTSはFOREXとつながっており、両方の市場が相互に影響を及ぼします。私はこの種類の専門家ではありませんが、すべてがバインドされており、データチャネルが多いほど良いことは理解できます。そのような詳細に深く踏み込むのではなく、価格を動かす単純なことに焦点を当てたほうがよいように思えます。
依存関係は、相場同様、多くの変数を持つ関数として表すことができます。最初の価格は次のとおりです。
- P=P(t)
つまり、価格は時間の関数です。関数の形式は、通貨ペアやその他の商品ごとに確実に確立することはできません。これには無限の時間がかかるためです。この表現から得るものはありません。ただし、価格には予測可能な要素とランダムな要素の両方があるため、価格には2つの性質があります。予測可能な部分は関数自体ではなく、その最初の導関数です。これは取引の目的がないため、この関数をいくつかの項として表すことには意味がありません。しかし、その一次導関数を考えると、次のようになります。
- P'(t)=Pa'(t)+Pu'(t)
ここで、最初の項は数学的分析を使用して何らかの方法で分析できる部分を反映し、2番目の項は予測不可能な部分です。この式から、移動の大きさや方向を100%の精度で予測することは不可能であると言えます。決定できないので、最終項がどうなるかを考える必要はありません。しかし、最初の項を決定することはできます。値関数が離散的であり、微分演算を適用できないことを考慮すると、この項は別の形式で表すことができると想定できます。しかし、代わりに、時間「st」の平均導関数をとることができます。価格に適用される場合、これはバーの持続時間になります。 ティックに適用される場合、それは2つのティック間の最小時間です。
- 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) - 未決済の売り注文のボリューム
上記の関数は、現在開いているすべての買いポジションと売りポジションの出来高の違いを示しています。これらのポジションの一部は互いに補正しますが、残りのポジションは独立しています。ポジションは開いているので、しばらくすると決済されるという約束を象徴しています。買うと価格が上がり、売ると価格が下がることは誰もが知っています。価格がどう動くかを知る唯一の方法は、未決済の成行注文のみを考慮に入れてポジションのボリュームを測定し、これらのポジションの方向を推定することです。
市場の波の性質は、実際にはこの単純な事実に関連しています。これは、ポジションボリュームの変動、または強気と弱気の行動のより一般的なプロセスの1つの特殊なケースにすぎません。
バーを扱うときは、バー内に4つの価格があるという事実を考慮することもできます。これにより、より良い数式が得られます。データが多いほど分析は正確になるため、すべての価格データを考慮することが重要です。ただし、すべてのティックを使用するのはアルゴリズムが10倍遅くなるため好みません。さらに、ティックデータは証券会社によって異なる場合があります。反対に、バーの始値と終値はほとんどの証券会社でほぼ同じです。すべての価格データを考慮に入れるようにボリューム関数を修正しましょう。
- 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))
この関数に、時間、曜日、月、週などの変数を追加することもできますが、これにより、特定の市場領域にリンクされた多くの関数が生成されます。ここでの目的は、一般的な市場の物理学を決定することです。壊れることはなく、市場が存在する限り使用できることがわかります。式のもう1つの利点は、その多通貨の性質です。
実用的には、この関数を構築する方法とデータに基づいて正確に知る必要があるため、この表現型を使用しても意味がありません。この関数の形式を記述しただけで依存関係を判別することはできません。しかし、これらの式は、分析方法と次の仮定に進む方法を最初に理解するのに役立ちます。論理条件の任意のセットは、最終的にはそのような関数として表すことができます。逆に、関数自体を一連の条件に変えることができます。どの形式を使用するかは関係なく、それを理解することだけが重要です。アルゴリズムはどれでも、何らかの単一の式にまとめることができます。非常に複雑な関数を作成するよりも、シグナルを条件または条件のシステムとして説明する方が簡単な場合があります。もう1つの大きな問題は、そのような関数をどのように構築するかです。
実際の取引システムでは、履歴全体を一度に分析することはできず、分析できるのは一定期間だけです。このような分析には4つの可能なアプローチがあります。それらの名前を作成して説明します。
- 数式(インディケーターまたはその関数)
- シミュレーション
- 一般的な数学
- 各種機械学習
最初のオプションは、1つの特定の値または値のセットを使用することを前提としています。例は、インディケーターまたは独自の式です。このアプローチの利点は、MetaTrader4/5ターミナルで大きなツールキットを利用できることです。さらに、人気のある市場理論に基づいた多くのインディケータ―をマーケットやWebで入手できることです。このアプローチの欠点は、ほとんどの場合、インディケーターが機能する根拠を理解できないことです。理解したとしても、そのような理解は価値がない可能性があります。
2番目のオプションでは、理解できないデータや役に立たないデータは使用しません。代わりに、市場での注文をシミュレートしてみると、システムは、一方向に開いているポジションの数と、他の方向に開いているポジションの数をある程度説明できることがわかります。この情報は必要な予測を生み出すことができ、グローバルな視点で市場を詳細に説明することができます。これは、機械学習に代わる唯一の方法です。
数学とは、現在の市場の状況に関係なく、相場を活用できるようにするいくつかの基本法則の理解または特定の数学的原理の知識を意味します。事実、離散関数を含むすべての関数には、悪用できる特性があります。もちろん、ここでは依存関係が混沌としていないことを前提としています(この場合、外国為替は混沌としていないため、相場を利用できます)。次の記事では、ほとんどの人が知っているそのような原則の1つを分析します。しかし、知ることと使用できることは、2つの異なることです。このアプローチの利点は、成功システムを構築できた場合、将来のシステムの動作についての心配がないことです。
機械学習はあらゆるデータを最大限に活用できるため、4番目のアプローチは最も進歩的なアプローチです。計算能力が高いほど、分析の品質は高くなります。このアプローチの欠点は、市場の物理学を理解するのには役立たないことであり、利点は、アプローチが単純であり、最小限の時間で結果の品質が最大になることです。ただし、このアプローチはこの記事には適用されません。
パターンについて
毎日の取引は、それぞれが異なる重要性を持っている、多数の用語を意味します。一部の用語は非常に頻繁に使用されますが、すべてのトレーダーがその本当の目的を理解しているわけではありません。これらの用語の1つは「パターン」です。ここで、「パターン」が数学の言語であるとの説明を試みます。パターンは常に特定の期間と特定の通貨ペアおよびチャート期間にリンクされています。一部のパターンは強力で、このようなパターンは、多通貨またはグローバルな性質のものである可能性があります。理想的なパターンは聖杯です。すべてのパターンに適用できるステートメントはいくつかあります。
- パターンを象徴する式または条件のセットの存在
- ストラテジーテスターの最小テスト値またはデモまたはリアル口座のパフォーマンス値
- すべての通貨ペアとチャート期間のパフォーマンスに関するパターンの分類
- パターンが見つかった歴史の期間
- パターンが機能し続ける将来の時間間隔
- 元のパターンがいくつかのパラメータを保持するまたはそれらを反転する、最初の期間に続く将来の2番目の期間
各プロパティを注意深く読むと、パターンは数式または条件のセットであり、選択した間隔での価格変動を最も正確に表すことがわかります。特に短すぎる期間に見つかった場合や関連するシステムが過度に楽観的な値を生成した場合には、パターンはランダムであることが判明する可能性があります。システムを短期間でテストする場合、グローバルパターンを見つける可能性はゼロになる傾向があることを理解することが非常に重要です。これはサンプルサイズに関連しています。サンプルが小さいほど、結果のランダム性が高くなります。
パターンとは何かを決定しましたが、パターンを効果的に使用するにはどうすればよいでしょうか。これはすべて、このパターンの見つけられ方とその品質に依存します。計算能力を利用した分析手法を考慮しなければ、分析することになります。私の意見では、分析はどんなマシン分析にもかないません。優れたアナリストチームでさえ、1台のマシンで処理できるデータを処理することはできません。とにかく、グローバルパターンを見つけるプロセスには計算能力が必要です。例外は、自分の目で明白なものを見て、それらの物理学を理解した場合です。
最も単純な位置シミュレータの作成
グローバルなパターンを見つけようとして、市場のプレーヤーの気分を説明できるエキスパートアドバイザーを開発することは興味深いでしょう。このために、私は市場ポジションのシミュレータを作成しようと決心しました。ポジションは、マーケットエッジに近いバー内でシミュレートされます。市場のプレーヤーが異なり、注文の重みも異なると想定する必要があります。同時に、これは単純な形式で提示する必要があります。単純なプロトタイプが利益を示す場合、その原則をさらに使用できます。
ロジックは、条件付きで3つの個別のシミュレーションと、それらの可能な混合の組み合わせに分割されます。
- 逆指値注文のシミュレーション
- 指値注文のシミュレーション
- 成行注文のシミュレーション
- 可能な組み合わせ
注文には次のロジックが使用されます。
これらのグリッドは、市場参加者の一部の気分をシミュレートするために、新しい各バーに配置されています。古い注文グリッドのステータスは、チャートに表示される新しいバーに基づいて更新されます。このアプローチはあまり正確ではありませんが、ティックごとのシミュレーションは無限の計算につながり、さらに、私はティックをあまり信用していません。
相対ボリュームの分布には、減衰と均等の2種類がありますが、逆指値および指値注文に対してのみです。成行注文は均等に分布されます。これを視野に入れれば、分布の種類を拡大することも可能です。以下に示します。
ここで、注文を表す線の長さは注文の量に比例します。このようなイラストは単純で誰にとってもわかりやすいと思います。
この場合、すべてはオブジェクト指向アプローチを使用して実行できます。まず、番号付きリストについて説明します。
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 };
シミュレータは、低速と高速の2つのモードで動作します。低速モードは、主に分析を開始するために必要です。開始時の分析では、市場のローソク足に最も近い最初の「n」で計算が実行されます。高速モードでは、計算は新しく登場したローソク足でのみ実行されます。しかし、単純なアプローチでは不十分であることがわかりました。アルゴリズムの速度を上げるには、追加の機能が必要でした。エキスパートアドバイザーの初期化では、非常に大きな計算が実行されます。ただし、各ローソク足で1つの新しいローソク足のシミュレーションを更新するだけで済みます。現在の市場価格(各バーのOpen[i])からの距離に応じて、指値注文と逆指値注文の2種類のボリューム分布があります。これは、逆指値注文と指値注文のグリッドが各バーで開かれ、分布と重みが異なるためです。しばらくすると、逆指値注文と指値注文が成行注文に変わります。指定された時間内に価格が必要な価格に達しない場合、逆指値注文と指値注文はキャンセルされます。
このシミュレーションを単純なものから複雑なものまで構築し、徐々にすべてをまとめていきましょう。まず、注文とは何かを定義します。
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; } };
パラメータは多くなく、各パラメータは一般的なアルゴリズムにとって重要です。フィールドの多くはすべての注文に適用できますが、一部のフィールドは指値注文または逆指値注文にのみ適用されます。たとえば、希望価格は成行注文の始値ですが、指値注文と逆指値注文の希望価格です。
終値の上限と下限は逆指値として機能します。同時に、グリッド注文は完全な注文ではなく多数の注文が含まれており、それらが1つの注文に結合され、特定のボリュームで特定の価格で開かれると想定します。開始ボリュームと現在のボリュームの変数は、特定のバーの特定のレベルでの注文の重要性を示します。
開始ボリュームは、発注時のボリュームです。現在のボリュームは、イベントがさらに発展するときのボリュームです。重要なのは、特定の注文からの利益ではなく、買い注文と売り注文の量の比率です。取引シグナルは、これらの考慮事項に基づいて生成されます。もちろん、他のシグナルを思いつくこともできますが、これには他の考慮事項が必要です。また、注文は特定のレベルに達しても決済されませんが、イベントの実際の展開を可能な限りシミュレートするために、各バーで徐々に決済されることに注意してください。
次に、各バーのストレージを定義する必要があります。バーには、このバーで開かれた注文が保存されます。
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); } } };
ここではすべてが非常に簡潔です。6種類の注文が配列で記述されます。これは混乱を避けるために行われます。このクラスは純粋な形では使用されず、建物のレンガにすぎません。
次に、すべてのバーの共通ストレージを1つのオブジェクトとして定義します。このオブジェクトから、後で継承が実行されます。ここでのテクニックは非常に簡単です。
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; } };
コード全体はMetaTrader4とMetaTrader5の両方で有効です。これらのクラスは、両方のプラットフォームでコンパイルできます。もちろん、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と同様のクラス操作を保証するために、それらを人為的に作成する必要があります。
動作設定を見つける方法は
自らの経験からすると、手動で設定を選択する方が良いと言えます。さらに、短い時間枠で実行され、数学的な期待が小さいエキスパートアドバイザーの最初の段階でのスプレッドを無視することをお勧めします。これにより、最初のパフォーマンスの兆候を見逃さないようにできます。MetaTrader4はこの目的に非常に適しています。検索が成功したら、最終的な数学的期待値と利益率(シグナル強度)を高めるために、常に修正や編集などがおこなわれます。また、入力データの構造は、理想的には、独立した動作モードを可能にする必要があります。つまり、1つの設定は、他の設定の値に関係なく、システムパフォーマンスに最も独立した影響を与えるはずです。このアプローチでは、検出されたすべてのシグナルを組み合わせるバランスの取れた設定を設定することにより、シグナル全体を強化できます。このような実装は常に可能であるとは限りませんが、ここでの場合、各注文タイプを個別に分析するため、適用可能です。
エキスパートアドバイザーのテスト
このエキスパートアドバイザーは、何の準備もせずにゼロから作成されているため、このEAコードは私にとって新しいものです。似たようなEAは持っていましたが、それははるかに単純で、ロジックがまったく異なりました。本稿の目的は、市場の物理学を完全に説明していなくてもいくつかの正しい基礎となる基本を持っているアイデアはある程度のパフォーマンスを示す可能性が非常に高いことを示すことであったため、これを強調したいと思います。システムが基本的なパフォーマンス能力を示している場合、それをテストし、このシステムでなにが機能するかを見つけて、市場理解の次のレベルに進むことができます。次のレベルでは、自分で作成する高品質のエキスパートアドバイザーを想定しています。
エキスパートアドバイザーをテストするとき、取引パラメータを選択するのに辛抱強く数日を費やさなければなりませんでした。退屈で長いプロセスでしたが、なんとか動作設定を見つけることができました。もちろん、これらの設定は非常に弱く、シミュレーションは1つの注文タイプのみを使用して実行されますが、これは意図的です。特定の注文タイプがシグナルにどのように影響するかを個別に分析してから、他の注文タイプをシミュレートすることをお勧めします。これがMetaTrader4での結果です。
まずMetaTrader4バージョンを作成し、可能な限り低いスプレッドでテストしました。事実は、特に短い時間枠でパターンを検索するには、すべてのティックを確認する必要があるということです。MetaTester5は自らの裁量でスプレッドを調整できるため、MetaTrader 5バージョンをテストするときにはこれを見ることができません。
これは、ストレステストや実際のシステムパフォーマンスの評価に最適なツールです。実際のティックでシステムをテストする最終段階で使用する必要があります。ここでの場合、MetaTrader4でシステムのテストを開始することをお勧めします。5番目のバージョンですぐにテストを開始すると、より高品質の設定の基礎として役立つ多くの優れた設定オプションが失われる可能性があるため、このアプローチを使用することをお勧めします。
最適化を使用することは多くの理由でお勧めしませんが、主な理由は、パラメータの単純な反復です。パラメータを手動で試さないと、どのように機能するかを理解できません。古いラジオのハンドルに電気モータを接続してそれらを始動したならば、おそらくラジオ局を見つけることができません。ここでも同じことが起こります。何かを捕まえても、それが何なのかわかりません。
もう1つの非常に重要な側面は、注文数です。開かれるバーの数に比べて注文が多いほど、より強力な物理特性が見つかり、将来そのパフォーマンスについて気にする必要はありません。また、見つかったパターンがスプレッドの内側にある可能性があることを忘れないでください。これらの瞬間が制御されないままになっていると、システムが役に立たなくなる可能性があります。
これがMetaTrader5テスターの出番です。MetaTrader 5では、実際のティックを使用してストラテジーをテストできます。残念ながら、実際のティックは、すべての通貨ペアと商品について比較的最近の期間存在します。2020年にシステムが機能するかどうかを確認するために、実際のティックと非常に厳格なスプレッド要件を使用して、最後にMetaTrader5のシステムバージョンをテストします。ただし、最初に、以前に使用した期間で「全ティック」モードでシステムをテストします。
このテストモードは、実際のティックを使用するモードほど良くありません。ただし、最初の結果からのシグナルのごく一部だけがここに残っていることは明らかです。それにもかかわらず、スプレッドをカバーし、わずかな利益さえも与えるシグナルがあります。また、テスターが深い歴史から取ったスプレッドについてもよくわかりません。このテストでは、ロットは0.01でした。これは、数学的期待値が5ポイントであることを意味します。チャートはあまり良くないように見えますが、こては元のテストよりもさらに高くなっています。このデータの背後にある最初のテストには10万取引の膨大なサンプルがあるため、このデータは引き続き信頼できます。
では、昨年を見てみましょう。
このテストでは、ロットを0.1に設定しました。数学的期待値は23.4ポイントで、MetaTrader 4の最初のテストでは3ポイントしか期待されていなかったことを考えると非常に良好です。期待は将来下がる可能性がありますが、何ポイントも下がることはないので、引き分けの取引にはまだ十分です。
両ターミナルのエキスパートアドバイザーは、以下の添付ファイルにあります。設定を変更して、指値注文と成行注文の動作パラメータを見つけ、次に、セットを組み合わせて、いくつかの平均パラメータを設定できます。残念ながら、最大限に活用するのには十分な時間がなかったので、さらなる措置を取る余地があります。
もちろん、これは、チャート上で起動して楽しむことができるようなすぐに使用できるEAではないことに注意してください。他のタイプの注文を使用してシミュレーションをテストし、設定を組み合わせて、EAが信頼できる取引結果を示すまでこれらの2つのテストサイクルを繰り返します。おそらく、いくつかのフィルターを導入したり、アルゴリズム自体を調整したりできます。テストからわかるように、さらなる改善が可能です。添付のプログラムを使用して、安定した結果を達成するためにそれを改良してみてください。また、私はより長い時間枠に適した設定を見つけることができませんでした。EAはM5で最適に動作しますが、他の時間枠を見つけることができるかもしれません。また、セットが他の通貨ペアでどのように機能するかを確認する時間もありませんでした。ただし、通常、このようなフラットラインは、EAが他の通貨ペアでも機能することを意味します。時間があれば、EAの改良を続けていきます。この記事を書いている間に、EAにいくつかの欠陥やエラーが見つかったので、やるべきことがまだたくさんあります。
終わりに
シミュレーターは、この分析方法に関して良い期待を示しています。最初の結果を取得したら、それらを改善する方法、アルゴリズムを最新化する方法、およびアルゴリズムをより良く、より速く、より可変にする方法について考える時です。このアプローチの最大の利点は、その最大限の単純さです。ロジックの実装についてではなく、物理的な観点から見たこのメソッドの基礎となるロジックについてです。
価格変動に影響を与えるすべての要因を考慮に入れることはできません。しかし、そのような要因が少なくとも1つある場合でも(確実に記述できない場合でも)、その不正確なコード記述でさえ、特定のシグナルを生成します。これらのシグナルはそれほど高品質ではないかもしれませんが、このアイデアからある程度の利益を生み出すには十分です。市場に影響を与えるすべての要因を考慮に入れることはできないため、理想的な式を見つけようとしないでください。これは不可能です。
さらに、私のアプローチを正確に使用する必要はありません。本稿の目的は、市場のいくつかの物理学を利用することでした。これは、私の意見では、少なくとも部分的に市場を説明し、アイデアを証明できるエキスパートアドバイザーを作成することでした。その結果、私はエキスパートアドバイザーを開発しました。これは、そのような仮定が作業システムの基礎として役立つことを示しています。
また、コードにマイナーで大きな欠陥やバグがあるという事実も考慮に入れてください。この形式でもEAは機能するので、洗練するだけです。次の記事では、別のタイプのマルチアセット市場分析を紹介します。これは、より単純かつ効果的で、誰もが知っているものです。ここでも、エキスパートアドバイザーを作成します。