English Русский 中文 Español Deutsch Português
preview
自動で動くEAを作る(第15回):自動化(VII)

自動で動くEAを作る(第15回):自動化(VII)

MetaTrader 5 | 19 7月 2023, 11:42
441 0
Daniel Jose
Daniel Jose

はじめに

前回の記事自動で動くEAを作る(第14回):自動化(VI)では、C_Automatonクラスについて考え、その基本について説明しました。C_Automatonクラスを使ってシステムを自動化するのは、見かけほど簡単ではないため、この記事では、これをおこなう方法の例を見ていきます。

ここでは3つの異なるモデルを見ていきます。この記事では、各モデルを実装するためにC_Automatonクラスをどのように適応させるかに焦点を絞って説明します。適応、つまり従属的な部分についてのみ説明するつもりなので、システムの詳細については、以前の記事をお読みください。

この話題は実はかなり長いので、実際の例に移りましょう。 


自動化の例1:9期間指数移動平均

この例では、以下に添付されているEA_v1.mq5ファイルで利用可能なEAコードを使用しています。クラスコンストラクタから始めます。

                C_Automaton(const ulong magic, double FinanceStop, double FinanceTake, uint Leverage,
                            bool IsDayTrade, double Trailing, const ENUM_TIMEFRAMES iPeriod,
                            const double OverBought = 70, const double OverSold = 30, const int iShift = 1)
                        :C_Manager(magic, 0, 0, Leverage, IsDayTrade, 0, false, 10),
                         m_TF(iPeriod),
                         m_Handle(INVALID_HANDLE)
                        {
                                m_Infos.Shift      = iShift;
                                m_Infos.OverBought = OverBought;
                                m_Infos.OverSold   = OverSold;
                                ArraySetAsSeries(m_Buff, true);
                                m_nBars  = iBars(NULL, m_TF);
                                m_Handle = iMA(NULL, m_TF, 9, 0, MODE_EMA, PRICE_CLOSE);
                        }

デフォルトのシステムとの違いを考えてみましょう。

  • このシステムにはストップロスもテイクプロフィットもありません。つまり、EA自体が値動きに応じてこれらの限度を生成するため、システムには利益限度も損失限度もありません。
  • システムはトレイリングストップ、ブレイクイーブン、ペンディングストップ注文を作成しません
  • 終値に基づく9期間の指数移動平均指標を使用します。

あとは先ほど説明したので、メカニズムの計算手順に移りましょう。関連する方法は前回の記事で説明したので、詳しくはそちらをお読みください。計算方法が定義されると、コードは次のようになります。

inline eTrigger CheckTrigger(void)
                        {
                                int iRet;
                                        
                                if (((iRet = iBars(NULL, m_TF)) > m_nBars) && (m_Handle != INVALID_HANDLE))
                                {
                                        if (CopyBuffer(m_Handle, 0, 0, m_Infos.Shift + 1, m_Buff) < m_Infos.Shift + 1) return TRIGGER_NONE;
                                        m_nBars = iRet;
                                        if (m_Buff[0] > m_Buff[m_Infos.Shift]) return TRIGGER_BUY;
                                        if (m_Buff[0] < m_Buff[m_Infos.Shift]) return TRIGGER_SELL;
                                };
                                return TRIGGER_NONE;
                        }

複雑そうでしょうか。実はそうではありません。前回の記事で説明したフローチャートでルールを作っておけば、やり方はいたって簡単です。まず、指標の内容を読み取ろうとします。それが不可能な場合、NULLトリガーを返し、シグナルが失われる可能性があります。

場合によっては、特に失われたシグナルがエグジットシグナルであった場合、システムは損失を出し始めます。ただし、早合点は禁物です。これが、EAを監視なしに放置してはいけない理由の説明だと思います。可能な解決策は、何らかのエラーが発生した場合に、C_Managerクラスにポジション終了シグナルを送信することでしょう。しかし、先に述べたように、決め付けは禁物なので、このシグナルを追加するかどうかは自分次第です。

