
EAコンストラクタの開発の試み
内容
- はじめに
- 1. コンストラクタ使用後のEA機能
- 2. コンストラクタの一般的なアルゴリズム
- 3. 標準指標の追加 — Code.mq5指標ファイルの処理
- 4. カスタム指標の追加
- 5. トランザクションの取得(簡略化されたコード)
- 6. コンストラクタを使用したEA(ポジション開始シグナル)の作成
- 7. コンストラクタを使用したEA(未決注文シグナル)の作成
- 終わりに
はじめに
当初から、私の目的は標準ライブラリを使用することでした。最初のタスクは、最も単純な機能を実装することでした。CTrade取引クラスをインクルードして、BuyまたはSellメソッドを実行します。短く簡潔なコードが生成されるため、標準ライブラリを選択しました。以下の短いコードはスクリプトの形で実行されて1.0ロットのボリュームで買いポジションを開きます。
//+------------------------------------------------------------------+ //| Open Buy.mq5 | //| Copyright © 2018-2021, Vladimir Karputov | //+------------------------------------------------------------------+ #property copyright "Copyright © 2018-2021, Vladimir Karputov" #property version "1.001" //--- #include <Trade\Trade.mqh> CTrade m_trade; // trading object //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- m_trade.Buy(1.0); // open Buy position, volume 1.0 lot }
徐々に要件が複雑になり、新しいエキスパートアドバイザー(EA)を作成するたびに取引エラーに遭遇するようになったため、正しいコードを書きたいという私の願望はますます強くなりました。最後に、非常に重要な「マーケットでの公開前にトレードロボットに行うべき検査」稿が公開されました。この記事が公開されたとき、私はすでに取引注文の実行に対する信頼できる制御機能の必要性を認識していました。その瞬間から、コピー->ペーストを使用してEAに簡単に追加できる実証済みの機能を徐々に取得し始めました。
EAの作業はほとんどの場合指標の使用を伴うため、指標ハンドルを正しく作成し、指標データを受信するための関数を取得し始めました。
NB: MQL5スタイルは、指標ハンドルが1回作成されることを意味します。原則として、これはOnInitで行われます。
バージョン2.XXX頃から、2つの開発ブランチを維持し始めました。通常の手続き型コードとクラス形式のコード(クラスの主な目的はマルチカレンシーEAの実装)です。
作業の過程で、コンストラクタに徐々に最も人気のある設定を追加しました。
- 決済逆指値と決済指値
- トレール注文
- リスクパーセンテージまたは一定/最小ロットとしてのロット計算
- 取引が行われる時間間隔の制御
- 市場での1つのポジションだけの存在
- 取引シグナルの逆転
- 反対のシグナルが表示された場合のポジションの強制決済
各入力には、コードブロックと新しい関数の作成が含まれていました。
日常的に使用するために、最も人気のあるすべての機能と入力のフルセットをTrading engine 3.mq5 EAに収集することにしました。実際、これは既製のEAであり、多くの日常業務から解放されます。 しなければならないのは、関数を追加/削除するか、それぞれの特定の場合にコードブロック間の相互作用を変更することだけです。
1. コンストラクタ後のEA機能
コンストラクタによって作成されたEAは、すぐに複数の設定を備えており、それらを組み合わせて独自のストラテジーを作成できます。バージョン4.XXXでは、次のルールを適用します。
- 現在の銘柄(EAが起動されるチャートの銘柄)が使用される
- テイクプロフィット、ストップロス、トレーリングは入力のポイントで設定されるポイント - 相場の通貨での現在の銘柄ポイントサイズ。たとえば、「EURSD」では1.00055-1.00045=10ポイント。
十字ツールをドラッグすると、銘柄チャートに「ポイント」が常に表示されます。
図1 ポイント
以下は、コンストラクタを使用して作成されたEAの入力です。
- 取引設定
- Working timeframe - 作業時間枠は、EAが起動されるチャートの時間枠とは異なる場合があります。これは、指標が作成される時間枠です(指標で別の時間枠が明示的に指定されていない場合)。また、新しいバーが作成された瞬間を追跡するためにも使用されます(新しいバーが表示されたときにのみ取引シグナルを検出する必要がある場合、または新しいバーが表示されたときにのみトレーリングを起動する場合)。
- Stop Loss (0 – 無効)
- Take Profit (0 – 無効)
- Trailing on ... — 各ティック(バー#0(すべてのティック))または新しいバーが表示されたときのみ(バー#1(新しいバー))でトレーリング能力を確認します。
- Search signals on ... — 各ティック(バー#0(すべてのティック))または新しいバーが表示されたときのみ(バー#1(新しいバー))で取引シグナルを検索します。
- Trailing Stop (min distance from price to Stop Loss) — 価格とポジションのストップロスの間の最小距離。トレーリングは、ポジション収益性があり、価格がトレーリングストップ+トレーリングステップ分始値から離れる場合にのみアクティブになります。 トレーリング操作はTrailingStopコードイメージに表示されます。
- Trailing Step
- ポジションサイズ管理(ロット計算)
- Money management lot: LotまたはRisk — ロット計算システム。ロットは静的(Money management= Constant lot、ロットサイズは「Money management」の値で設定されます)にも動的にできます。取引ごとのリスク%(Money management= Risk in percent for a deal、リスク%は「Money management」の値に設定されます。最小ロットに等しい定数ロットを設定することもできます(Money management= Lots Min)。
- 「Money management」の値
- 取引モード
- Trade mode: 買いポジションのみを許可、売りポジションのみを許可、 買いと売りのポジションを許可
- DEMA — カスタム指標パラメータ。これは、最終的に指標とそのパラメータを設定する場所です
- DEMA: 平均期間
- DEMA: 水平シフト
- DEMA: 価格の種類
- 時間制御 — 作業時間。取引シグナルの検索が許可されている期間
- Use time control — フラグ、時間制御を有効/無効化
- Start Hour — 期間の開始時間
- Start Minute — 期間の開始分
- End Hour — 期間の終了時間
- End Minute — 期間の終了分
- 未決注文パラメータ — 未決注文に関連するパラメータ
- Pending: Expiration, in minutes (0 - OFF) — 未決注文の有効期限(0 - 無効)
- Pending: Indent — 現在の価格からの未決注文のインデント(未決注文価格が明示的に設定されていない場合)
- Pending: Maximum spread (0 -> OFF) — 最大スプレッド(0 - 無効)現在のスプレッドが指定されたスプレッドを超える場合、未決注文は設定されません(EAはスプレッドが減少するのを待ちます)
- Pending: Only one pending — 有効/無効フラグ。市場で許可されている未決注文は1つだけです
- Pending: Reverse pending type — 有効/無効フラグ未決注文の反転
- Pending: New pending -> delete previous ones — 未決注文を設定する場合は、他のすべての未決注文が事前に削除されます
- 追加機能
- Positions: Only one — 有効/無効フラグ。市場で許可されているポジションは1つだけです
- Positions: Reverse — 有効/無効フラグ。取引注文の反転
- Positions: Close opposite — 有効/無効フラグ。取引注文がある場合、注文を実行できるように、すべてのポジションが事前に決済されます
- Print log — 有効/無効フラグ。操作とエラーに関する拡張情報を表示します
- Coefficient (Freeze==0またはStopsLevels==0の場合) — 係数(Freeze == 0またはStopsLevels == 0の場合) — ストップレベルを考慮した比率
- Deviation — 指定されたずれ
- Magic number — EAの一意のID
2. コンストラクタの一般的なアルゴリズム
SPosition配列は、グローバルプログラムレベル(EAヘッダー内)で宣言され、STRUCT_POSITION構造体で構成されています。起動中、配列のサイズはゼロです。取引シグナルを処理した後、配列もゼロに戻ります。
OnTickから、SearchTradingSignals関数が呼び出されます。シグナルが存在する場合(市場にポジションがない場合)、関数は取引注文を形成します(配列内の取引注文ごとに単一のSTRUCT_POSITION構造体が作成されます)。 取引注文の存在はOnTickでチェックされます。SPosition配列サイズがチェックされ、ゼロを超える場合は取引注文があるので、OpenBuyまたはOpenSellを実行するために送信されます。取引リクエストの実行の制御はOnTradeTransactionで行われます。
図2 一般的なアルゴリズム(単純)
EAは現在の銘柄(EAが配置されているチャート)で機能すると常に想定されています。例: USDPLNに配置されているEAはUSDPLNで機能します。
2.1. STRUCT_POSITION構造体
この構造体はEAの心臓部です。一度に2つの役割が果たされます。構造体は取引注文が設定されているフィールドを特徴とします(設定はSearchTradingSignalsで行われます)。また、構造体は 取引注文の実行を管理するためのフィールドを備えています(制御はOnTradeTransactionで行われます)。
//+------------------------------------------------------------------+ //| Structure Positions | //+------------------------------------------------------------------+ struct STRUCT_POSITION { ENUM_POSITION_TYPE pos_type; // position type double volume; // position volume (if "0.0" -> the lot is "Money management") double lot_coefficient; // lot coefficient bool waiting_transaction; // waiting transaction, "true" -> it's forbidden to trade, we expect a transaction ulong waiting_order_ticket; // waiting order ticket, ticket of the expected order bool transaction_confirmed; // transaction confirmed, "true" -> transaction confirmed //--- Constructor STRUCT_POSITION() { pos_type = WRONG_VALUE; volume = 0.0; lot_coefficient = 0.0; waiting_transaction = false; waiting_order_ticket = 0; transaction_confirmed = false; } };
一部のフィールドは取引注文自体を担当し、その他はその実行を処理します。 構造体には、コンストラクタ(STRUCT_POSITION()特殊関数)が含まれています。これは、構造体オブジェクトを作成するときに呼び出され、構造体要素を初期化するために使用されます。
取引注文フィールド:
- pos_type - 開くポジションのタイプ(POSITION_TYPE_BUYまたはPOSITION_TYPE_SELL)
- volume - ポジションボリューム。ボリュームが0.0の場合、入力の「Position size management (lot calculation)」グループから取得されます
- lot_coefficient - 比率が0.0を超える場合、ポジションボリュームに比率を掛けます
取引注文実行制御のフィールド
- waiting_transaction - 取引注文が正常に実行され、確認を待つ必要があることを示すフラグ
- waiting_order_ticket - 取引注文の実行時に取得された注文のインデックス
- transaction_confirmed - 取引注文の実行が確認されたことを示すフラグ
transaction_confirmedでフラグを有効にすると、取引注文が構造体から削除されます。したがって、EAの操作に取引注文が含まれない場合、構造体のサイズはゼロになります。構造体のフィールドと制御の詳細については、「トランザクションの取得(簡略化されたコード)」セクションを参照してください。
そのようなアルゴリズムを使用する訳
最初は、Buyメソッドのtrueとfalseをチェックして、 trueの場合は、取引注文が実行されたと想定するだけで十分なように思われるかもしれません。多くの場合、このアプローチは実際に機能します。ただし、trueを返しても結果が保証されない場合があります。これは、BuyメソッドとSellメソッドに関するドキュメントに記載されています
メモ
メソッドが正常に完了したからといって、必ずしも取引操作が正常に実行されたとは限りません。ResultRetcode()とResultDeal()から返された値を使用して、取引リクエストの結果を確認する必要があります(取引サーバーリターンコード)。
取引履歴でのエントリの存在は、取引操作の実行の最終的かつ正確な確認として役立つ場合があります。したがって、次のアルゴリズムが選択されています。メソッドが正常に実行された場合は、ResultDeal(取引チケット)を確認し、ResultRetcode(実行結果コードのリクエスト)を確認して、ResultOrder (注文チケット)を保存します。注文チケットはOnTradeTransactionにあります。
3. 標準指標の追加 — Indicators Code.mq5ファイルの処理
さらに便利なように、既製のコードブロック(ハンドルの保存、入力、ハンドルの作成のための変数の宣言)は、Indicators Code.mq5 EAに集められています。ハンドルを格納するための指標入力と変数はEAの「ヘッダー」にあり、ハンドルの作成はOnInitで設定されます。ハンドルを格納するための変数の名前は「handle_」 + 「指標」として形成されます(例: handle_iStdDev)。Indicators Code.mq5の処理全体は、コピー-ペースト操作に要約されます。
NB: MQL5スタイルは、指標ハンドルが1回作成されることを意味します。原則として、これはOnInitで行われます。
3.1. iRVI(Relative Vigor Index、RVI)指標の追加例
Add indicator.mq5 EAを作成します。 MetaEditorで、たとえばをクリックし、[Expert Advisor (template)]を選択してMQLウィザードを実行します。
図3 MQLウィザード ->[Expert Advisor (template)]
次のステップでは少なくとも1つの入力を追加することを強くお勧めします。
図4 Expert Advisor (template) -> パラメータの追加
これにより、入力ブロックの文字列をコードに自動的に追加できます。
//--- input parameters input int Input1=9;
MQLウィザードで空のEAが作成されました。次に、iRVI(Relative Vigor Index、RVI)指標を追加しましょう。Indicators Code.mq5で、 handle_iRVIを検索します(ctrl + Fを使用)。検索により、ハンドルが格納されている変数が生成されます。
図5 RVIの処理
新しく見つかった文字列をコピーし、「Add indicator」EAヘッダーに挿入します。
//--- input parameters input int Input1=9; //--- int handle_iRVI; // variable for storing the handle of the iRVI indicator //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit()
検索を再開して、ハンドル作成ブロックを見つけます。
図6 iRVIの処理
新しく見つかった文字列をコピーし、「Add indicator」EAのOnInitに挿入します。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create handle of the indicator iRVI handle_iRVI=iRVI(m_symbol.Name(),Inp_RVI_period,Inp_RVI_ma_period); //--- if the handle is not created if(handle_iRVI==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iRVI indicator for the symbol %s/%s, error code %d", m_symbol.Name(), EnumToString(Inp_RVI_period), GetLastError()); //--- the indicator is stopped early m_init_error=true; return(INIT_SUCCEEDED); } //--- return(INIT_SUCCEEDED); }
次に、指標の入力を追加しましょう。Indicators Code.mq5で、たとえばInp_RVI_periodを中クリックして、入力ブロックにすぐに移動します。
図7 iRVIの処理
文字列をコピーして、入力に挿入します。
#property version "1.00" //--- input parameters input group "RVI" input ENUM_TIMEFRAMES Inp_RVI_period = PERIOD_D1; // RVI: timeframe input int Inp_RVI_ma_period = 15; // RVI: averaging period //--- int handle_iRVI; // variable for storing the handle of the iRVI indicator //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+
コンパイルすると、m_symbolおよびm_init_errorエラーが発生します。これらの変数はコンストラクタ操作後に取得されたコードに存在するため、これは予想される動作です。一方、「Add indicator」EAは、Indicators Code.mq5ファイルの処理を示すためだけに作成されています。
4. カスタム指標の追加
MA on DeMarkerカスタム指標を追加します。まず、これはカスタム指標で、次にそれはグループを使用します。前のセクションと同様に、「Add custom indicator」EAを作成します。その後、カスタム指標から入力をコピーしてEAに挿入します。
#property version "1.00" //--- input parameters input group "DeMarker" input int Inp_DeM_ma_period = 14; // DeM: averaging period input double Inp_DeM_LevelUP = 0.7; // DeM: Level UP input double Inp_DeM_LevelDOWN = 0.3; // DeM: Level DOWN input group "MA" input int Inp_MA_ma_period = 6; // MA: averaging period input ENUM_MA_METHOD Inp_MA_ma_method = MODE_EMA; // MA: smoothing type //---
Indicators Code.mq5で、カスタム指標ハンドルを格納するためのhandle_iCustom変数を見つけてEAに挿入します 。
//+------------------------------------------------------------------+ //| Add custom indicator.mq5 | //| Copyright © 2021, Vladimir Karputov | //| https://www.mql5.com/en/users/barabashkakvn | //+------------------------------------------------------------------+ #property copyright "Copyright © 2021, Vladimir Karputov" #property link "https://www.mql5.com/en/users/barabashkakvn" #property version "1.00" //--- input parameters input group "DeMarker" input int Inp_DeM_ma_period = 14; // DeM: averaging period input double Inp_DeM_LevelUP = 0.7; // DeM: Level UP input double Inp_DeM_LevelDOWN = 0.3; // DeM: Level DOWN input group "MA" input int Inp_MA_ma_period = 6; // MA: averaging period input ENUM_MA_METHOD Inp_MA_ma_method = MODE_EMA; // MA: smoothing type //--- int handle_iCustom; // variable for storing the handle of the iCustom indicator //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit()
Indicators Code.mq5のOnInit()でカスタム指標ハンドル作成ブロックを見つけてEAに挿入します。
int handle_iCustom; // variable for storing the handle of the iCustom indicator //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create handle of the indicator iCustom handle_iCustom=iCustom(m_symbol.Name(),Inp_DEMA_period,"Examples\\DEMA", Inp_DEMA_ma_period, Inp_DEMA_ma_shift, Inp_DEMA_applied_price); //--- if the handle is not created if(handle_iCustom==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d", m_symbol.Name(), EnumToString(Inp_DEMA_period), GetLastError()); //--- the indicator is stopped early m_init_error=true; return(INIT_SUCCEEDED); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function |
ここでやるべきことがいくつかあります。時間枠(InpWorkingPeriod)、指標へのパス(指標フォルダのルートに保存されていると想定)、および入力を設定する必要があります。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create handle of the indicator iCustom handle_iCustom=iCustom(m_symbol.Name(),InpWorkingPeriod,"MA on DeMarker", "DeMarker", Inp_DeM_ma_period, Inp_DeM_LevelUP, Inp_DeM_LevelDOWN, "MA", Inp_MA_ma_period, Inp_MA_ma_method); //--- if the handle is not created if(handle_iCustom==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d", m_symbol.Name(), EnumToString(InpWorkingPeriod), GetLastError()); //--- the indicator is stopped early m_init_error=true; return(INIT_SUCCEEDED); } //--- return(INIT_SUCCEEDED); }
5. トランザクションの取得(簡略化されたコード)
注意: これはEAの簡略版です。多くの関数のコードは本格的なコンストラクタに比べて短くなっています。
このEAによって開かれたポジションが市場にない場合、買いポジションを開くように取引要求を設定します。ポジションを開くための確認は、OnTradeTransactionとOnTickから出力されます。以下は、SearchTradingSignals関数での取引注文の検索と書き込みです。
//+------------------------------------------------------------------+ //| Search trading signals | //+------------------------------------------------------------------+ bool SearchTradingSignals(void) { if(IsPositionExists()) return(true); //--- int size_need_position=ArraySize(SPosition); if(size_need_position>0) return(true); ArrayResize(SPosition,size_need_position+1); SPosition[size_need_position].pos_type=POSITION_TYPE_BUY; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY"); return(true); }
市場にEAによって開かれたポジションがなく、SPosition配列サイズがゼロの場合は、配列サイズを1つ増やします。したがって、単一のSTRUCT_POSITION構造体オブジェクトを作成します。これにより、STRUCT_POSITION()コンストラクタが呼び出されます。コンストラクタを呼び出した後、構造体要素が初期化されます(たとえば、volume - ポジションボリュームは0.0に設定されるので、入力の「Position size management (lot calculation)」グループから取得されます。次に取引注文タイプを構造体に設定するだけです。この場合、「買いポジションを開く」と解釈できます。
取引注文を設定した後、SPosition配列は単一の構造体で構成され、構造体要素の値は次のとおりです。
要素 | 値 | メモ |
---|---|---|
pos_type | POSITION_TYPE_BUY | SearchTradingSignalsで設定 |
取引量 | 0.0 | 構造体コンストラクタで初期化 |
lot_coefficient | 0.0 | 構造体コンストラクタで初期化 |
waiting_transaction | false | 構造体コンストラクタで初期化 |
waiting_order_ticket | 0 | 構造体コンストラクタで初期化 |
transaction_confirmed | false | 構造体コンストラクタで初期化 |
5.1. 新しいティックでOnTickに到達する
以下は、OnTickの一般原則です。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- int size_need_position=ArraySize(SPosition); if(size_need_position>0) { for(int i=size_need_position-1; i>=0; i--) { if(SPosition[i].waiting_transaction) { if(!SPosition[i].transaction_confirmed) { if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","transaction_confirmed: ",SPosition[i].transaction_confirmed); return; } else if(SPosition[i].transaction_confirmed) { ArrayRemove(SPosition,i,1); return; } } if(SPosition[i].pos_type==POSITION_TYPE_BUY) { SPosition[i].waiting_transaction=true; OpenPosition(i); return; } if(SPosition[i].pos_type==POSITION_TYPE_SELL) { SPosition[i].waiting_transaction=true; OpenPosition(i); return; } } } //--- search for trading signals only at the time of the birth of new bar if(!RefreshRates()) return; //--- search for trading signals if(!SearchTradingSignals()) return; //--- }
OnTickの開始時に、SPosition配列のサイズを確認します(これはSTRUCT_POSITION構造体配列です)。配列サイズがゼロを超える場合、次の2つのシナリオを使用して、ゼロへのトラバースを開始します。
- waiting_transaction構造体フラグがtrueの場合(取引注文が準備されている場合は、 確認を待つ)、transaction_confirmedフラグを確認します。
- falseの場合、トランザクションはまだ確認されていません(たとえば、 OnTradeTransactionにはまだ確認がないが、取引注文が送信され、新しいティックが到着した場合に発生する可能性があります)。適切なメッセージを印刷してreturnで終了します。新しいティックで情報が更新されることを期待して、新しいティックを待ちます。
- trueの場合、トランザクションは確認されています。配列から構造を削除し、returnで終了します。
-
waiting_transaction構造体フラグがfalse(取引注文が指定されたばかりで、まだ実行されていない)、waiting_transactionフラグを有効にして、注文をOpenPositionにリダイレクトします。コードブロックは、次のように簡略化できます。
SPosition[i].waiting_transaction=true; OpenPosition(i); return;
ただし、EAコンストラクタの完全な形式を理解しやすくするために、このままにしておきます。
if(SPosition[i].pos_type==POSITION_TYPE_BUY) { if(InpCloseOpposite) { if(count_sells>0) { ClosePositions(POSITION_TYPE_SELL); return; } } if(InpOnlyOne) { if(count_buys+count_sells==0) { SPosition[i].waiting_transaction=true; OpenPosition(i); return; } else { ArrayRemove(SPosition,i,1); return; } } SPosition[i].waiting_transaction=true; OpenPosition(i); return; } if(SPosition[i].pos_type==POSITION_TYPE_SELL) { if(InpCloseOpposite) { if(count_buys>0) { ClosePositions(POSITION_TYPE_BUY); return; } } if(InpOnlyOne) { if(count_buys+count_sells==0) { SPosition[i].waiting_transaction=true; OpenPosition(i); return; } else { ArrayRemove(SPosition,i,1); return; } } SPosition[i].waiting_transaction=true; OpenPosition(i); return; }
追跡を続けましょう。次のコードブロックを思い出してください。
if(SPosition[i].pos_type==POSITION_TYPE_BUY) { SPosition[i].waiting_transaction=true; OpenPosition(i); return; }
取引注文が構造体に設定され(SearchTradingSignals関数で)、waiting_transactionフラグがfalseに設定されています。したがって、waiting_transactionフラグをtrueに設定し、iパラメータをOpenPosition関数に渡します。これは、OpenPosition配列の構造体のシリアル番号です。取引注文タイプはPOSITION_TYPE_BUYであるため、構造体のシリアル番号をOpenBuy関数に渡します。
5.2. OpenBuy関数
この関数の目的は、予備テストに合格し、BUYを開くための取引リクエストを送信し、結果をすぐに追跡することです。
1番目のチェック - SYMBOL_VOLUME_LIMIT
SYMBOL_VOLUME_LIMIT | この銘柄のポジションと一方向(買いまたは売り)の未決注文の最大許容合計ボリューム。たとえば、上限が5ロットの場合、5ロットのポジションがあって5ロットの売り指値注文も行うことができます。ただし、この場合、買い指値注文を出すことはできません(一方向の総量が指値を超えるため)。また、5ロットを超える売り指値注文を出すことはできません。 |
チェックに通らなかった場合は、構造体要素をSPosition配列から削除します。
2番目のチェック - 証拠金
取引操作後に残っている余剰証拠金(FreeMarginCheck)と取引操作に必要な証拠金(MarginCheck )を取得します。その後、念のために、合計を少なくともFreeMarginCheckと等しくするようにしてください。
if(free_margin_check>margin_check)
チェックに通らなかった場合は、free_margin_check変数を出力し、SPosition配列から構造体要素を削除します。
3番目のチェック - 買い操作のブール結果
Buyメソッドがfalseを返した場合は、エラーを出力し、waiting_transactionをfalseに設定します(最も一般的な理由はエラー10004のリクオートです)。したがって、新しいチケットで買いポジションを再開する試みが行われます。結果がtrueの場合(以下はBuyメソッドが trueを返すコードブロックです)。
if(m_trade.ResultDeal()==0) { if(m_trade.ResultRetcode()==10009) // trade order went to the exchange { SPosition[index].waiting_transaction=true; SPosition[index].waiting_order_ticket=m_trade.ResultOrder(); } else { SPosition[index].waiting_transaction=false; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", ERROR: ","#1 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); } if(InpPrintLog) PrintResultTrade(m_trade,m_symbol); } else { if(m_trade.ResultRetcode()==10009) { SPosition[index].waiting_transaction=true; SPosition[index].waiting_order_ticket=m_trade.ResultOrder(); } else { SPosition[index].waiting_transaction=false; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","#2 Buy -> true. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); } if(InpPrintLog) PrintResultTrade(m_trade,m_symbol); }
その後ResultDeal(取引チケット)を確認します。
取引チケットがゼロの場合、ResultRetcode(リクエスト実行結果コード)を確認します。結果のリターン コードは1000です(たとえば、取引注文は取引所などの外部取引システムに送信されたため、取引チケットがゼロです)。waiting_transactionをtrueに設定します。 waiting_order_ticketはResultOrder (注文チケット)を含みます。それ以外の場合(戻りコードは10009以外)、waiting_transactionはfalseに設定されてエラーメッセージが印刷されます。
取引チケットがゼロでない場合(たとえば、実行が同じ取引サーバーで実行される場合)、同様のリターンコードチェックを実行し、値をwaiting_transactionおよびwaiting_order_ticketに書き込みます。
5.3. OnTradeTransaction
取引注文が正常に送信された場合は、取引が実行され、取引履歴に記録されたことの確認を待ちます。OnTradeTransactionでは、trans変数(MqlTradeTransaction型の構造体)を使用します。この構造体にある興味のある文字列はdealとtypeの2つだけです。
struct MqlTradeTransaction { ulong deal; // Deal ticket ulong order; // Order ticket string symbol; // Symbol name ENUM_TRADE_TRANSACTION_TYPE type; // Trading transaction type ENUM_ORDER_TYPE order_type; // Order type ENUM_ORDER_STATE order_state; // Order state ENUM_DEAL_TYPE deal_type; // Deal type ENUM_ORDER_TYPE_TIME time_type; // Order type by lifetime datetime time_expiration; // Order expiration time double price; // Price double price_trigger; // Stop Limit order trigger price double price_sl; // Stop Loss level double price_tp; // Take Profit level double volume; // Volume in lots ulong position; // Position ticket ulong position_by; // Opposite position ticket };
OnTradeTransactionがTRADE_TRANSACTION_DEAL_ADDを取得(履歴に取引を追加)するとすぐに、チェックを実行します。HistoryDealSelectを介して履歴内の取引を選択して、選択に失敗した場合は、エラーを出力します。取引が取引履歴に存在する場合は、SPosition配列をループで繰り返します。ループでは、waiting_transactionがtrueに設定されている構造体のみを確認します。 waiting_order_ticketは、選択した取引の注文のチケットと同じです。一致が見つかった場合は、transaction_confirmedをtrueに設定します。これは、取引注文が実行され、確認されたことを意味します。
//+------------------------------------------------------------------+ //| TradeTransaction function | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) { //--- get transaction type as enumeration value ENUM_TRADE_TRANSACTION_TYPE type=trans.type; //--- if transaction is result of addition of the transaction in history if(type==TRADE_TRANSACTION_DEAL_ADD) { ResetLastError(); if(HistoryDealSelect(trans.deal)) m_deal.Ticket(trans.deal); else { Print(__FILE__," ",__FUNCTION__,", ERROR: ","HistoryDealSelect(",trans.deal,") error: ",GetLastError()); return; } if(m_deal.Symbol()==m_symbol.Name() && m_deal.Magic()==InpMagic) { if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL) { int size_need_position=ArraySize(SPosition); if(size_need_position>0) { for(int i=0; i<size_need_position; i++) { if(SPosition[i].waiting_transaction) if(SPosition[i].waiting_order_ticket==m_deal.Order()) { Print(__FUNCTION__," Transaction confirmed"); SPosition[i].transaction_confirmed=true; break; } } } } } } }
新しいティックでOnTickに移動します。transaction_confirmedにtrueがある構造体は、SPosition配列から削除されます。したがって、取引注文は、取引履歴に表示されるまで発行および追跡されています。
6. コンストラクタを使用したEA(ポジション開始シグナル)の作成
EAを開発する前に、その取引ストラテジーについて考える必要があります。iDEMA(二重指数移動平均、DEMA)指標に基づく簡単なストラテジーを考えてみましょう。 これは、コンストラクタで設定されるデフォルトのストラテジーです。オープンシグナルの検出は、新しいバーが表示されたときにのみ試行されますが、取引シグナル自体は順次上下する指標です。
図8 DEMAストラテジー
いかなるストラテジーもパラメータを調整することで大幅に変更できます。たとえば、テイクプロフィットとストップロスをそのままにして、トレーリングを無効にすることができます。またはその逆トレーリングをそのままにして、テイクプロフィットとストップロスを無効にします。買いまたは売りのみを許可することにより、取引の方向性を制限することもできます。時間制御を有効にして夜間の取引を制限したり、逆に夜間のみの取引を設定したりすることもできます。追加機能グループのパラメータを調整して、取引システムを大幅に変更することもできます。
一般に、取引ストラテジーのバックボーンはSearchTradingSignals関数に組み込まれていますが、他のすべてのパラメータは、最適なアプローチを探して市場を「調査」するためのものです。
EAブランクになる新しいファイルを作成しましょう(図3および4に示されている手順を実行します)。手順4で、EAの一意の名前を「iDEMAFullEA.mq5」に指定します。その結果、次のワークピースが得られます。
//+------------------------------------------------------------------+ //| iDEMA Full EA.mq5 | //| Copyright © 2021, Vladimir Karputov | //| https://www.mql5.com/en/users/barabashkakvn | //+------------------------------------------------------------------+ #property copyright "Copyright © 2021, Vladimir Karputov" #property link "https://www.mql5.com/en/users/barabashkakvn" #property version "1.00" //--- input parameters input int Input1=9; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
次に、Trading engine 3.mq5からコード全体をコピーし、文字列の代わりにコードを挿入します。 次に、「EAヘッダー」を編集します。結果の「ヘッダー」は次のようになります。
//+------------------------------------------------------------------+ //| iDEMA Full EA.mq5 | //+------------------------------------------------------------------+ //| Trading engine 3.mq5 | //| Copyright © 2021, Vladimir Karputov | //| https://www.mql5.com/en/users/barabashkakvn | //+------------------------------------------------------------------+ #property copyright "Copyright © 2021, Vladimir Karputov" #property link "https://www.mql5.com/en/users/barabashkakvn" #property version "4.003" #property description "barabashkakvn Trading engine 4.003" #property description "Take Profit, Stop Loss and Trailing - in Points (1.00055-1.00045=10 points)" /* barabashkakvn Trading engine 4.003 */ #include <Trade\PositionInfo.mqh>
「ヘッダー」を次のようにします。
//+------------------------------------------------------------------+ //| iDEMA Full EA.mq5 | //| Copyright © 2021, Vladimir Karputov | //| https://www.mql5.com/en/users/barabashkakvn | //+------------------------------------------------------------------+ #property copyright "Copyright © 2021, Vladimir Karputov" #property link "https://www.mql5.com/en/users/barabashkakvn" #property version "1.001" #property description "iDEMA EA" #property description "Take Profit, Stop Loss and Trailing - in Points (1.00055-1.00045=10 points)" /* barabashkakvn Trading engine 4.003 */ #include <Trade\PositionInfo.mqh>
コンパイルすると、 エラーは発生しません。得られたEAでは取引することさえできます。
6.1. SearchTradingSignals関数
これは、取引注文の可用性をチェックする主な関数です。この関数をブロックごとに考えてみましょう。
バーごとに1つのポジションのみ:
if(iTime(m_symbol.Name(),InpWorkingPeriod,0)==m_last_deal_in) // on one bar - only one deal return(true);
取引時間範囲の確認:
if(!TimeControlHourMinute()) return(true);
指標からのデータ受信指標データはdema配列に渡されます。ArraySetAsSeriesを使用すると、インデックスの逆順が設定されます([0]配列要素は、チャートの右端のバーに対応します)。データはiGetArrayカスタム関数を介して受信されます。
double dema[]; ArraySetAsSeries(dema,true); int start_pos=0,count=6; if(!iGetArray(handle_iCustom,0,start_pos,count,dema)) { return(false); } int size_need_position=ArraySize(SPosition); if(size_need_position>0) return(true);
買いポジション開始シグナル必要に応じて(InpReverse変数はPositionsReverse入力値を格納します)、取引シグナルを反転させることができます。取引の方向性に制限がある場合(InpTradeMode変数はTrade mode:入力値を格納します)、 考慮されます。
//--- BUY Signal if(dema[m_bar_current]>dema[m_bar_current+1] && dema[m_bar_current+1]>dema[m_bar_current+3]) { if(!InpReverse) { if(InpTradeMode!=sell) { ArrayResize(SPosition,size_need_position+1); SPosition[size_need_position].pos_type=POSITION_TYPE_BUY; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY"); return(true); } } else { if(InpTradeMode!=buy) { ArrayResize(SPosition,size_need_position+1); SPosition[size_need_position].pos_type=POSITION_TYPE_SELL; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL"); return(true); } } }
売りシグナルのコードブロックも同様です。
7. コンストラクタを使用したEA(未決注文シグナル)の作成
EAの名前はiDEMA Full EA Pending.mq5になります。iDEMA Full EA.mq5を開き、新しい名前で保存します。
取引ストラテジーは常に最初に開発され、その後にコードが続きます。セクション「6. コンストラクタを使用したEA(ポジション開始シグナル)の作成」で使用されているストラテジーを少し変更してみましょう。買いポジション開始シグナルは買いストップ未決注文1に置き換えられ、売りポジション開始シグナルは売りストップ未決注文に置き換えられます。未決注文には、次のパラメータが使用されます。
- Pending: Expiration, in minutes (0 - OFF) — 600
- Pending: Indent — 現在の価格からの未決注文のインデント(未決注文価格が明示的に設定されていない場合)-> 50
- Pending: Maximum spread (0 -> OFF). 現在のスプレッドが指定されたものを超える場合、未決注文は設定されません(EAはスプレッドが減少するのを待ちます)-> 12
- Pending: Only one pending — 有効/無効フラグ。市場で許可されている未決注文は1つだけです->true
- Pending: Reverse pending type — 有効/無効フラグ未決注文の反転-> false
- Pending: New pending -> delete previous ones — 未決注文を設定する場合は、他のすべての未決注文が事前に削除されます -> true
SearchTradingSignals関数は次のようになります。
//+------------------------------------------------------------------+ //| Search trading signals | //+------------------------------------------------------------------+ bool SearchTradingSignals(void) { if(iTime(m_symbol.Name(),InpWorkingPeriod,0)==m_last_deal_in) // on one bar - only one deal return(true); if(!TimeControlHourMinute()) return(true); double dema[]; ArraySetAsSeries(dema,true); int start_pos=0,count=6; if(!iGetArray(handle_iCustom,0,start_pos,count,dema)) { return(false); } int size_need_pending=ArraySize(SPending); if(size_need_pending>0) return(true); //--- if(InpPendingOnlyOne) if(IsPendingOrdersExists()) return(true); if(InpPendingClosePrevious) m_need_delete_all=true; //--- BUY Signal if(dema[m_bar_current]>dema[m_bar_current+1] && dema[m_bar_current+1]>dema[m_bar_current+3]) { if(!InpReverse) { if(InpTradeMode!=sell) { ArrayResize(SPending,size_need_pending+1); SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP"); return(true); } } else { if(InpTradeMode!=buy) { ArrayResize(SPending,size_need_pending+1); SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL STOP"); return(true); } } } //--- SELL Signal if(dema[m_bar_current]<dema[m_bar_current+1] && dema[m_bar_current+1]<dema[m_bar_current+3]) { if(!InpReverse) { if(InpTradeMode!=buy) { ArrayResize(SPending,size_need_pending+1); SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL STOP"); return(true); } } else { if(InpTradeMode!=sell) { ArrayResize(SPending,size_need_pending+1); SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP; if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP"); return(true); } } } //--- /*if(InpPendingOnlyOne) if(IsPendingOrdersExists()) return(true); if(InpPendingClosePrevious) m_need_delete_all=true; int size_need_pending=ArraySize(SPending); ArrayResize(SPending,size_need_pending+1); if(!InpPendingReverse) SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP; else SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP; SPending[size_need_pending].indent=m_pending_indent; if(InpPendingExpiration>0) SPending[size_need_pending].expiration=(long)(InpPendingExpiration*60); if(InpPrintLog) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");*/ //--- return(true); }
未決注文価格はSPending構造体に設定しません。 これは、現在の価格とインデントが使用されることを意味します。
スプレッドが指定されたものより低くなったときにのみトリガーされた(未決注文が出された)取引シグナルを受け取りました。
図9 iDEMA Full EA Pending
記事に添付されているファイル
名称 | ファイルタイプ | 説明 |
---|---|---|
指標コード | EA | ハンドル、指標入力、指標作成ブロックを格納するための変数 |
Add indicator.mq5 | EA | Add indicator.mq5の操作例 — 標準指標の追加 |
Add custom indicator.mq5 | EA | カスタム指標の追加例 |
Trading engine 4.mq5 | EA | コンストラクタ |
iDEMA Full EA.mq5 | EA | コンストラクタの助けを借りて作成されたEA — ポジション開始シグナル |
iDEMA Full EA Pending.mq5 | EA | コンストラクタの助けを借りて作成されたEA — 未決注文シグナル |
終わりに
この一連の取引機能が、絶えず変化する市場取引条件に対応できる、より信頼性の高いエキスパートアドバイザーの作成に役立つことを願っています。パラメータを試すことを躊躇しないでください。 一部のパラメータを有効にし、他のパラメータを無効にすることで、ストラテジーを大幅に変更できます。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/9717





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索