
運動継続モデル-チャート上での検索と実行統計
- イントロダクション
- モデルの説明-一般的な機能
- チャート上のモデル認識の原理
- アルゴリズムの構築とコードの記述
- インプットパラメータ、OnInit() 関数、および初期変数宣言
- 一般パラメータ
- 配列データの更新
- 極値点 の検索
- モデル認識条件
- コントロールの作成
- 相場参入条件の記述
- トレード条件
- トレーディングオペレーションの操作
- 統計データの収集
- 結論
1. イントロダクション
この記事では、運動継続モデルの1つをプログラムによって定義します。 この主なアイデアは、2つの波の定義です(メインと補正) 極値点については、"潜在的な "フラクタル同様に、まだフラクタルとして形成されていない極値点のフラクタルを適用します。 次に、波の運動に関する統計データを収集します。 このデータは CSV ファイルにアップロードされます。
2. モデルの説明-一般的な機能
この記事で記述されている継続モデルは2つの波から成っています(メインおよび補正)。 このモデルを模式的に図1に示します。 ABは主な波で、BCは補正波で、CDは主なトレンドに向う波です。
図1. 運動継続モデル
チャート上では、次のようになります。
図2. AUDJPY H4 の運動継続モデル
3. チャート上のモデル認識の原理
モデル認識の原則を表1に示します。
表 1. トレンドの文脈における運動継続モデル認識の原理
# | 下降トレンドのモデル認識原理 | # | 上向きのトレンドのモデル認識の原則 |
---|---|---|---|
1 | 極値の足が、前の足の2つの高値/安値以下の高値/安値を有する足である。 | 1 | 極値の足が、前の足の2つの高値/安値以下の高値/安値を有する足である。 |
2 | 補正波は常に上側の極値で終わる (点С-図1および図2参照)。 | 2 | 補正波は常に低い極値で終わる(点С-図1および図2参照)。 |
3 | 補正波の時間は長くできず、いくつかの足に制限する必要があります。 | 3 | 補正波の時間は長くできず、いくつかの足に制限する必要があります。 |
4 | 補正運動の高値 (点С-図1及び図2参照) は、メインの運動の高値より低い (点 A-図1及び図2参照)。 | 4 | 補正運動の安値 (点С-図1及び図2参照) は、メインの運動の安値より高い (点 A-図1及び図2参照)。 |
5 | エントリポイント適時性の原則-ポジションは、エントリポイントの形成の特定の瞬間にのみ開く必要があります | 5 | エントリポイント適時性の原則-ポジションは、エントリポイントの形成の特定の瞬間にのみ開く必要があります |
4. アルゴリズムの構築とコードの記述
1. インプットパラメータ、OnInit() 関数、および初期変数宣言
まず、トレード操作にアクセスするための CTrade class をインクルードする必要があります。
//---ファイルをインクルードする #include <Trade\Trade.mqh> //---トレーディングオペレーションを行うためのオブジェクト CTrade trade;
次に、インプットパラメータを定義します。
//---インプットパラメータ input ENUM_TIMEFRAMES base_tf; //基準期間のタイムフレーム input ENUM_TIMEFRAMES work_tf; //稼働時間の時間枠 input double SummRisk=100; //トレードごとのリスクの合計 input double sar_step=0.1; //パラボリックステップの設定 input double maximum_step=0.11; //パラボリックの最大ステップを設定 input boolTP_mode=true; //TPの設定を許可 input int M=2; //リスク率への利益 input bool Breakeven_mode=true; //ポジションを ブレイクイーブン に移動できるようにする input double ブレイクイーブン=1; //SLへの利益率
基準期間では、このEAはインプットの方向を定義し、タスク期間はエントリポイントの定義に使用します。
このプログラムは、トレードごとのリスクの合計に応じてロットサイズを計算します。
このEAはまた、指定利益 (Мパラメータ)に基づいてテイクプロフィットを設定し、指定された利益に基づいてポジションを ブレイクイーブン に移動することもできます。
インプットパラメータを記述した後、base_tf と work_tf のタイムフレームのインジケータハンドルと配列の変数を宣言します。
//---インジケータハンドルの変数を宣言します。 int Fractal_base_tf,Fractal_work_tf; //iFractals インジケータハンドル int Sar_base_tf,Sar_work_tf; //iSARインジケータハンドル //---base_tf の配列を宣言する double High_base_tf[],Low_base_tf[]; //高値と安値足の価格を格納するための配列 double Close_base_tf[],Open_base_tf[]; //クローズおよびオープン足の価格を格納するための配列 datetime Time_base_tf[]; //足のオープンタイムを格納するための配列 double Sar_array_base_tf[]; //iSAR (パラボリック) インジケータの価格を格納するための配列 double FractalDown_base_tf[],FractalUp_base_tf[];//iFractals インジケータの価格を格納するための配列 //---work_tf の配列を宣言する double High_work_tf[],Low_work_tf[]; double Close_work_tf[],Open_work_tf[]; datetime Time_work_tf[]; double Sar_array_work_tf[]; double FractalDown_work_tf[],FractalUp_work_tf[];;
このEAは2つのインジケータを適用します。( 極値点 の一部を定義するためのフラクタルとポジションのトレーリングストップを維持するためのパラボリック。) また、今回はwork_tf タスク時間枠のエントリポイントを定義するためにパラボリックを使用する予定です。
次に、OnInit() 関数でインジケータハンドルを受け取り、配列に初期データをインプットします。
int OnInit() { //---iSARインジケータハンドルを取得します。 Sar_base_tf=iSAR(Symbol(),base_tf,sar_step,maximum_step); Sar_work_tf=iSAR(Symbol(),work_tf,sar_step,maximum_step); //---iFractals インジケータハンドルの取得 Fractal_base_tf=iFractals(Symbol(),base_tf); Fractal_work_tf=iFractals(Symbol(),work_tf); //---base_tf の時系列のように配列のオーダーを設定します。 ArraySetAsSeries(High_base_tf,true); ArraySetAsSeries(Low_base_tf,true); ArraySetAsSeries(Close_base_tf,true); ArraySetAsSeries(Open_base_tf,true); ArraySetAsSeries(Time_base_tf,true);; ArraySetAsSeries(Sar_array_base_tf,true); ArraySetAsSeries(FractalDown_base_tf,true); ArraySetAsSeries(FractalUp_base_tf,true); //---base_tf を埋める初期配列 CopyHigh(Symbol(),base_tf,0,1000,High_base_tf); CopyLow(Symbol(),base_tf,0,1000,Low_base_tf); CopyClose(Symbol(),base_tf,0,1000,Close_base_tf); CopyOpen(Symbol(),base_tf,0,1000,Open_base_tf); CopyTime(Symbol(),base_tf,0,1000,Time_base_tf); CopyBuffer(Sar_base_tf,0,TimeCurrent(),1000,Sar_array_base_tf); CopyBuffer(Fractal_base_tf,0,TimeCurrent(),1000,FractalUp_base_tf); CopyBuffer(Fractal_base_tf,1,TimeCurrent(),1000,FractalDown_base_tf); //---work_tf の時系列のように配列のオーダーを設定します。 ArraySetAsSeries(High_work_tf,true); ArraySetAsSeries(Low_work_tf,true); ArraySetAsSeries(Close_work_tf,true); ArraySetAsSeries(Open_work_tf,true); ArraySetAsSeries(Time_work_tf,true); ArraySetAsSeries(Sar_array_work_tf,true); ArraySetAsSeries(FractalDown_work_tf,true); ArraySetAsSeries(FractalUp_work_tf,true); //---work_tf を満たす初期配列 CopyHigh(Symbol(),work_tf,0,1000,High_work_tf); CopyLow(Symbol(),work_tf,0,1000,Low_work_tf); CopyClose(Symbol(),work_tf,0,1000,Close_work_tf); CopyOpen(Symbol(),work_tf,0,1000,Open_work_tf); CopyTime(Symbol(),work_tf,0,1000,Time_work_tf); CopyBuffer(Sar_work_tf,0,TimeCurrent(),1000,Sar_array_work_tf); CopyBuffer(Fractal_work_tf,0,TimeCurrent(),1000,FractalUp_work_tf); CopyBuffer(Fractal_work_tf,1,TimeCurrent(),1000,FractalDown_work_tf); //--- return(INIT_SUCCEEDED); }
まず、インジケータのハンドルを受け取ってから、時系列のように配列のオーダーを定義し、配列にデータを格納しました。 1000の足のデータがあれば、EAの操作には十分です。
2. 一般パラメータ
ここでは、OnTick() 関数を使用してタスクを開始します。
"一般パラメータ " セクションでは、通常、マーケットデータを記述し、ポジションの設定に使用する変数を宣言します。
//+------------------------------------------------------------------+ //| 1. 一般パラメータ (開始) | //+------------------------------------------------------------------+ //---相場データ //シンボル価格の小数点以下の桁数 int Digit=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); //現在のシンボルの価格能力を定義します。 double f=1; if(Digit==5) {f=100000;} if(Digit==4) {f=10000;} if(Digit==3) {f=1000;} if(Digit==2) {f=100;} if(Digit==1) {f=10;} //--- double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/f;//価格の容量を考慮した小数値へのスプレッドの削減 double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);//Bid価格に関するデータ double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);//Ask 価格のデータ double CostOfPoint=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_VALUE);//ティック価格のデータ //---ポジションを設定するためのロット計算変数 double RiskSize_points;//現在のポジションのSLサイズを格納するための変数 double CostOfPoint_position;//トレードごとのリスクを考慮して現在ポジションのポイント価格を格納するための変数 double Lot;//ポジションを開くためのロットサイズを格納するための変数 doubleSLPrice_sell,SLPrice_buy;//SLの価格レベルを格納するための変数 //---足の数にデータを格納するための変数 int bars_base_tf=Bars(Symbol(),base_tf); int bars_work_tf=Bars(Symbol(),work_tf); //---ポジションにデータを格納するための変数 string P_symbol; //ポジションシンボル int P_type,P_ticket,P_opentime;//ポジションオープンタイプ、チケットと時間 //+------------------------------------------------------------------+ //| 1. 一般パラメータ (終了) | //+------------------------------------------------------------------+
3. 配列データの更新
配列は最初に OnInit() 関数にインプットされましたが、配列データは常に関連したままである必要があります。 インプットされた各ティックで配列をインプットすると、システムの負荷が大幅に低下することになります。 したがって、新しい足が表示されたら、配列を補充することをお勧めします。
これを行うには、次の構造体を使用します。
static datetime LastBar_base_tf=0;//新しい足を定義するための変数 datetime ThisBar_base_tf=(datetime)SeriesInfoInteger(_Symbol,base_tf,SERIES_LASTBAR_DATE);//現在の足タイム if(LastBar_base_tf!=ThisBar_base_tf)//時間が一致しない場合は、新しい足が登場 { //配列はここに満たされます }
この方法では、ゼロ足のデータが失われますので、インデックス0の足データ用の別の配列があります。
また、フラクタルデータを使用して配列を個別に更新する必要があります。 0番目の足の 極値点 は、前の2つよりも高いまたは低いたびに補充する必要があります。
配列の例を以下に示します。
1. 新しい足が表示されたときの配列の入力
最初に、新しい足が表示されたら配列にインプットします。
//+------------------------------------------------------------------+ //| 2.1 新しい足が表示されたときの配列のインプット (開始) | //+------------------------------------------------------------------+ //---base_tf 用 //---時系列の配列のオーダーを設定します。 ArraySetAsSeries(High_base_tf,true); ArraySetAsSeries(Low_base_tf,true); ArraySetAsSeries(Close_base_tf,true); ArraySetAsSeries(Open_base_tf,true); ArraySetAsSeries(Time_base_tf,true); ArraySetAsSeries(Sar_array_base_tf,true); ArraySetAsSeries(FractalDown_base_tf,true); ArraySetAsSeries(FractalUp_base_tf,true); //---配列を埋める static datetime LastBar_base_tf=0;//新しい受信足を定義するための変数 datetime ThisBar_base_tf=(datetime)SeriesInfoInteger(_Symbol,base_tf,SERIES_LASTBAR_DATE);//現在の足を開く時間 if(LastBar_base_tf!=ThisBar_base_tf)//時間が一致しない場合は、新しい足が登場 { CopyHigh(Symbol(),base_tf,0,1000,High_base_tf); CopyLow(Symbol(),base_tf,0,1000,Low_base_tf); CopyClose(Symbol(),base_tf,0,1000,Close_base_tf); CopyOpen(Symbol(),base_tf,0,1000,Open_base_tf); CopyTime(Symbol(),base_tf,0,1000,Time_base_tf); CopyBuffer(Sar_base_tf,0,TimeCurrent(),1000,Sar_array_base_tf); CopyBuffer(Fractal_base_tf,0,TimeCurrent(),1000,FractalUp_base_tf); CopyBuffer(Fractal_base_tf,1,TimeCurrent(),1000,FractalDown_base_tf); LastBar_base_tf=ThisBar_base_tf; } //---work_tf 用 //---時系列の配列のオーダーを設定します。 ArraySetAsSeries(High_work_tf,true); ArraySetAsSeries(Low_work_tf,true); ArraySetAsSeries(Close_work_tf,true); ArraySetAsSeries(Open_work_tf,true); ArraySetAsSeries(Time_work_tf,true); ArraySetAsSeries(Sar_array_work_tf,true); ArraySetAsSeries(FractalDown_work_tf,true); ArraySetAsSeries(FractalUp_work_tf,true); //---配列のインプット static datetime LastBar_work_tf=0;//新しい足を定義するための変数 datetime ThisBar_work_tf=(datetime)SeriesInfoInteger(_Symbol,work_tf,SERIES_LASTBAR_DATE);//現在の足の開始時刻 if(LastBar_work_tf!=ThisBar_work_tf)//時間が一致しない場合は、新しい足が登場している { CopyHigh(Symbol(),work_tf,0,1000,High_work_tf); CopyLow(Symbol(),work_tf,0,1000,Low_work_tf); CopyClose(Symbol(),work_tf,0,1000,Close_work_tf); CopyOpen(Symbol(),work_tf,0,1000,Open_work_tf); CopyTime(Symbol(),work_tf,0,1000,Time_work_tf); CopyBuffer(Sar_work_tf,0,TimeCurrent(),1000,Sar_array_work_tf); CopyBuffer(Fractal_work_tf,0,TimeCurrent(),1000,FractalUp_work_tf); CopyBuffer(Fractal_work_tf,1,TimeCurrent(),1000,FractalDown_work_tf); LastBar_work_tf=ThisBar_work_tf; } //+------------------------------------------------------------------+ //| 2.1 新しい足が表示されたときの配列のインプット (終了) | //+------------------------------------------------------------------+
2. 足#0データを含む配列の入力
インデックス1以降の足のデータは常に関連付けられていますが、インデックス0足のデータは依然として古くなっています。 ゼロ足にデータを格納するための別の配列が含まれている:
//+------------------------------------------------------------------+ //| 2.2 足#0データを補完配列 (スタート) | //+------------------------------------------------------------------+ //---base_tf 用 //---配列を宣言 double High_base_tf_0[],Low_base_tf_0[]; double Close_base_tf_0[],Open_base_tf_0[]; datetime Time_base_tf_0[]; double Sar_array_base_tf_0[]; //---時系列の配列のオーダーを設定します。 ArraySetAsSeries(High_base_tf_0,true); ArraySetAsSeries(Low_base_tf_0,true); ArraySetAsSeries(Close_base_tf_0,true); ArraySetAsSeries(Open_base_tf_0,true); ArraySetAsSeries(Time_base_tf_0,true); ArraySetAsSeries(Sar_array_base_tf_0,true); //---配列にインプットする CopyHigh(Symbol(),base_tf,0,1,High_base_tf_0); CopyLow(Symbol(),base_tf,0,1,Low_base_tf_0); CopyClose(Symbol(),base_tf,0,1,Close_base_tf_0); CopyOpen(Symbol(),base_tf,0,1,Open_base_tf_0); CopyTime(Symbol(),base_tf,0,1,Time_base_tf_0); CopyBuffer(Sar_base_tf,0,TimeCurrent(),1,Sar_array_base_tf_0); //---work_tf 用 //---配列を宣言 double High_work_tf_0[],Low_work_tf_0[]; double Close_work_tf_0[],Open_work_tf_0[]; datetime Time_work_tf_0[]; double Sar_array_work_tf_0[]; //---時系列の配列のオーダーを設定します。 ArraySetAsSeries(High_work_tf_0,true); ArraySetAsSeries(Low_work_tf_0,true); ArraySetAsSeries(Close_work_tf_0,true); ArraySetAsSeries(Open_work_tf_0,true); ArraySetAsSeries(Time_work_tf_0,true); ArraySetAsSeries(Sar_array_work_tf_0,true); //---配列を埋める CopyHigh(Symbol(),work_tf,0,1,High_work_tf_0); CopyLow(Symbol(),work_tf,0,1,Low_work_tf_0); CopyClose(Symbol(),work_tf,0,1,Close_work_tf_0); CopyOpen(Symbol(),work_tf,0,1,Open_work_tf_0); CopyTime(Symbol(),work_tf,0,1,Time_work_tf_0); CopyBuffer(Sar_work_tf,0,TimeCurrent(),1,Sar_array_work_tf_0); //+------------------------------------------------------------------+ //| 2.2 補完配列足#0データ (終了) | //+------------------------------------------------------------------+
3. フラクタルデータの更新
フラクタルデータを含む配列を更新する必要があります。 各タイム足 0 極値点 は、前の2つより高いまたは低い、配列を補充する必要があります。
//+------------------------------------------------------------------+ //| 2.3 フラクタルデータの更新 (スタート) | //+------------------------------------------------------------------+ //---base_tf 用 if(High_base_tf_0[0]>High_base_tf[1] && High_base_tf_0[0]>High_base_tf[2]) { CopyBuffer(Fractal_base_tf,0,TimeCurrent(),1000,FractalUp_base_tf); } if(Low_base_tf_0[0]<Low_base_tf[1] && Low_base_tf_0[0]<Low_base_tf[2]) { CopyBuffer(Fractal_base_tf,1,TimeCurrent(),1000,FractalDown_base_tf); } //---work_tf 用 if(High_work_tf_0[0]>High_work_tf[1] && High_work_tf_0[0]>High_work_tf[2]) { CopyBuffer(Fractal_work_tf,0,TimeCurrent(),1000,FractalUp_work_tf); } if(Low_work_tf_0[0]<Low_work_tf[1] && Low_work_tf_0[0]<Low_work_tf[2]) { CopyBuffer(Fractal_work_tf,1,TimeCurrent(),1000,FractalDown_work_tf); } //+------------------------------------------------------------------+ //| 2.3 フラクタルデータの更新 (終了) | //+------------------------------------------------------------------+
4. 極値点 の検索
運動継続モデルに戻りましょう。 これを行うには、 図2 に戻る必要があります。
АВセグメントは主波であり、ВСは補正波です。 モデル認識原理によれば、補正波は常にフラクタルの極値で終わるべきです。 イメージでは、Сとしてマークされます。 極値点 の検索は、この時点で開始する必要がありますが、残りは一貫してその後検出されます。 しかし、インプットの瞬間に、形成された (確認) フラクタルは、存在しない可能性があります。 したがって、足の極値は、上記の2つの前の足の下にある状況を探す必要があります。そのような足の高値/安値は、ポイントСを形成します。 また、補正運動の高低 (点С) は、ゼロ足、またはインプットの瞬間にゼロより上のインデックスを持つ足のいずれかに位置することに注意してください。
表2は、極値定義のシーケンスを示します。
表 2. 極値定義シーケンス
# | 下降トレンド | 上昇トレンド |
---|---|---|
1 | 補正運動ハイを見つける (ポイントС) | 補正運動ローを見つける (ポイントС) |
2 | 補正運動ハイから次の上位極値を探す (ポイントА) | 補正運動ローから次の下位極値を探す (ポイントА) |
3 | ポイント C と A の間の点В (補正運動ロー) を見つける | 点 C と A の間の点В (補正運動ハイ) を見つける |
//+------------------------------------------------------------------+ //| 3.1 下降 極値点 の検索 (スタート) | //+------------------------------------------------------------------+ //---変数を宣言する int High_Corr_wave_downtrend_base_tf;//補正運動の高い足 (点С) について int UpperFractal_downtrend_base_tf; //次の上の極値足 (ポイントА) について int Low_Corr_wave_downtrend_base_tf; //補正運動の下の足 (ポイント B) //--- //--- 補正運動ハイを見つける (ポイントС) if(High_base_tf_0[0]>High_base_tf[1] && High_base_tf_0[0]>High_base_tf[2]) { High_Corr_wave_downtrend_base_tf=0; } else { for(n=0; n<(bars_base_tf);n++) { if(High_base_tf[n]>High_base_tf[n+1] && High_base_tf[n]>High_base_tf[n+2]) break; } High_Corr_wave_downtrend_base_tf=n; } //--- //--- 補正運動ハイの次の上の極値を見つける (ポイントА) for(n=High_Corr_wave_downtrend_base_tf+1; n<(bars_base_tf);n++) { //---空でない値の場合は、ループを終了します。 if(FractalUp_base_tf[n]!=EMPTY_VALUE) break; } UpperFractal_downtrend_base_tf=n; //--- //---点 C と A の間の点 B (補正運動ロー) を見つける int CountToFind_arrmin=UpperFractal_downtrend_base_tf-High_Corr_wave_downtrend_base_tf; Low_Corr_wave_downtrend_base_tf=ArrayMinimum(Low_base_tf,High_Corr_wave_downtrend_base_tf,CountToFind_arrmin); //+------------------------------------------------------------------+ //| 3.1 下降 (終了) の 極値点 の検索 | //+------------------------------------------------------------------+
2. 上昇トレンドの 極値点 の検索
//+------------------------------------------------------------------+ //| 3.2 上昇トレンド 極値点 の検索 (スタート) | //+------------------------------------------------------------------+ //---変数の宣言 int Low_Corr_wave_uptrend_base_tf;//補正運動のロー足 (ポイントС) int LowerFractal_uptrend_base_tf; //次の下極値足 (ポイントА) について int High_Corr_wave_uptrend_base_tf; //補正運動の高値 (ポイント B) //--- //--- 補正運動ローを見つける (ポイントС) if(Low_base_tf_0[0]<Low_base_tf[1] && Low_base_tf_0[0]<Low_base_tf[2]) { Low_Corr_wave_uptrend_base_tf=0; } else { //ロールバックローの検索 for(n=0; n<(bars_base_tf);n++) { if(Low_base_tf[n]<Low_base_tf[n+1] && Low_base_tf[n]<Low_base_tf[n+2]) break; } Low_Corr_wave_uptrend_base_tf=n; } //--- //--- 補正運動ローから、次の下の極値を見つける (ポイントА) for(n=Low_Corr_wave_uptrend_base_tf+1; n<(bars_base_tf);n++) { if(FractalDown_base_tf[n]!=EMPTY_VALUE) break; } LowerFractal_uptrend_base_tf=n; //--- //---点 C と A の間の点 B (補正運動ハイ) を見つける int CountToFind_arrmax=LowerFractal_uptrend_base_tf-Low_Corr_wave_uptrend_base_tf; High_Corr_wave_uptrend_base_tf=ArrayMaximum(High_base_tf,Low_Corr_wave_uptrend_base_tf,CountToFind_arrmax); //+------------------------------------------------------------------+ //| 3.2 の 極値点 の検索 (終了) | //+------------------------------------------------------------------+
3. 補正波の高値安値の統合変数への削減
したがって、極値の足のインデックスを発見しました。 しかし、同様に足の価格と時間の値を参照する必要があります。 高値または補正波の安値の値を参照するために、高値または補正波の安値はゼロインデックスバー、またはゼロ以上のインデックスを持つ足のいずれかである可能性があるため、2つの異なる配列を使用する必要があります これは、今回のタスクにとって便利ではないため、if演算子 を使用して一般的な変数に値をもたらす方が合理的です。
//+----------------------------------------------------------------------------------+ //| 3.3 補正波の高値安値を共通変数に取り込む (スタート) | //+----------------------------------------------------------------------------------+ //---変数の宣言 double High_Corr_wave_downtrend_base_tf_double,Low_Corr_wave_uptrend_base_tf_double; datetime High_Corr_wave_downtrend_base_tf_time,Low_Corr_wave_uptrend_base_tf_time; //---High_Corr_wave_downtrend_base_tf 用 if(High_Corr_wave_downtrend_base_tf==0) { High_Corr_wave_downtrend_base_tf_double=High_base_tf_0[High_Corr_wave_downtrend_base_tf]; High_Corr_wave_downtrend_base_tf_time=Time_base_tf_0[High_Corr_wave_downtrend_base_tf]; } else { High_Corr_wave_downtrend_base_tf_double=High_base_tf[High_Corr_wave_downtrend_base_tf]; High_Corr_wave_downtrend_base_tf_time=Time_base_tf[High_Corr_wave_downtrend_base_tf]; } //--Low_Corr_wave_uptrend_base_tf に if(Low_Corr_wave_uptrend_base_tf==0) { Low_Corr_wave_uptrend_base_tf_double=Low_base_tf_0[Low_Corr_wave_uptrend_base_tf]; Low_Corr_wave_uptrend_base_tf_time=Time_base_tf_0[Low_Corr_wave_uptrend_base_tf]; } else { Low_Corr_wave_uptrend_base_tf_double=Low_base_tf[Low_Corr_wave_uptrend_base_tf]; Low_Corr_wave_uptrend_base_tf_time=Time_base_tf[Low_Corr_wave_uptrend_base_tf]; } //+---------------------------------------------------------------------------------+ //| 3.3 補正波の高値安値を共通変数に取り込む (終了) | //+---------------------------------------------------------------------------------+
これより、補正波の高値/安値と時間値は変数に書き込まれます。 毎回異なる配列にアクセスする必要はありません。
極値点 を検索するタスクをまとめると、モデルの認識に従って A、B、C の点が見つかったことがわかります (表4および5を参照)。
表 4. А、В、Сのポイントの値
パラメータ | ポイントAの値 | ポイント B の値 | ポイント C の値 |
---|---|---|---|
足インデックス | UpperFractal_downtrend_base_tf | Low_Corr_wave_downtrend_base_tf | High_Corr_wave_downtrend_base_tf |
時間の値 | Time_base_tf[UpperFractal_downtrend_base_tf] | Time_base_tf[Low_Corr_wave_downtrend_base_tf] | High_Corr_wave_downtrend_base_tf_time |
価格 | High_base_tf[UpperFractal_downtrend_base_tf] | Low_base_tf[Low_Corr_wave_downtrend_base_tf] | High_Corr_wave_downtrend_base_tf_double |
表 5. ポイントА、В、Сの上昇トレンドの値
パラメータ | ポイントAの値 | ポイント B の値 | ポイント C の値 |
---|---|---|---|
足インデックス | LowerFractal_uptrend_base_tf | High_Corr_wave_uptrend_base_tf | Low_Corr_wave_uptrend_base_tf |
時間の値 | Time_base_tf[LowerFractal_uptrend_base_tf] | Time_base_tf[High_Corr_wave_uptrend_base_tf] | Low_Corr_wave_uptrend_base_tf_time |
価格 | Low_base_tf[LowerFractal_uptrend_base_tf] | High_base_tf[High_Corr_wave_uptrend_base_tf] | Low_Corr_wave_uptrend_base_tf_double |
5. モデル認識条件
このセクションでは、この記事で説明するモデルの最も必要な基本条件について説明します。
表 6. 運動継続モデルを認識するための最低条件セット
# | 下降トレンド条件 | 上昇トレンド条件 |
---|---|---|
1 | 補正波高値 (点 C) が、続く極値の高値を下回る (点А) | 補正波安値 (点 C)が、続く極値の安値を上回る (点А) |
2 | 補正波低指数 (点В) が上野指数を超える (ポイントС) | 補正波高指数 (点В) が下の指数 (点С) を超える |
3 | 2 ~ 6 小節の補正運動時間 (ポイントВの足数) | 2 ~ 6 小節の補正運動時間 (ポイントВの足数) |
モデル認識条件を記述するためのコードを以下に示します。 この条件は2つの論理変数で集められる: 1 つは下降トレンド用、もう一つは上昇トレンド用です:
//+------------------------------------------------------------------+ //| 4. モデル認識条件の記述 (開始) | //+------------------------------------------------------------------+ //---下降トレンド /*1. 補正波ハイ (点 C) が、続く極値の高値より下 (点А) */ /*2. 補正波ロウ指数 (点В) が高い指数 (点С) を超える */ /*3. 2 ~ 6 小節の補正運動時間 (ポイントВからの小節数) */ bool Model_downtrend_base_tf=( /*1.*/High_Corr_wave_downtrend_base_tf_double<High_base_tf[UpperFractal_downtrend_base_tf] && /*2.*/Low_Corr_wave_downtrend_base_tf>High_Corr_wave_downtrend_base_tf && /*3.*/Low_Corr_wave_downtrend_base_tf>=1 && Low_Corr_wave_downtrend_base_tf<=6 ); //---上昇トレンド /*1. 補正波ロウ(点 C)が、続く極値の安値より上 (点А) */ /*2. 補正波ハイ指数 (点В) がロウ指数 (点С) を超えている */ /*3. 2 ~ 6 小節の補正運動時間 (ポイントВからの小節数) */ bool Model_uptrend_base_tf=( /*1.*/Low_Corr_wave_uptrend_base_tf_double>Low_base_tf[LowerFractal_uptrend_base_tf] && /*2.*/High_Corr_wave_uptrend_base_tf>Low_Corr_wave_uptrend_base_tf && /*3.*/High_Corr_wave_uptrend_base_tf>=1 && High_Corr_wave_uptrend_base_tf<=6 ); //+------------------------------------------------------------------+ //| 4. モデル認識条件 (終了) | //+------------------------------------------------------------------+
6. コントロールの作成
このEAは少なくとも3つの確認をする必要があります。
最初の2つのチェックは、インプットの適時性を確認します。 3つ目は、1つのモデル内で1つのポジションしかないことを確認します。
図3を参照してください。 点線は、ポイントВとСの間のどこかに、エントリポイントが配置されているポジションのオープンをマークします。 リスクが増加するため、ポイント B のレベルを介して価格がブレイクするときに、後でインプットすることは推奨されません。 これが、プログラムが実行する最初のチェックです。
図3. AUDJPY H4 の運動継続モデル
場合によっては、価格はポイントВを通ってブレイクし、ポジションのオープンエリアに戻るかもしれません。 このような状況は、トレードの一つとして考慮することはできません。 これが、プログラムが行う必要がある2番目のチェックです。 最後に、複数のポジションを避けるために、制限を導入する必要があります。(1 オープンポジション) これが、プログラムが実行する必要がある3番目の確認事項です。
1. ポジションエントリ領域におけるエントリポイント制御の形成
すべて簡単です。 売りモデルは、Bid価格が補正運動ロウ (ポイントВ) 超過したときです。 買いモデルの場合、Bid価格が補正運動ハイ (ポイントВ) を下回ったときです。
//+----------------------------------------------------------------------------+ //| 5.1 ポジションオープンエリアにおけるインプットポイントコントロールの形成 (スタート) | //+----------------------------------------------------------------------------+ //---下降トレンド bool First_downtrend_control_bool=(bid>=Low_base_tf[Low_Corr_wave_downtrend_base_tf]); //---上昇トレンド bool First_uptrend_control_bool=(bid<=High_base_tf[High_Corr_wave_uptrend_base_tf]); //+----------------------------------------------------------------------------+ //| 5.1 ポジションオープンにおけるインプットポイントコントロールの形成 (終了) | //+----------------------------------------------------------------------------+
2. 価格ロールの制御-ポジションオープンエリアに戻る
この制御を実装するには、最も低い安値/最も高い高値で足を定義します。その値は、現在のインデックスから始まるものでなければなりません。 これを実現するために、ArrayMinimum() 関数を売りモデルに、ArrayMaximum()関数を買いモデルに使用します。
さらに、このインデックスは、補正運動ハイロー指数 (ポイントВ) とArrayMinimum()とArrayMaximum ( ) 関数によって得られるインデックスを比較します。 これが一致すれば、補正運動がないことを表し、エントリを考慮する必要があります。 インデックスが一致しない場合は、運動が先に開始されており、ポジションを開くには遅すぎます。
//+------------------------------------------------------------------------------+ //| 5.2 ポジションオープンエリアへの価格ロールバックの制御 (スタート) | //+------------------------------------------------------------------------------+ //---下降トレンド //足#0と補正運動の安値の間に最安値で足を見つける int Second_downtrend_control_int=ArrayMinimum(Low_base_tf,0,Low_Corr_wave_downtrend_base_tf+1); //現在の足の安値が補正運動の安値 if(Low_base_tf_0[0]<Low_base_tf[Second_downtrend_control_int]) { Second_downtrend_control_int=0; //最小値が足#0にあることを意味します } //最安値と補正運動安値が一致する足の場合、同じ足です //これは、価格がポジションのオープンエリアを超えて移動していないことを意味します bool Second_downtrend_control_bool=(Second_downtrend_control_int==Low_Corr_wave_downtrend_base_tf); //--- //---上昇トレンド //足#0と補正運動の高値の間に高値の足を見つける int Second_uptrend_control_int=ArrayMaximum(High_base_tf,0,High_Corr_wave_uptrend_base_tf+1); //現在の足の高値が補正運動の高を上回っている場合 if(High_base_tf_0[0]>High_base_tf[Second_uptrend_control_int]) { Second_uptrend_control_int=0;//足#0で最大を意味する } //高値と補正運動の高い価格率が一致する足であれば、同じ足 //これは、価格がポジションのオープンエリアを超えて移動していないことを意味します bool Second_uptrend_control_bool=(Second_uptrend_control_int==High_Corr_wave_uptrend_base_tf); //+-----------------------------------------------------------------------------+ //| 5.2 ポジションオープンエリアへの価格ロールバックの制御 (終了) | //+-----------------------------------------------------------------------------+
3. 単一モデル内での重複ポジションの除去
このコントロールは、開いているポジションの数を制限するために使用します。 その背後にあるアイデア(1つのオープンポジション。) オープンポジションは1つずつ分析されます。 現在のチャート上でポジションが開かれている場合、エントリポイントからのそのポジションに最も近い極値足は、トレードタイプに応じて定義された-補正運動ハイ/ロー (エントリポイントからのポイントС) になります。
その後、検出された足の時間-補正運動の高低 (エントリポイントからのポイントС)-現在の補正運動の時間と比較されますハイ/ロー (現在のポイントС)。 一致する場合は、このモデルに付着したポジションがないため、ポジションを開く必要はありません。
売り制御を作成する:
//+---------------------------------------------------------------------------+ //| 5.3.1 売り (スタート) | //+---------------------------------------------------------------------------+ //---変数の宣言 int Bar_sell_base_tf,High_Corr_wave_downtrend_base_tf_sell; bool Third_downtrend_control_bool=false; //---開いているポジションを繰り返し処理する if(PositionsTotal()>0) { for(i=0;i<=PositionsTotal();i++) { if(PositionGetTicket(i)) { //---ポジションシンボル、時刻、および型の定義 P_symbol=string(PositionGetString(POSITION_SYMBOL)); P_type=int(PositionGetInteger(POSITION_TYPE)); P_opentime=int(PositionGetInteger(POSITION_TIME)); //---ポジションシンボルが現在のチャートと一致し、トレードの種類が "売り " の場合 if(P_symbol==Symbol() && P_type==1) { //---ポジションが開いている足を見つける Bar_sell_base_tf=iBarShift(Symbol(),base_tf,P_opentime); //---補正運動の検索から高値 //現在の足にポジションが開いている場合 if(Bar_sell_base_tf==0) { //そして現在の足が極値 if(High_base_tf_0[Bar_sell_base_tf]>High_base_tf[Bar_sell_base_tf+1] && High_base_tf_0[Bar_sell_base_tf]>High_base_tf[Bar_sell_base_tf+2]) { High_Corr_wave_downtrend_base_tf_sell=Bar_sell_base_tf;//補正運動ハイが、現在の足に等しい } else { //現在の足が極値でない場合は、極値を検索するためのループを起動します。 for(n=Bar_sell_base_tf; n<(bars_base_tf);n++) { if(High_base_tf[n]>High_base_tf[n+1] && High_base_tf[n]>High_base_tf[n+2])//極値が見つかった場合 break;//ループをブレイクする } High_Corr_wave_downtrend_base_tf_sell=n; } //---制御条件の説明 Third_downtrend_control_bool=( /*1. 補正運動ハイが、ポジションのオープンからある matches the time of the current correction movement high*/Time_base_tf[High_Corr_wave_downtrend_base_tf_sell]==High_Corr_wave_downtrend_base_tf_time ); } //---現在の足にないポジションが開かれている場合 if(Bar_sell_base_tf!=0 && Bar_sell_base_tf!=1000) { //---極値足を検出するためのループを起動します。 for(n=Bar_sell_base_tf; n<(bars_base_tf);n++) { //---極値が見つかった場合 if(High_base_tf[n]>High_base_tf[n+1] && High_base_tf[n]>High_base_tf[n+2]) break;//ループをブレイクする } High_Corr_wave_downtrend_base_tf_sell=n; } Third_downtrend_control_bool=( /*1. 補正運動ハイが、ポジションのオープンからある matches the time of the current correction movement high*/Time_base_tf[High_Corr_wave_downtrend_base_tf_sell]==High_Corr_wave_downtrend_base_tf_time ); } } } } //+---------------------------------------------------------------------------+ //| 5.3.1 売り (終了) | //+---------------------------------------------------------------------------+買いコントロールの作成:
//+---------------------------------------------------------------------------+ //| 5.3.2 買い (スタート) | //+---------------------------------------------------------------------------+ //---変数の宣言 int Bar_buy_base_tf,Low_Corr_wave_uptrend_base_tf_buy; bool Third_uptrend_control_bool=false; //---開いているポジションを繰り返し処理する if(PositionsTotal()>0) { for(i=0;i<=PositionsTotal();i++) { if(PositionGetTicket(i)) { //ポジションシンボル、タイプ、および時間の定義 P_symbol=string(PositionGetString(POSITION_SYMBOL)); P_type=int(PositionGetInteger(POSITION_TYPE)); P_opentime=int(PositionGetInteger(POSITION_TIME)); //ポジションシンボルが現在のチャートと一致し、買いした場合 if(P_symbol==Symbol() && P_type==0) { //ポジションが開いている足を見つける Bar_buy_base_tf=iBarShift(Symbol(),base_tf,P_opentime); //補正運動ロウの検索 //現在の足にポジションが開いている場合 if(Bar_buy_base_tf==0) { //そして現在の足が極値 if(Low_base_tf_0[Bar_buy_base_tf]<Low_base_tf[Bar_buy_base_tf+1] && Low_base_tf_0[Bar_buy_base_tf]<Low_base_tf[Bar_buy_base_tf+2]) { Low_Corr_wave_uptrend_base_tf_buy=Bar_buy_base_tf; } else { //現在の足が極値でない場合は、極値を検索するためのループを起動します。 for(n=Bar_buy_base_tf; n<(bars_base_tf);n++) { if(Low_base_tf[n]<Low_base_tf[n+1] && Low_base_tf[n]<Low_base_tf[n+2])//極値が見つかった場合 break;//ループをブレイクする } Low_Corr_wave_uptrend_base_tf_buy=n; } //---制御条件の説明 Third_uptrend_control_bool=( /*1. 補正運動ロウがポジションのオープンから発見 matches the time of the current correction movement low*/Time_base_tf[Low_Corr_wave_uptrend_base_tf_buy]==Low_Corr_wave_uptrend_base_tf_time ); } //---現在の足にないポジションが開かれている場合 if(Bar_buy_base_tf!=0 && Bar_buy_base_tf!=1000) { //---極値足を検出するためのループを起動します。 for(n=Bar_buy_base_tf; n<(bars_base_tf);n++) { //---極値が見つかった場合 if(Low_base_tf[n]<Low_base_tf[n+1] && Low_base_tf[n]<Low_base_tf[n+2]) break;//ループをブレイクする } Low_Corr_wave_uptrend_base_tf_buy=n; } //---制御条件の説明 Third_uptrend_control_bool=( /*1. 補正運動ロウがポジションのオープンから発見 matches the time of the current correction movement low*/Time_base_tf[Low_Corr_wave_uptrend_base_tf_buy]==Low_Corr_wave_uptrend_base_tf_time ); } } } } //+---------------------------------------------------------------------------+ //| 5.3.2 売り (終了) | //+---------------------------------------------------------------------------+
7. 相場参入条件の記述
エントリポイントは、稼働期間 (work_tf) で定義する必要があります。 これは、相場へのタイムリーな参入と、可能であれば、ポイントのリスクの量を減らすために必要です。 パラボリックインジケータの読み取り値は、シグナルとして使用します: 現在の足のインジケータの数値が現在の足の高値を超え、かつ、前の足ではインジケータの値が同じ足の安値より低い場合は売りです。 買いについては、逆です。
//+------------------------------------------------------------------+ //| 6. 相場参入条件の説明 (スタート) | //+------------------------------------------------------------------+ //---売り bool PointSell_work_tf_bool=( /*1. 足#1安値がiSARを超えている [1] */Low_work_tf [1] > Sar_array_work_tf [1] & & /*2. 足#0の高値がiSAR [0] */High_work_tf_0 [<>0]0] より低い ); //---買い bool PointBuy_work_tf_bool=( /*1. 足#1の高値がiSarの下にある*/High_work_tf[1]<Sar_array_work_tf[1] && /*2. 足#0安値がiSAR [0]の上にある */Low_work_tf_0[0]>Sar_array_work_tf_0[0] ); //+------------------------------------------------------------------+ //| 6. 相場参入条件の記述 (終了) | //+------------------------------------------------------------------+
8. トレード条件
この段階では、以前に作成したすべての条件とコントロールを1つのロジック変数に結合します。
//+------------------------------------------------------------------+ //| 7. トレード条件の記述 (開始) | //+------------------------------------------------------------------+ //---売り bool OpenSell=( /*1. model formed*/Model_downtrend_base_tf==true && /*2. control 1 allows opening a position*/First_downtrend_control_bool==true && /*3. control 2 allows opening a position*/Second_downtrend_control_bool==true && /*4. control 3 allows opening a position*/Third_downtrend_control_bool==false && /*5. Entry point to work_tf*/PointSell_work_tf_bool==true ); //---売り bool OpenBuy=( /*1. model formed*/Model_uptrend_base_tf==true && /*2. control 1 allows opening a position*/First_uptrend_control_bool==true && /*3. control 2 allows opening a position*/Second_uptrend_control_bool==true && /*4. control 3 allows opening a position*/Third_uptrend_control_bool==false && /*5. Entry point to work_tf*/PointBuy_work_tf_bool==true ); //+------------------------------------------------------------------+ //| 7. トレード条件の記述 (終了) | //+------------------------------------------------------------------+
9. トレーディングオペレーションの操作
トレーディングオペレーションの操作は次のように分けることができます。
- ポジションの設定;
- テイクプロフィットの設定;
- ポジションをブレイクイーブンに移動
1. ポジションの設定
//+------------------------------------------------------------------+ //| 8. トレーディングオペレーション (スタート) の操作 | //+------------------------------------------------------------------+ //---SLレベルの定義 SLPrice_sell=High_Corr_wave_downtrend_base_tf_double+spread; SLPrice_buy=Low_Corr_wave_uptrend_base_tf_double-spread; //+------------------------------------------------------------------+ //| 8.1 設定ポジション (スタート) | //+------------------------------------------------------------------+ //---売り if(OpenSell==true) { RiskSize_points=(SLPrice_sell-bid)*f;//ポイントの ストップロス を整数として定義 if(RiskSize_points==0)//ゼロ除算チェック { RiskSize_points=1; } CostOfPoint_position=SummRisk/RiskSize_points;//sl を考慮したポイントでのポジション価格の定義 Lot=CostOfPoint_position/CostOfPoint;//ポジションを開くためのロットの計算 //ポジションを開く trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,NormalizeDouble(Lot,2),bid,NormalizeDouble(SLPrice_sell,5),0,""); } //---買い if(OpenBuy==true) { RiskSize_points=(bid-SLPrice_buy)*f;//ポイントの ストップロス を整数として定義 if(RiskSize_points==0)//ゼロ除算チェック { RiskSize_points=1; } CostOfPoint_position=SummRisk/RiskSize_points;//sl を考慮したポイントでのポジション価格の定義 Lot=CostOfPoint_position/CostOfPoint;//ポジションを開くためのロットの計算 //ポジションを開く trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,NormalizeDouble(Lot,2),ask,NormalizeDouble(SLPrice_buy,5),0,""); } //+------------------------------------------------------------------+ //| 8.1 設定ポジション (終了) | //+------------------------------------------------------------------+
2. TPの設定
//+------------------------------------------------------------------+ //| 8.2 設定TP(スタート) | //+------------------------------------------------------------------+ if(TP_mode==true) { if(PositionsTotal()>0) { for(i=0;i<=PositionsTotal();i++) { if(PositionGetTicket(i)) { //ポジションの値の取得 SL_double=double (PositionGetDouble(POSITION_SL)); OP_double=double (PositionGetDouble(POSITION_PRICE_OPEN)); TP_double=double (PositionGetDouble(POSITION_TP)); P_symbol=string(PositionGetString(POSITION_SYMBOL)); P_type=int(PositionGetInteger(POSITION_TYPE)); P_profit=double (PositionGetDouble(POSITION_PROFIT)); P_ticket=int (PositionGetInteger(POSITION_TICKET)); P_opentime=int(PositionGetInteger(POSITION_TIME)); if(P_symbol==Symbol()) { if(P_type==0 && TP_double==0) { doubleSL_size_buy=OP_double-SL_double;//ポイント単位で ストップロス を定義 doubleTP_size_buy=SL_size_buy*M;//インプットの1セットの比率によって ストップロス を乗算 doubleTP_price_buy=OP_double+TP_size_buy;//tp レベルの定義 //ポジションを変更する trade.PositionModify(PositionGetInteger(POSITION_TICKET),SL_double,NormalizeDouble(TP_price_buy,5)); } if(P_type==1 && TP_double==0) { doubleSL_size_sell=SL_double-OP_double;//ポイント単位で ストップロス を定義 doubleTP_size_sell=SL_size_sell*M;//インプットの1セットの比率によって ストップロス を乗算します。 doubleTP_price_sell=OP_double-TP_size_sell;//tp レベルの定義 //ポジションを変更する trade.PositionModify(PositionGetInteger(POSITION_TICKET),SL_double,NormalizeDouble(TP_price_sell,5)); } } } } } } //+------------------------------------------------------------------+ //| 8.2 TPのセット(終了) | //+------------------------------------------------------------------+
3. ポジションを ブレイクイーブン に移動
//+------------------------------------------------------------------+ //| 8.3 ポジションを ブレイクイーブン に移動する (スタート) | //+------------------------------------------------------------------+ double Size_Summ=breakeven*SummRisk;//テイクプロフィットを定義し、その後、ポジションを ブレイクイーブン に移動する必要があります。 if(Breakeven_mode==true && breakeven!=0) { if(PositionsTotal()>0) { for(i=0;i<=PositionsTotal();i++) { if(PositionGetTicket(i)) { //ポジションの値の取得 SL_double=double (PositionGetDouble(POSITION_SL)); OP_double=double (PositionGetDouble(POSITION_PRICE_OPEN)); TP_double=double (PositionGetDouble(POSITION_TP)); P_symbol=string(PositionGetString(POSITION_SYMBOL)); P_type=int(PositionGetInteger(POSITION_TYPE)); P_profit=double (PositionGetDouble(POSITION_PROFIT)); P_ticket=int (PositionGetInteger(POSITION_TICKET)); P_opentime=int(PositionGetInteger(POSITION_TIME)); if(P_symbol==Symbol()) { if(P_type==0 && P_profit>=Size_Summ && SL_double<OP_double) { trade.PositionModify(PositionGetInteger(POSITION_TICKET),OP_double,TP_double); } if(P_type==1 && P_profit>=Size_Summ && SL_double>OP_double) { trade.PositionModify(PositionGetInteger(POSITION_TICKET),OP_double,TP_double); } } } } } } //+------------------------------------------------------------------+ //| 8.3 ポジションを ブレイクイーブン に移動する (終了) | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| 8. トレーディングオペレーションの操作 (終了) | //+------------------------------------------------------------------+
5. 統計データの収集
まず、統計のインジケータのセットを決定する必要があります:
- シンボル;
- 取引種別;
- エントリタイム;
- オープン価格;
- ストップロス;
- ストップロスサイズ;
- 最大利益レベル;
- 最大利益サイズ;
- トレード期間。
最大利益点は、ポジションが開いた足の後に形成された主周期の最初の上下フラクタルの高値安値であるという仮定をする必要があります。
まず、ストラテジーテスターでEAの動作をテストする必要があります。 テストのため、 01.01.2018-29.08.2018 の期間の AUDJPY を選択します。 D1 は主な期間として選択され、この間に使用されていたのタスク時間枠です。 トレードごとのリスク-$100. ブレイクイーブンにポジションの1/2を移動し、1/3はTPです。
図4. EAインプット
テストが完了したら、レポートを CSV ファイルに保存します。 ターミナルローカルフォルダで、新しいreport.csv ファイルを作成します。 レポートデータをコピーします ([オーダー] セクションから)。 図5に示すように、ポジションのクローズに関連する行を削除する必要があります。
図5. レポートからの決済ポジションに関連する行の削除
コピーする列:
- オープンタイム;
- シンボル;
- タイプ;
- 価格;
- S/L.
結果として、report.csvファイルは次のようになります。
図6. report.csvファイルの内容
ここで、report.csv ファイルからデータを読み取り、追加の統計情報を含む新しい file_stat.csv ファイルを作成するスクリプトを作成する必要があります。
- SLsize;
- 最大利益レベル;
- 最大利益サイズ;
- 足のトレード期間。
このタスクを解決するため、 " MQL5 Programming Basics: Files " の「Reading a file with separators to an array(配列に区切りシンボルを含むファイルの読み取り)」から既製のソリューションを使用しました。 また、file_stat.csv ファイルに列の値を格納するための配列とその補完も追加しました。
新しいスクリプトを作成し、 OnStart() 関数の下の配列にファイルを読み取るための関数のコードを記述します。
//+------------------------------------------------------------------+ //| 配列関数への読み込み (開始) | //+------------------------------------------------------------------+ bool ReadFileToArrayCSV(string FileName,SLine &Lines[]) { ResetLastError(); int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_CSV,";"); if(h==INVALID_HANDLE) { int ErrNum=GetLastError(); printf("File open error %s # %i",FileName,ErrNum); return(false); } int lcnt=0; //文字列を計算するための変数 int fcnt=0; //文字列フィールドを計算するための変数 while(!FileIsEnding(h)) { string str=FileReadString(h); //新しい文字列 (新しい構造体配列要素) if(lcnt>=ArraySize(Lines)) { //構造配列の完全補完 ArrayResize(Lines,ArraySize(Lines)+1024); //1024の要素で配列のサイズを大きくする } ArrayResize(Lines[lcnt].field,64);//構造体の配列サイズを変更する Lines[lcnt].field[0]=str; //最初のフィールドの値を割り当てる //文字列の残りのフィールドの読み取りを開始します。 fcnt=1; //フィールド配列内の1つの要素が占有されている間 while(!FileIsLineEnding(h)) { //文字列の残りのフィールドを読み取る str=FileReadString(h); if(fcnt>=ArraySize(Lines[lcnt].field)) { //フィールドの配列が完全に埋められている ArrayResize(Lines[lcnt].field,ArraySize(Lines[lcnt].field)+64); //64の要素で配列のサイズを大きくする } Lines[lcnt].field[fcnt]=str; //次のフィールドの値を割り当てる fcnt++; //フィールドカウンタを増やす } ArrayResize(Lines[lcnt].field,fcnt); //実際のフィールド数に応じてフィールド配列のサイズを変更する lcnt++; //文字列カウンタを増やす } ArrayResize(Lines,lcnt); //文字列の実際の数に従って構造体 (文字列) の配列を変更 FileClose(h); return(true); } //+------------------------------------------------------------------+ //| 配列関数への読み込み (終了) | //+------------------------------------------------------------------+
次に、インプットを指定します。
#property script_show_inputs //---インプット input ENUM_TIMEFRAMES base_tf; //基準期間のタイムフレーム input double sar_step=0.1; //パラボリックステップの設定 input double maximum_step=0.11; //パラボリックの最大ステップを設定 //---インジケータハンドルの変数を宣言します。 int Fractal_base_tf; //iFractal インジケータハンドル //---base_tf の変数を宣言する double High_base_tf[],Low_base_tf[]; //高値と安値足の価格を格納するための配列 double FractalDown_base_tf[],FractalUp_base_tf[];//iFractall インジケータの価格を格納するための配列 //---配列構造 struct SLine { string field[]; };
OnStart() 関数の内部では、 iFractals インジケータハンドルを取得し、高値/安値の配列を宣言およびインプットします。 また、シンボル価格の小数点以下の桁数に応じて価格桁の容量を格納するために for ループと f 変数に使用する bars_base_tf 変数が必要です。 この変数は、SLと最大利益値を整数に変換するために使用します。
//---iFractal インジケータハンドルの取得 Fractal_base_tf=iFractals(Symbol(),base_tf); //---base_tf の時系列のように配列のオーダーを設定します。 ArraySetAsSeries(High_base_tf,true); ArraySetAsSeries(Low_base_tf,true); ArraySetAsSeries(FractalDown_base_tf,true); ArraySetAsSeries(FractalUp_base_tf,true); //---base_tf 用配列の初期補完 CopyHigh(Symbol(),base_tf,0,1000,High_base_tf); CopyLow(Symbol(),base_tf,0,1000,Low_base_tf); CopyBuffer(Fractal_base_tf,0,TimeCurrent(),1000,FractalUp_base_tf); CopyBuffer(Fractal_base_tf,1,TimeCurrent(),1000,FractalDown_base_tf); //---足の数にデータを格納するための変数 int bars_base_tf=Bars(Symbol(),base_tf); //シンボル価格の小数点以下の桁数 int Digit=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); //現在のシンボルの価格能力を定義します。 double f=1; if(Digit==5) {f=100000;} if(Digit==4) {f=10000;} if(Digit==3) {f=1000;} if(Digit==2) {f=100;} if(Digit==1) {f=10;}
次に、配列と変数を宣言します。
//---変数と配列を宣言する int i,j,n; //ループの変数 datetime opentime[];//ポジション設定時間を格納するための配列 string symbol[];//シンボルを格納するための配列 string type[];//トレードタイプを格納するための配列 string openprice[];//始値を格納するための配列 string sl_price[];//SLレベルを格納するための配列 int index[];//足のポジションのインデックスを格納するための配列が設定 int down_fractal[];//下のフラクタルインデックスを格納するための配列 int up_fractal[];//上のフラクタルインデックスを格納するための配列 double sl_size_points[];//SLサイズをポイント単位で格納するための配列 string maxprofit_price[];//最大利益レベルを格納するための配列 double maxprofit_size_points[];//最大利益値を格納するための配列 int duration[];//足の波の持続時間にデータを格納するための配列 bool maxprofit_bool[];//ポジションが ストップロス によってアクティブ化されないことを保証する配列 int maxprofit_int[];//最小/最大足を定義するための配列。 これは、maxprofit_bool[]と併用するべきです
この後、ファイルから配列へのデータの読み取りに移ります。
SLine lines[]; int size=0; if(!ReadFileToArrayCSV("report.csv",lines)) { Alert("Error, see details in the \"Experts\"" tab); } else { size=ArraySize(lines); ArrayResize(opentime,ArraySize(lines)); ArrayResize(symbol,ArraySize(lines)); ArrayResize(type,ArraySize(lines)); ArrayResize(openprice,ArraySize(lines)); ArrayResize(sl_price,ArraySize(lines)); ArrayResize(index,ArraySize(lines)); ArrayResize(down_fractal,ArraySize(lines)); ArrayResize(up_fractal,ArraySize(lines)); ArrayResize(sl_size_points,ArraySize(lines)); ArrayResize(maxprofit_price,ArraySize(lines)); ArrayResize(maxprofit_size_points,ArraySize(lines)); ArrayResize(duration,ArraySize(lines)); ArrayResize(maxprofit_bool,ArraySize(lines)); ArrayResize(maxprofit_int,ArraySize(lines)); for(i=0;i<size;i++) { for(j=0;j<ArraySize(lines[i].field);j=j+5)//ポジションオープンタイム列によるフィールドの選択 { opentime[i]=(datetime)(lines[i].field[j]);//配列へのデータの書き込み } for(j=1;j<ArraySize(lines[i].field);j=j+4)//シンボル列でフィールドを選択 { symbol[i]=(lines[i].field[j]);//配列へのデータの書き込み } for(j=2;j<ArraySize(lines[i].field);j=j+3)//トレードタイプ列別にフィールドを選択 { type[i]=(lines[i].field[j]);//配列へのデータの書き込み } for(j=3;j<ArraySize(lines[i].field);j=j+2)//オープンプライス列によるフィールドの選択 { openprice[i]=(lines[i].field[j]);//配列へのデータの書き込み } for(j=4;j<ArraySize(lines[i].field);j=j+1)//SL列でフィールドを選択 { sl_price[i]=(lines[i].field[j]);//配列へのデータの書き込み } } } //-----------------------------------------------------
openrpice[]および sl_price[]配列には文字列データ型があります。 計算で使用するには、 StringToDouble()関数を使用して double 型 に変換します。 ただし、この場合、小数は失われます。 これを回避するには、 StringReplace()関数を使用してコンマをピリオドに置き換えます。
for(i=0;i<size;i++) { StringReplace(openprice[i],",","."); StringReplace(sl_price[i],",","."); }
次に、ポジションが配置されている足のインデックスを定義します。
//---足のポジションの定義のインデックスは、下で開かれた for(i=0;i<size;i++) { index[i]=iBarShift(Symbol(),PERIOD_D1,opentime[i]);//配列へのデータの書き込み }
その後、配置ポジションに最も近い上下のフラクタルを見つける:
//---売りのダウンフラクタルを検索 for(i=0;i<size;i++) { if(type[i]=="sell") { for(n=index[i];n>0;n--) { if(FractalDown_base_tf[n]!=EMPTY_VALUE) break; } down_fractal[i]=n; } } //---買いのフラクタルを検索 for(i=0;i<size;i++) { if(type[i]=="buy") { for(n=index[i];n>0;n--) { if(FractalUp_base_tf[n]!=EMPTY_VALUE) break; } up_fractal[i]=n; } }
次に、SLをポイント単位で定義し、ポイント数を整数に変換します。
//---ポイントのSL for(i=0;i<size;i++) { if(type[i]=="sell") { sl_size_points[i]=(StringToDouble(sl_price[i])-StringToDouble(openprice[i]))*f; } if(type[i]=="buy") { sl_size_points[i]=(StringToDouble(openprice[i])-StringToDouble(sl_price[i]))*f; } }
以前に検出されたフラクタルに基づいて、最大利益レベルを決定することができます。 しかし、まずポジションが途中でSLによって閉じられないことを確認する必要があります。 チェックコード:
//---最大利益に達する前に、ポジションが ストップロス によって閉じられていないことを確認してください //---売りのトレード for(i=0;i<size;i++) { if(type[i]=="sell") { for(n=index[i];n>down_fractal[i];n--) { if(High_base_tf[n]>=StringToDouble(sl_price[i])) break; } maxprofit_int[i]=n; maxprofit_bool[i]=(n==down_fractal[i]); } } //---買いトレード for(i=0;i<size;i++) { if(type[i]=="buy") { for(n=index[i];n>up_fractal[i];n--) { if(Low_base_tf[n]<=StringToDouble(sl_price[i])) break; } maxprofit_int[i]=n; maxprofit_bool[i]=(n==up_fractal[i]); } }
次に、最大利益レベルを決定するためのコードを記述します。
//---最大利益レベル for(i=0;i<size;i++) { if(type[i]=="sell" && maxprofit_bool[i]==true) { maxprofit_price[i]=(string)Low_base_tf[down_fractal[i]]; } if(type[i]=="sell" && maxprofit_bool[i]==false) { maxprofit_price[i]=""; } if(type[i]=="buy" && maxprofit_bool[i]==true) { maxprofit_price[i]=(string)High_base_tf[up_fractal[i]]; } if(type[i]=="buy" && maxprofit_bool[i]==false) { maxprofit_price[i]=""; } }
次に、最大利益のサイズを決定することができます。 コントロールがアクティブになっている場合、利益は負になります。
for(i=0;i<size;i++) { if(type[i]=="sell" && maxprofit_bool[i]==true) { maxprofit_size_points[i]=(StringToDouble(openprice[i])-Low_base_tf[down_fractal[i]])*f; } if(type[i]=="sell" && maxprofit_bool[i]==false) { maxprofit_size_points[i]=sl_size_points[i]*-1; } if(type[i]=="buy" && maxprofit_bool[i]==true) { maxprofit_size_points[i]=(High_base_tf[up_fractal[i]]-StringToDouble(openprice[i]))*f; } if(type[i]=="buy" && maxprofit_bool[i]==false) { maxprofit_size_points[i]=sl_size_points[i]*-1; } }
最後に、ポジションが置かれている足と最大利益 1 (足) の間の期間を定義してみましょう。 sl 決済制御が有効になっている場合、その期間は、ポジションが設定されている足と、sl がトリガされる1との間の差として定義されます。
//---足でのトレード期間の計算 for(i=0;i<size;i++) { if(type[i]=="sell" && maxprofit_bool[i]==true) { duration[i]=index[i]-(int)down_fractal[i]; } if(type[i]=="sell" && maxprofit_bool[i]==false) { duration[i]=index[i]-maxprofit_int[i]; } if(type[i]=="buy" && maxprofit_bool[i]==true) { duration[i]=index[i]-(int)up_fractal[i]; } if(type[i]=="buy" && maxprofit_bool[i]==false) { duration[i]=index[i]-maxprofit_int[i]; } }
その後、パラメータの正しい表示にピリオドをコンマに戻してみましょう。
for(i=0;i<size;i++) { StringReplace(openprice[i],".",","); StringReplace(sl_price[i],".",","); StringReplace(maxprofit_price[i],".",","); }
さて、file_stat.csv ファイルに取得したデータを書き込む作業が残っています:
//---新しい統計ファイルにデータを書き込む int h=FileOpen("file_stat.csv",FILE_READ|FILE_WRITE|FILE_ANSI|FILE_CSV,";"); //---オープン確認 if(h==INVALID_HANDLE) { Alert("Error opening file!"); return; } else { FileWrite(h, /*1 symbol*/"Symbol", /*2 deal type*/"Deal type", /*3 entry time*/"Open time", /*4 open price*/"Open price", /*5 sl level*/"SL", /*6 sl level*/"SL size", /*7 max profit level*/"Max profit level", /*8 max profit value*/"Max profit value", /*9 duration*/"Duration in bars"); //---最後に移動する FileSeek(h,0,SEEK_END); for(i=0;i<size;i++) { FileWrite(h, /*1 symbol*/symbol[i], /*2 deal type*/type[i], /*3 entry time*/TimeToString(opentime[i]), /*4 open price*/openprice[i], /*5 sl level*/sl_price[i], /*6 sl size*/NormalizeDouble(sl_size_points[i],2), /*7 max profit level*/maxprofit_price[i], /*8 max profit size*/NormalizeDouble(maxprofit_size_points[i],2), /*9 duration*/duration[i]); } } FileClose(h); Alert("file_stat.csv file created");
チェック: インプット (場合は D1) のベース期間を設定した後、チャート上のスクリプトを起動します。 その後、次のパラメータのセットを持つ新しい file_stat.csv ファイルがターミナルのローカルフォルダに表示されます。
図7. file_stat.csv ファイルの内容
6. 結論
この記事では、運動継続モデルの1つをプログラムによって決定する方法を分析しました。 この方法の重要な考え方は、任意のインジケータを適用することがない、高値/安値極値補正運動の検索です。 モデルの連続した点は、見つかった極値に基づいて検出されます。
また, テスト結果を配列に書き込んで, その後の処理を行うことにより, ストラテジーテスタのテスト結果に基づいて統計データを収集する方法についても検討しました。 統計データを処理する、より効率的な方法を開発することが可能だと思います。 しかし、このメソッドは、最もシンプルで包括的だと思います。
この記事では、モデルを定義するための最小要件、最も重要なのは、EAによって提供される最小限のコントロールセットを説明していることに注意してください。 実際のトレードでは、コントロールのセットを展開する必要があります。
運動継続モデル認識の例を以下に示します。
図8. サンプル運動継続モデルの認識
図9. サンプル運動継続モデルの認識
図10. サンプル運動継続モデルの認識
図11. サンプル運動継続モデルの認識
記事で使用するプログラム
# | 名前 | タイプ | 詳細 |
---|---|---|---|
1 | Trade.mqh | クラスライブラリ | トレーディング・オペレーションのクラス |
2 | MQL5_POST_final | EA | 運動継続モデルを定義するEA |
3 | Report_read | Script | 統計情報を収集するためのスクリプト |
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/4222





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