次に、バーカウンタを更新して、シグナルが次のバーでのみトリガーされるようにしました。ただし、これは指標からの反応があった場合のみです。そうでない場合、シグナルは次のOnTimeイベントで再び確認されます。何が起こっているのかは、決めつけない方がいいのです。すべてが起こる順番に注意を払います。バー数の更新がその前におこなわれると、次のOnTimeイベントを見逃すことになります。しかし、後で更新するので、OnTimerイベントを受け取り、指標を再度読み込もうとすることができます。

次に、買うか売るかを判断するための計算をしてみましょう。この計算を理解するには、指数移動平均の計算方法を理解する必要があります。他の移動平均線と異なり、指数移動平均線は価格変動に素早く反応します。そのため、コンストラクタで定義した終値の位置に基づいて、バーが傾くとすぐに、そのバーが終値より上で閉じたのか下で閉じたのかを実際に知ることができます。

しかし、この計算には1つ細かな事実があります。現在の平均値と直前の値を比較する場合のみ、この情報を迅速に報告することができるということです。そのため、わずかな変化でもトリガーが起こる可能性があります。感度レベルを下げたい場合は、m_Infos.Shift変数に含まれる値を1から2、またはそれ以上の値に変更する必要があります。これは、ある種の動きを捉えるために移動平均のシフトをシミュレートし、システムの感度を下げたり上げたりします。

このようなシフトは、ジョー ディナポリのような設定によく見られます。多くの人は、移動平均線との関係でバーを見る必要があると考えていますが、実際には、バーがパターンに従っているかどうかを理解するために、MAを適宜調整する必要があるだけです。ジョー ディナポリの設定の場合、トリガーが適切なポイントで作動するように、移動平均でジグザグ計算をおこなう必要があります。それでも、バーを見る必要はなく、必要なのは平均値のみです。

上記の計算における重要な詳細は、計算におけるゼロ点は、バッファの直近の値、すなわち指標によって計算された最後の値を示すということです。 

最後の値が前の値より高ければ、EAは即座に買います 。より低ければ、EAは売りを出します。

このシステムは、よく知られたラリー・ウィリアムズのシステムに似ています。追加要素を使う人もいます。即座に売買する代わりに、移動平均シグナルが発生したバーの高値または安値で指値注文を出すことができます。C_Managerクラスは、サーバーに未決注文が1つしかないことを保証しているので、計算を変えずにTriggers関数を変更するだけです。したがって、成行取引の要求の代わりに、システムはシグナルを発生させたバーのデータを含む指値注文を送信します。

これは添付ファイルで提供されたコードではありませんが、以下のようなものになるでしょう。

inline virtual void Triggers(void) final
                        {
                                if (!CtrlTimeIsPassed()) ClosePosition(); else switch (CheckTrigger())
                                {
                                        case TRIGGER_BUY:
                                                if (m_Memory == TRIGGER_SELL) ClosePosition();
                                                if (GetVolumeInPosition() == 0)
                                                {
                                                        DestroyOrderPendent();
                                                        CreateOrder(ORDER_TYPE_BUY, iHigh(NULL, m_TF, 0));
                                                }
                                                m_Memory = TRIGGER_BUY;
                                                break;
                                        case TRIGGER_SELL:
                                                if (m_Memory == TRIGGER_BUY) ClosePosition();
                                                if (GetVolumeInPosition() == 0)
                                                {
                                                        DestroyOrderPendent();
                                                        CreateOrder(ORDER_TYPE_SELL, iLow(NULL, m_TF, 0));
                                                }
                                                m_Memory = TRIGGER_SELL;
                                                break;
                                }
                        };

C_Managerクラスのコードに新しい関数を追加しました。ここで、作成される注文がマーケットエントリとは異なるという事実に注目してください。これで、バーリミットの1つの価格に基づくエントリができました。これは状況の進展とともに変わっていくでしょう。トリガーが作成されたバーで注文が執行されなかった場合、次のバーで注文は自動的にリセットされます。このモデルは添付ファイルにはないのでご注意ください。

このシステムがかなり柔軟であることは、すでにご理解いただけたと思います。しかし、私たちはこのクラスシステムを使って実現できることのほんの表面をなぞったに過ぎません。別の応用例を説明するために、2番目の例を見てみましょう。


自動化の例2:RSIまたはIFRの使用

MAベースのシステムがどのように機能するかは見てきたので、別の指標を使った場合を見てみましょう。この例では、かなりポピュラーな指標を使います。しかし、この方法は他の指標やオシレーターにも適用可能であり、考え方は極めて普遍的です。

この例のEAコードは、記事に添付されているEA_v2.mq5ファイルにあります。再びコンストラクターから始めましょう。

                C_Automaton(const ulong magic, double FinanceStop, double FinanceTake, uint Leverage,
                            bool IsDayTrade, double Trailing, const ENUM_TIMEFRAMES iPeriod,
                            const double OverBought = 70, const double OverSold = 30, const int iShift = 1)
                        :C_Manager(magic, FinanceStop, 0, Leverage, IsDayTrade, Trailing, true, 10),
                         m_TF(iPeriod),
                         m_Handle(INVALID_HANDLE)
                        {
                                m_Infos.Shift      = iShift;
                                m_Infos.OverBought = OverBought;
                                m_Infos.OverSold   = OverSold;
                                ArraySetAsSeries(m_Buff, true);
                                m_nBars = iBars(NULL, m_TF);
                                m_Handle = iRSI(NULL, m_TF, 14, PRICE_CLOSE);

                        }

ここで最初の例との違いを見てみましょう。前の例と同じプロセスを繰り返すこともできるし、前の例をこのようにアレンジすることもできます。

  • ここでは、ポジションを開いた後ですでにストップロスとして使用する値を定義しています
  • ブレイクイーブンとトレーリングストップとして使用する値を指定します
  • 未決注文をストップポイントとして使用します
  • 終値に基づく14期間RSIの使用を示します
  • 買われ過ぎと売られ過ぎの値はここに入力され後で使用するために保存されます.。

このプロセスがいかにシンプルかおわかりでしょうか。iRSIの代わりに別の指標を使うことができます。次のステップは次の計算です。

inline eTrigger CheckTrigger(void)
                        {
                                int iRet;
                                        
                                if (((iRet = iBars(NULL, m_TF)) > m_nBars) && (m_Handle != INVALID_HANDLE))
                                {
                                        if (CopyBuffer(m_Handle, 0, 0, m_Infos.Shift + 1, m_Buff) < m_Infos.Shift + 1) return TRIGGER_NONE;
                                        m_nBars = iRet;
                                        if ((m_Buff[0] > m_Buff[m_Infos.Shift]) && (m_Buff[0] > m_Infos.OverSold) && (m_Buff[m_Infos.Shift] < m_Infos.OverSold)) return TRIGGER_BUY;
                                        if ((m_Buff[0] < m_Buff[m_Infos.Shift]) && (m_Buff[0] < m_Infos.OverBought) && (m_Buff[m_Infos.Shift] > m_Infos.OverBought)) return TRIGGER_SELL;
                                };
                                return TRIGGER_NONE;
                        }

ここでの計算では、前の例と同じテストを続け、いくつかの詳細を追加します。指標の動きが下向きか上向きかを分析していることにお気づきかもしれません。 この要素は、修正を示唆する可能性があるため、非常に重要です。だからこそ、このような動きに気づくためのシフトがあるのです。しかし、いずれにせよ、指標が売られすぎや買われすぎを指しているかどうかを確認してから、指標がその領域から出たかどうかで2回目の判断をします。 これは売買のトリガーになります

それ以外は大きな変化は見られません。ご覧の通り、手順はいたってシンプルで、分析によって大きく変わることはありません。EAを自動化するために必要なモデルや方法論が何であれ、それを適応させるためのアクションを実行するトリガーを定義するだけです。

しかし、前の例とは異なり、この例ではブレイクイーブンの動きとトレーリングストップを実装します。利益をもたらす動きがあったときに、より収益性の高い方法でポジションを閉じることができるという考えです。この変更は、以下のコードを追加することで実装されます。

inline virtual void Triggers(void) final
                        {
                                if (!CtrlTimeIsPassed()) ClosePosition(); else switch (CheckTrigger())
                                {
                                        case TRIGGER_BUY:
                                                if (m_Memory == TRIGGER_SELL) ClosePosition();
                                                if (m_Memory != TRIGGER_BUY) ToMarket(ORDER_TYPE_BUY);
                                                m_Memory = TRIGGER_BUY;
                                                break;
                                        case TRIGGER_SELL:
                                                if (m_Memory == TRIGGER_BUY) ClosePosition();
                                                if (m_Memory != TRIGGER_SELL) ToMarket(ORDER_TYPE_SELL);
                                                m_Memory = TRIGGER_SELL;
                                                break;
                                }
                                TriggerTrailingStop();
                        };

なお、手順はオリジナルからほとんど変わっていません。しかし、ブレイクイーブンとトレーリングストップを実装するためにこの呼び出しを追加しました。ご覧のとおり、システムには後で使用するためのすべての詳細がすでに用意されており、必要な場合に応じてニーズに適応できるため、重要なのは、いつ、どこで呼び出すかということになります。

では、考え方をよりよく理解するために、別の例を見てみましょう。


自動化の例3:移動平均のクロスオーバー

このサンプルはEA_v3.mq5ファイルで入手できますが、最も基本的な自動化・プロセスだけで終わらせるつもりはありません。最初のものは、自動化システムにロングポジションかショートポジションかを知らせるルーチンの作成です。以下に示します。

const bool IsBuyPosition(void) const
                        {
                                return m_Position.IsBuy;
                        }

この関数は、実際には、ポジションが開いているかどうかを確認するのではなく、変数が買いか売りかを示しているかどうかを返すだけです。実際にポジションがあるかどうかを確認するのではなく、買われたか売られたかを返すのです。ただし、お使いの自動化システムがその検証を必要とする場合、ポジションがあるかどうかを確認することができます。とにかく、この例ではこの関数で十分です。これは、下に来る関数のためです。

                void LockStopInPrice(const double Price)
                        {
                                if (m_InfosManager.IsOrderFinish)
                                {
                                        if (m_Pending.Ticket == 0) return;
                                        if ((m_Pending.PriceOpen > Price) && (m_Position.IsBuy)) return;
                                        if ((m_Pending.PriceOpen < Price) && (!m_Position.IsBuy)) return;
                                        ModifyPricePoints(m_Pending.Ticket, m_Pending.PriceOpen = Price, m_Pending.SL = 0, m_Pending.TP = 0);
                                }else
                                {
                                        if (m_Position.SL == 0) return;
                                        if ((m_Position.SL > Price) && (m_Position.IsBuy)) return;
                                        if ((m_Position.SL < Price) && (!m_Position.IsBuy)) return;
                                        ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, Price, m_Position.TP);
                                }
                        }

この関数は、あるポイントに逆指値を設定するためのものです。実際、ブレイクイーブンがすでに有効になっている場合、トレーリングストップコードと同じ動作をおこないます。しかし、取引の種類によっては、ポジションを損切りせず、前のバーの高値や安値、移動平均線が示す価格、または他の自動化メカニズムなど、何らかの基準に基づいてストップロスを移動させます。この場合、このタスクを実行するための特別な関数が必要になります。 指定された方向に値が動くと損失が大きくなるため、それを防ぐ仕組みがあることにご注意ください。 このタイプのロックは、特に移動平均に基づく値を送信したい場合に非常に重要です。

これに基づいて、トレーリングストップ関数のコードを以下に示します。

inline void TriggerTrailingStop(void)
                        {
                                double price, v1;
                                
                                if ((m_Position.Ticket == 0) || (m_InfosManager.IsOrderFinish ? m_Pending.Ticket == 0 : m_Position.SL == 0)) return;
                                if (m_Position.EnableBreakEven) TriggerBreakeven(); else
                                {
                                        price = SymbolInfoDouble(_Symbol, (GetTerminalInfos().ChartMode == SYMBOL_CHART_MODE_LAST ? SYMBOL_LAST : (m_Position.IsBuy ? SYMBOL_ASK : SYMBOL_BID)));
                                        v1 = (m_InfosManager.IsOrderFinish ? m_Pending.PriceOpen : m_Position.SL);
                                        if (v1 > 0) if (MathAbs(price - v1) >= (m_Position.Gap * 2)) 
                                                LockStopInPrice(v1 + (m_Position.Gap * (m_Position.IsBuy ? 1 : -1)));
                                        {                                               
                                                price = v1 + (m_Position.Gap * (m_Position.IsBuy ? 1 : -1));
                                                if (m_InfosManager.IsOrderFinish) ModifyPricePoints(m_Pending.Ticket, m_Pending.PriceOpen = price, m_Pending.SL = 0, m_Pending.TP = 0);
                                                else    ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, price, m_Position.TP);
                                        }
                                }
                        }

コードの再利用を改善するための専用の呼び出しがあるため、取り消し線の部分は削除されました。

さて、C_Managerクラスの変更を実装したので、この3つ目の例を作成する方法を見てみましょう。これらはケースによって異なる場合があります。しかし、自動化を実現するためのプランニングには常に注意を払う必要があります。そして、ここでの自動化には、これまでのケースよりも少し多くのものが必要なので、必要な変更を見てみましょう。これらの変更は、2つの指標を同時に使用するモデルにとっては十分なものでしょう。

まずは変数の宣言から始めます。

class C_Automaton : public C_Manager
{
        protected:
                enum eTrigger {TRIGGER_NONE, TRIGGER_BUY, TRIGGER_SELL};
        private :
                enum eSelectMedia {MEDIA_FAST, MEDIA_SLOW};
                struct st00
                {
                        int     Shift,
                                nBars;
                        double  OverBought,
                                OverSold;
                }m_Infos;
                struct st01
                {
                        double  Buff[];
                        int     Handle;
                }m_Op[sizeof(eSelectMedia) + 1];
                int     m_nBars;
                ENUM_TIMEFRAMES m_TF;

ここでは、MAデータに高レベル言語でアクセスするのに役立つ列挙を用意し、計算プログラミング時のエラーを回避しています。

次にあるのは、バッファと指標のハンドルの両方にアクセスするための構造体です。 この構造体は配列として宣言されており、この配列のサイズは列挙に含まれるデータ量に1を足したものであることにご注意ください。つまり、使用する要素の数に関係なく、列挙に追加するだけでいいのです。こうすることで、配列はこれから作ろうとしている最終的なモデルに適応します。

ある意味、これはデフォルトのクラスモデルよりも良い選択肢ですが、よりシンプルなモデルを実装することができたので、まずそれを実装しました。こうして、すべてが明確になり、理解しやすくなるように思います。

C_Automaton クラスにいくつかの指標を追加する方法が、とても簡単に理解できたと思います。しかし、クラスのコンストラクタで実際に初期化する方法を見てみましょう。

                C_Automaton(const ulong magic, double FinanceStop, double FinanceTake, uint Leverage,
                                                bool IsDayTrade, double Trailing, const ENUM_TIMEFRAMES iPeriod,
                                                const double OverBought = 70, const double OverSold = 30, const int iShift = 1)
                        :C_Manager(magic, FinanceStop, FinanceTake, Leverage, IsDayTrade, Trailing, true, 10),
                         m_TF(iPeriod)
                        {
                                for (int c0 = sizeof(eSelectMedia); c0 <= 0; c0--)
                                {
                                        m_Op[c0].Handle = INVALID_HANDLE;
                                        ArraySetAsSeries(m_Op[c0].Buff, true);
                                }
                                m_Infos.Shift      = (iShift < 3 ? 3 : iShift);
                                m_Infos.OverBought = OverBought;
                                m_Infos.OverSold   = OverSold;
                                m_nBars = iBars(NULL, m_TF);
                                m_Op[MEDIA_FAST].Handle = iMA(NULL, m_TF, 9, 0, MODE_EMA, PRICE_CLOSE);
                                m_Op[MEDIA_SLOW].Handle = iMA(NULL, m_TF, 20, 0, MODE_SMA, PRICE_CLOSE);
                        }

ここからマジックが始まります。、すべての指標をデフォルトで初期化する方法をご覧ください。最も簡単な方法は、このループを使うことです。列挙された指標の数を気にする必要はありません。このループがすべてを管理することができるからです。

次は、私たちが本当に注目しなければならない点です。この段階では、すべての指標が同じ時間枠を使用しますが、指標によって異なる時間枠が必要な場合もあり、その場合、コンストラクタのコードを調整する必要があります。ただし、変更は最小限にとどまり、作成した特定のモデルにのみ適用されます。

ただし、後で使用するハンドルをキャプチャする際には注意が必要です。 それぞれの指標が正しくインスタンス化されるように、それらをキャプチャしなければなりません。これが正しくおこなわれないと、モデルに問題が生じる可能性があります。ここでは、9周期の指数移動平均と20周期の算術移動平均をシステムで使用することを示しています。ただし、お使いの操作システムに必要であれば、異なる指標を組み合わせることもできます。

重要な注意: ここでひとつ重要なことがあります。 作成したカスタム指標を使用する場合は、資産チャートに表示する必要はありません。しかし、標準の指標にはないため、このカスタム指標のデータを取得するためにハンドルを開始するには、 iCustom関数を使用する必要があります。カスタム指標にアクセスできるようにするには、この関数の使用方法をドキュメントで参照してください。繰り返しになりますが、必ずしもチャート上である必要はありません。

この瞬間は本当に重要なので注意を払ってください。EAでオフセット値を通知しない場合、実際にはデフォルト値を使用することはできません。というのも、デフォルト値を使用すると、実際に平均のクロスオーバーを確認するのが難しくなるからです。オフセットの最小値を示さなければなりませんが、これは3の値です。トリガーをより敏感にするために2を使うこともできます 。 しかし、適切な分析ができないため、1の値を使用することはできません。その理由を理解するために、計算の方法を見てみましょう。

コンストラクタで使用するデータを正しく初期化したら、トリガーメカニズムがEAを自動的に作動させることができるように、計算を担当する部分を作る必要があります。機構に複数の指標がある場合、システムは1つの指標だけを使う場合とは少し違った動きをするはずです。これは次のコードからわかります。

inline eTrigger CheckTrigger(void)
                        {
                                int iRet;
                                bool bOk = false;
                                        
                                if (iRet = iBars(NULL, m_TF)) > m_nBars)
                                {
                                        for (int c0 = sizeof(eSelectMedia); c0 <= 0; c0--)
                                        {
                                                if (m_Op[c0].Handle == INVALID_HANDLE) return TRIGGER_NONE;
                                                if (CopyBuffer(m_Op[c0].Handle, 0, 0, m_Infos.Shift + 1, m_Op[c0].Buff) < m_Infos.Shift + 1) return TRIGGER_NONE;
                                                bOk = true;
                                        }
                                        if (!bOk) return TRIGGER_NONE; else m_nBars = iRet;
                                        if ((m_Op[MEDIA_FAST].Buff[1] > m_Op[MEDIA_SLOW].Buff[1]) && (m_Op[MEDIA_FAST].Buff[m_Infos.Shift] < m_Op[MEDIA_SLOW].Buff[m_Infos.Shift])) return TRIGGER_BUY;
                                        if ((m_Op[MEDIA_FAST].Buff[1] < m_Op[MEDIA_SLOW].Buff[1]) && (m_Op[MEDIA_FAST].Buff[m_Infos.Shift] > m_Op[MEDIA_SLOW].Buff[m_Infos.Shift])) return TRIGGER_SELL;
                                };
                                return TRIGGER_NONE;
                        }

使用する指標の数を気にすることなくタスクを実行するループを使用しています。しかし、これらすべてがコンストラクタで正しく初期化されていることが極めて重要です。なぜなら、これがなければ、計算ステージは売買トリガーを生成できないからです。

まず、指標IDが正しく初期化されているかどうかを確認します。そうでない場合は、有効なトリガーがないことになります 。この確認が完了したら、指標バッファからデータの取り込みを開始しますこの機能を使うことに疑問がある場合は、ドキュメントのCopyBuffer関数について読むことをお勧めします。この機能は、カスタム指標を使用する場合に特に便利です。

すべての指標とそれぞれのバッファが揃ったら、計算の部分に移りましょう。でも、少し待ってください。計算前のコードは何なのでしょうか。 このコードは、列挙子のNULLリストを配置してしまった場合の回避に役立ちます。この場合、計算システムは作動しません。このコードがなければ、列挙体のリストがNULLであっても計算がトリガーされてしまいます。これはシステムの堅牢性を完全に破壊することになります。MAクロスオーバーを使っているため、ここでは非常に注意しなければなりません。

バッファに存在するゼロ(最新)の値を無謀に確認しているわけではないことに注意してください。その理由は、時間枠が実際にクローズする前に、平均線が偽のクロスオーバーを起こしてそれが偶発的なトリガーにつながる可能性があるからです。

システムがバッファを確認するのは、新しいバーが生成されたときだけでしょうか。答えは「はい」ですが、バーが形成される正確な時刻に平均が交差すれば、システムは注文をトリガーします。したがって、直近の値は無視し、直前の値を分析します。このため、感度を最大にするためにオフセットを少なくとも2、またはこの例でおこなっているように3に設定し、形成されるバーから少し離れた位置でクロスオーバーが起こるようにします。ただし、他の計算方法を使うこともできます。これはデモンストレーションのために提供されているものなので、決して実際の口座では使用しないでください。

この最後のモデルを完成させるために、システムに関する他のものを見てみましょう。

inline virtual void Triggers(void) final
                        {
#define def_HILO 20
                                if (!CtrlTimeIsPassed()) ClosePosition(); else switch (CheckTrigger())
                                {
                                        case TRIGGER_BUY:
                                                if (m_Memory == TRIGGER_SELL) ClosePosition();
                                                if (m_Memory != TRIGGER_BUY) ToMarket(ORDER_TYPE_BUY);
                                                m_Memory = TRIGGER_BUY;
                                                break;
                                        case TRIGGER_SELL:
                                                if (m_Memory == TRIGGER_BUY) ClosePosition();
                                                if (m_Memory != TRIGGER_SELL) ToMarket(ORDER_TYPE_SELL);
                                                m_Memory = TRIGGER_SELL;
                                                break;
                                }
                                LockStopInPrice(IsBuyPosition() ?  iLow(NULL, m_TF, iLowest(NULL, m_TF, MODE_LOW, def_HILO, 0)) : iHigh(NULL, m_TF, iHighest(NULL, m_TF, MODE_HIGH, def_HILO, 0)));
#undef def_HILO
                        };

この関数の大きな利点は、まさにこのコードにあります。したがって、注文またはストップ価格は、状況に応じて、買いか売りかに応じて、高値または安値になります。使用される値は、多くのB3トレーダーが知っているHILO指標に非常に似ています。ご存じない方のために説明すると、この指標は、一定のバー数内で価格の高値または安値を探します。このコードにはその責任があります:ここではLO値 を探しており 、ここではHI値を探しています。どちらの場合もHILOは20です

これで3つ目の例は完了です。


まとめ

この小さなシーケンスでは、自動的に動作するEAを開発する方法を紹介しました。遊び心を持ってシンプルに示そうとしました。このプレゼンテーションがあったとしても、実際にEAを開発する方法を学ぶには、ある程度の勉強と時間が必要です。

自動的に機能するEAを作成する際にプログラマーの作業に影響するような主な失敗、問題、困難について説明しましたが、それが多くの知識をもたらし、実際の市場観察の方法を変える可能性があることもお見せしました。

安全で信頼性が高く、堅牢なシステムを実際に作ることができるように、提示をおこないました。同時に、モジュール式でコンパクト、そして非常に軽量でなければなりません。そして、他の多くのものと組み合わせて使うこともできなければなりません。同時にいろいろなことが操作できないようなシステムには意味がありません。というのも、1つの資産だけを取引していても、実際に利益を上げられるとは限らないからです。

おそらく読者の多くは、この連載の、3つの実践的な例を使ってこの考え方を説明した以前の記事に興味を持つでしょう。ただし、この記事を活用するためには、連載全体の知識が必要であることにご注意ください。プログラミングの天才である必要はないし、何科目もクラスを取って卒業する必要もないということを、とてもシンプルな方法で伝えることができたと思います。MetaTrader 5プラットフォームとMQL5言語がどのように機能するかを本当に理解する必要があります。

また、使用したい指標がMQL5やMetaTrader5がにない場合でも、効率的な作業システムのための特定の状況を作り出す方法も紹介しました。例3で示した、HILO指標を内部的に作成する方法です。しかし、それとは関係なく、システムは常に正しく実装され、テストされるべきです。素晴らしいシステムを作っても、結局何の利益も得られないのでは意味がないからです。

この連載の最後に、可能な選択肢をすべて網羅したわけではないことを強調しておきたいと思います。自動化されたEAを作成するためのモデリングライブラリを作成するまでの詳細を掘り下げることは考えていません。このテーマについては、また新しい連載で、市場初心者のための便利なツールの開発についてお話ししたいと思います。

自動化されたEAの実際のテストは、MetaTrader 5ストラテジーテスターでおこなわれるのではなく、本格的なマーケットワークのあるデモ口座でおこなわれることを覚えておいてください。そこでは、EAはその実際のパフォーマンスを隠すことができる設定なしでテストされます。この連載はこれで終わりです。この連載で取り上げたコードはすべて添付されているので、自動EAがどのように機能するかを本当に理解するためには、それらを研究・分析してください。


重要:添付のEAを正しい知識なしに使用しないでください。このようなEAは、実証的かつ教育的な使用のみを目的として提供されています。

実際の口座で使用する場合は、自己責任でおこなってください。


MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/11438

添付されたファイル |
Rebuyのアルゴリズム:効率を上げるための数学モデル Rebuyのアルゴリズム:効率を上げるための数学モデル
この記事では、取引システムの効率をより深く理解するためにRebuyアルゴリズムを使用し、数学と論理を使用して取引効率を向上させる一般的な原則に着手し、どのような取引システムでも制約なく使用するという観点から、最も非標準的な、効率を高める方法を適用します。
自動で動くEAを作る(第14回):自動化(VI) 自動で動くEAを作る(第14回):自動化(VI)
今回は、この連載で得た知識をすべて実践してみましょう。最終的には、100%自動化された機能的なシステムを構築します。しかしその前に、まだ最後の詳細を学ばなければなりません。
MQL5における行列とベクトル:活性化関数 MQL5における行列とベクトル:活性化関数
ここでは、機械学習の一側面である活性化関数についてのみ説明します。人工ニューラルネットワークでは、ニューロンの活性化関数は、入力シグナルまたは入力シグナルのセットの値に基づいて出力シグナル値を計算します。その内幕に迫ります。
多層パーセプトロンとバックプロパゲーションアルゴリズム(その3):ストラテジーテスターとの統合 - 概要(I) 多層パーセプトロンとバックプロパゲーションアルゴリズム(その3):ストラテジーテスターとの統合 - 概要(I)
多層パーセプトロンは、非線形分離可能な問題を解くことができる単純なパーセプトロンを進化させたものです。バックプロパゲーションアルゴリズムと組み合わせることで、このニューラルネットワークを効果的に学習させることができます。多層パーセプトロンとバックプロパゲーション連載第3回では、このテクニックをストラテジーテスターに統合する方法を見ていきます。この統合により、取引戦略を最適化するためのより良い意思決定を目的とした複雑なデータ分析が可能になります。この記事では、このテクニックの利点と問題点について説明します。