MQL5 と MQL4 の選択とナビゲーションユーティリティ: パターンの自動検索の追加と検出されたシンボルの表示
イントロダクション
多くのトレード戦略では、さまざまな相場参入パターンを検索する際に銘柄に対する一定の分析が必要です。 シンボルの検索と分析は相場に対する洞察を得る上で有用かもしれませんが、場合によっては、必要なパラメータを備えたシンボルのリストを表示することが必要になる場合があります。 この記事では、デイトレードパターンのこのようなツールを開発します。
具体的には、現在、特定のパラメータによってシンボルの自動ソートを追加することにより、ユーティリティの機能を拡張します。 これを行うには、現在、特定のトレードパターンをフィーチャーしたシンボルを検索する一連のタブを作成します: パラボリック曲線、エアーレベル (レンジな範囲)、ギャップなどがあります。 また、MQL プログラミングの基本を知っていれば、カスタムタブを追加する方法についても学習できます。
前回の記事のように、このユーティリティは MQL4 と MQL5 の両方で動作します。 MQL5 で自動ソートタブを開くことは MQL4 よりもスローと言うべきです。 これは、リクエストされたシンボルに必要な深さまでのヒストリーがない場合に発生します。 このような場合、MetaTrader5 はトレードサーバからのヒストリーをリクエストし、必要な時間枠を構築します。
したがって、タブをクリックしたときに何も起こらない場合、またはすべてのボタンが消える場合は、パニックにならず、ただ待ってください。 15 ~ 20 秒で、必要なシンボルが表示されます。 何百ものシンボルのチャートを手動で表示するよりも高速です。 一方、MetaTrader4 では、必要なシンボルとタイムフレームのヒストリーを独立して提供する必要があり、そのようなささいなことにも時間と注意が必要です。
さらに、コンピュータに少量の ram が搭載されている場合 (または 1 GB などの ram 容量が限られている仮想マシンでタスクしている場合)、MQL5 では、自動ソートタブを開くときにメモリ不足エラーによってEA操作が中断されることがあります。 タイムフレームヒストリー全体が異なる深さで個別にアップロードされるため、MQL4 にはこのような問題はありません。 MQL5 では、 「チャートの最大足」パラメータを制限することで問題を解決することができます。
自動並べ替えタブに機能を追加する
最初に、[自動並べ替え] タブをユーティリティに追加する方法を定義しましょう。 これを行うには、タブのメカニズムが内部からどのように設計されているかを理解する必要があります。
以前の記事でタブを追加する関数は既に実装されています。 覚えているかもしれませんが、ループを行います。 ホームワークのタブの名前が配列に保存されます。 自動並べ替えタブの名前も、別の配列に保存されます。
string panelNamesAddon[9]={"Air Level", "Parabolic", "Gap", "4 weeks Min/Max", "365 days Min/Max", "Round levels", "Mostly Up/Down", "All time high/low", "High=Close"};
つまり、カスタムタブを追加するには、配列のサイズを1ずつ増やして、タブのリストの最後に追加する必要があります。 その後、ユーティリティに新しいタブが表示されます。
show_panel_buttons関数は、タブを表示する役割を担います。 そのコードが変更されている、すべての自動並べ替えタブは、ホームワークのタブに加えて表示されます。
void show_panel_buttons(){ int btn_left=0; //タブを表示可能な最大 x 座標を定義します。 int btn_right=(int) ChartGetInteger(0, CHART_WIDTH_IN_PIXELS)-77; string tmpName=""; for( int i=0; i<ArraySize(panelNames); i++ ){ //新しいボタンの開始座標が可能な最大値を超える場合は、 //新しい行に移動します。 if( btn_left>btn_right-BTN_WIDTH ){ btn_line++; btn_left=0; } //[ホームワーク] タブにシンボルが付いている場合は、その番号を追加します。 //タブ名に tmpName=panelNames[i]; if(i>0 && arrPanels[i].Total()>0 ){ tmpName+=" ("+(string) arrPanels[i].Total()+")"; } //タブボタンの表示 ObjectCreate(0, exprefix+"panels"+(string) i, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_XDISTANCE,btn_left); ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_XSIZE,BTN_WIDTH); ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_COLOR,clrBlack); ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_BGCOLOR,clrSilver); ObjectSetString(0,exprefix+"panels"+(string) i,OBJPROP_TEXT,tmpName); ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_SELECTABLE,false); //[ボタン] タブが現在アクティブな場合は、 //押させる if( cur_panel == i ){ ObjectSetInteger(0,exprefix+"panels"+(string) i,OBJPROP_STATE, true); } btn_left+=BTN_WIDTH; } //自動ソートタブの表示がインプットによって許可されている場合は、 if(useAddonsLevels){ for( int i=0; i<ArraySize(panelNamesAddon); i++ ){ if( btn_left>btn_right-BTN_WIDTH ){ btn_line++; btn_left=0; } tmpName=panelNamesAddon[i]; //タブが Gap と呼ばれる場合は、現在のインプットパラメータ値を表示します。 //ギャップ率の定義 if(tmpName=="Gap"){ StringAdd(tmpName, " ("+(string) gap_min+"%)"); } ObjectCreate(0, exprefix+"panels"+(string) (i+ArraySize(panelNames)), OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_XDISTANCE,btn_left); ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_XSIZE,BTN_WIDTH); ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_COLOR,clrBlack); ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_BGCOLOR,clrLightSteelBlue); ObjectSetString(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_TEXT,tmpName); ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_SELECTABLE,false); if( cur_panel == i+ArraySize(panelNames) ){ ObjectSetInteger(0,exprefix+"panels"+(string) (i+ArraySize(panelNames)),OBJPROP_STATE, true); } btn_left+=BTN_WIDTH; } } //設定されている場合はコメントを表示: if(StringLen(cmt)>0){ string tmpCMT=cmt; if(from_txt){ StringAdd(tmpCMT, ", from txt"); } ObjectCreate(0, exprefix+"title", OBJ_EDIT, 0, 0, 0); ObjectSetInteger(0,exprefix+"title",OBJPROP_XDISTANCE,btn_left+11); ObjectSetInteger(0,exprefix+"title",OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"title",OBJPROP_XSIZE,133); ObjectSetInteger(0,exprefix+"title",OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"title",OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"title",OBJPROP_COLOR,clrGold); ObjectSetInteger(0,exprefix+"title",OBJPROP_BGCOLOR,clrNONE); ObjectSetInteger(0,exprefix+"title",OBJPROP_BORDER_COLOR,clrBlack); ObjectSetString(0,exprefix+"title",OBJPROP_TEXT,tmpCMT); ObjectSetInteger(0,exprefix+"title",OBJPROP_SELECTABLE,false); } }
関数のコードでわかるように、自動並べ替えタブは、 addons_infowatchインプットで許可されている場合にのみ表示されます。 加えて、自動ソートタブを設定するために、さらに2つのパラメータを追加します。
sinput string delimeter_05=""; //追加のタブ input bool useAddonsLevels=true; //追加のタブを表示する input bool addons_infowatch=true;//マーケットウォッチにない場合はシンボルを非表示にする input int addon_tabs_scale=3; //追加タブのスケール (0-5)
addons_infowatchパラメータだけがここで余分な明確化を必要とすると思います。 設定されている場合は、 Market Watchタブのシンボルのみがソートされます。 それ以外の場合は、ブローカーが提供するすべてのシンボルに対してソートが実行されます。
その結果、ユーティリティの新しいバージョンを起動すると、ホームワークのものとは別に新しい自動ソートタブを見ることができます。
しかし、コードに戻りましょう。 ここでは、自動並べ替えタブを追加する方法がわかっています。 ただし、シンボル表示はまだ実装されていないため、これまでのところクリックしてもシンボルは表示されません。 現在開いているタブのすべてのボタンは、 show_symbols関数を使用して表示されます。 ここでは、自動並べ替えタブの表示を追加していきます。 その結果、関数は次のようになります。
void show_symbols(){ //X および Y 座標を定義するための変数を初期化します。 int btn_left=0; int btn_right=(int) ChartGetInteger(0, CHART_WIDTH_IN_PIXELS)-77; btn_line++; if( cur_panel==0 ){ ObjectCreate(0, exprefix+"clear_"+(string) cur_panel, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_XDISTANCE,btn_left); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_XSIZE,BTN_WIDTH); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_COLOR,clrBlack); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_BGCOLOR,clrPaleTurquoise); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_SELECTABLE,false); ObjectSetString(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_TEXT,"Clear All"); btn_left+=BTN_WIDTH; ObjectCreate(0, exprefix+"showpos", OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0,exprefix+"showpos",OBJPROP_XDISTANCE,btn_left); ObjectSetInteger(0,exprefix+"showpos",OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"showpos",OBJPROP_XSIZE,BTN_WIDTH); ObjectSetInteger(0,exprefix+"showpos",OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"showpos",OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"showpos",OBJPROP_COLOR,clrBlack); ObjectSetInteger(0,exprefix+"showpos",OBJPROP_BGCOLOR,clrPaleTurquoise); ObjectSetInteger(0,exprefix+"showpos",OBJPROP_SELECTABLE,false); ObjectSetString(0,exprefix+"showpos",OBJPROP_TEXT,"Show Pos"); btn_left+=BTN_WIDTH; }else if( cur_panel<ArraySize(arrPanels) && arrPanels[cur_panel].Total()>0 ){ ObjectCreate(0, exprefix+"clear_"+(string) cur_panel, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_XDISTANCE,btn_left); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_XSIZE,BTN_WIDTH); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_COLOR,clrBlack); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_BGCOLOR,clrPaleTurquoise); ObjectSetInteger(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_SELECTABLE,false); ObjectSetString(0,exprefix+"clear_"+(string) cur_panel,OBJPROP_TEXT,"Clear"); btn_left+=BTN_WIDTH; ObjectCreate(0, exprefix+"new_"+(string) cur_panel, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0,exprefix+"new_"+(string) cur_panel,OBJPROP_XDISTANCE,btn_left); ObjectSetInteger(0,exprefix+"new_"+(string) cur_panel,OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"new_"+(string) cur_panel,OBJPROP_XSIZE,BTN_WIDTH); ObjectSetInteger(0,exprefix+"new_"+(string) cur_panel,OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"new_"+(string) cur_panel,OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"new_"+(string) cur_panel,OBJPROP_COLOR,clrBlack); ObjectSetInteger(0,exprefix+"new_"+(string) cur_panel,OBJPROP_BGCOLOR,clrPaleTurquoise); ObjectSetInteger(0,exprefix+"new_"+(string) cur_panel,OBJPROP_SELECTABLE,false); ObjectSetString(0,exprefix+"new_"+(string) cur_panel,OBJPROP_TEXT,"Open All"); btn_left+=BTN_WIDTH; } //現在開いているタブのインデックスが、[ホームワーク] タブの要素の数を超えている場合配列要素 //そして、すべてのシンボルを含むタブでは、 //次に、[自動並べ替え] タブをクリックします if(cur_panel>(ArraySize(arrPanels)-1)){ MqlRates rates[]; ArraySetAsSeries(rates, true); int tmpNumAddon=cur_panel-ArraySize(arrPanels); addonArr.Resize(0); arrTT.Resize(0); string addonName; CArrayString tmpSymbols; if( tmpNumAddon==0 && air_only_home ){ for( int j=1; j<ArraySize(arrPanels); j++ ){ for( int k=0; k<arrPanels[j].Total(); k++ ){ string curName=arrPanels[j].At(k); bool isYes=false; for( int r=0; r<tmpSymbols.Total(); r++ ){ if(tmpSymbols.At(r)==curName){ isYes=true; break; } } if(!isYes){ tmpSymbols.Add(arrPanels[j].At(k)); } } } }else{ if( ArraySize(result)>1 ){ for(int j=0;j<ArraySize(result);j++){ StringReplace(result[j], " ", ""); if(StringLen(result[j])<1){ continue; } tmpSymbols.Add(onlySymbolsPrefix+result[j]+onlySymbolsSuffix); } }else{ for( int i=0; i<SymbolsTotal(addons_infowatch); i++ ){ tmpSymbols.Add(SymbolName(i, addons_infowatch)); } } } switch(tmpNumAddon){ case 0: //エアーレベル //タブの内容表示コード break; case 1: //パラボリック //タブの内容表示コード break; case 2: //ギャップ //タブの内容表示コード break; case 3: //4週間 min/max //タブの内容表示コード break; case 4: //365日 min/max //タブの内容表示コード break; case 5: //ラウンドレベル //タブの内容表示コード break; case 6: // mostly up/down //タブの内容表示コード break; case 7: // all time high/low //タブの内容表示コード break; case 8: // high=close //タブの内容表示コード break; } //配列内の各シンボルのボタンがチャートに表示されます。 //シンボル名がボタンに追加されます。 for( int i=0; i<addonArr.Total(); i++ ){ if( btn_left>btn_right-BTN_WIDTH ){ btn_line++; btn_left=0; } ObjectCreate(0, exprefix+"btn"+(string) i, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_XDISTANCE,btn_left); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_XSIZE,BTN_WIDTH); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_COLOR,clrBlack); ObjectSetString(0,exprefix+"btn"+(string) i,OBJPROP_TEXT,addonArr.At(i)); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_SELECTABLE,false); if( arrTT.At(i)>0 ){ ObjectSetString(0,exprefix+"btn"+(string) i,OBJPROP_TOOLTIP,(string) arrTT.At(i)); } if( checkSYMBwithPOS(addonArr.At(i)) ){ ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_BGCOLOR,clrPeachPuff); } btn_left+=BTN_WIDTH; } //ボタンは既に表示されているため、関数を終了します。 return; } //配列内の各シンボルのチャート上にボタンを表示します。 //現在アクティブなタブの //シンボル名がボタンに追加されます。 for( int i=0; i<arrPanels[cur_panel].Total(); i++ ){ if( btn_left>btn_right-BTN_WIDTH ){ btn_line++; btn_left=0; } ObjectCreate(0, exprefix+"btn"+(string) i, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_XDISTANCE,btn_left); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_YDISTANCE,BTN_HEIGHT*btn_line); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_XSIZE,BTN_WIDTH); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_YSIZE,BTN_HEIGHT); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_FONTSIZE,8); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_COLOR,clrBlack); ObjectSetString(0,exprefix+"btn"+(string) i,OBJPROP_TEXT,arrPanels[cur_panel].At(i)); ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_SELECTABLE,false); if( !noSYMBwithPOS || cur_panel>0 ){ if( checkSYMBwithPOS(arrPanels[cur_panel].At(i)) ){ ObjectSetInteger(0,exprefix+"btn"+(string) i,OBJPROP_BGCOLOR,clrPeachPuff); } } btn_left+=BTN_WIDTH; } }
ご覧のとおり、タブの内容を表示するコードは、 switch演算子の内部にあります。 タブ名を含む配列要素のインデックスは、 case演算子で示されます。 したがって、その名前を配列に追加した後にカスタムタブを追加するには、インデックス1が最後に適用されたインデックスを超える新しいcaseを追加するだけです。
特定のタブを考慮する際に、特定のパラメータによる自動ソートシンボルのコードサンプルを詳しく見ていきます。 しかし、すでにすべてのタブのコードが同様の方法で開始されていることがわかります。
ソートされるすべてのシンボルのリストは、 tmpSymbols配列にすでに存在します。 したがって、各タブのコードはforループから始まります。
for( int i=0; i<tmpSymbols.Total(); i++ ){ addonName=tmpSymbols[i]; //シンボルを表示するかどうかを定義するコード }
エアーレベル (レンジ)
レベルからのトレードの場合、すべてのインプットはレンジの近くで実行され、価格が同じまたはほぼ同じ価格になると、各足での高値または安値によって行われます。 この例は、次のイメージに表示されます。
これは、得られたレベルが一定のダマシブレイクスルーを経験するので完璧な例ではないかもしれません。 しかし、一方で、ダマシのブレイクスルーの存在がレベルを強化すると考えられています。 =)
このような状況を検索することは面倒なタスクですので、自動化してみましょう。
レンジの検索は、通常、M5 チャートで実行されますが、必須条件ではありません。 一部のトレーダーは、M15 または M30 チャート上で動作させます。 レンジが検出された時間枠が高いほど、潜在的なエントリーが良くなると考えられています。
したがって、インプットを追加して、必要な時間枠を定義することができます。
sinput string delimeter_06=""; // --- Additional Air levels tab --- input bool air_level_m5=true; // Search for air levels on M5 input bool air_level_m15=true; // Search for air levels on M15 input bool air_level_m30=false; // Search for air levels on M30 input bool air_level_h1=false; // Search for air levels on H1 input bool air_level_h4=false; // Search for air levels on H4 input bool air_level_d1=false; // Search for air levels on D1
選択した時間枠が多いほど、検索プロセスが遅くなることを忘れないでください。 したがって、1つまたは2つの時間枠で検索を制限することをお勧めします。
また、他のインプットを追加してみましょう。
input uchar air_level_count=4; //レベル足の数 input uchar air_level_offset=3; //ポイントのレベルを基準としたオフセット input bool air_level_cur_day=true; //現在の日の方向のレベルのみ input bool air_level_prev_day=true; //前日の方向のレベルのみ input bool air_only_home=false; //「ホームワーク」でのみ検索
[レベル足の数] パラメータでは、をレンジな範囲と見なすために、厳密に配置された価格に接する足の数を指定できます。 このパラメータの最適値は4小節です。 足の数が多いほど、レンジの品質は高くなりますが、検出頻度は低くなります。
[ポイント単位でのオフセット] パラメータを使用すると、価格が "密接に配置されている" と仮定する必要があるポイントの範囲を指定できます。 つまり、パラメータが0の場合、足はセントまでの同じ価格に正確に接する必要があります。 一般的に、このような場合は、特に高い時間枠では少なくなります。 ほとんどの場合、価格はからポイントでストップし、指定されたレベルに到達することはできません、したがって、デフォルトのパラメータ値は3ポイントです。
現在および/または前日の方向でのみトレードを行う場合、現在の日の方向のレベルと前日の方向のレベルのみが、検出されたレンジが反対方向を持つソートシンボルを許可します。価格の動き。
価格の移動方向は、始値に対する終値の比率によって定義されます。 前の日の足の終値が開いているものを超えている場合は、長い間のレンジな範囲、すなわち「安値」によって密接に位置する価格に触れるものを詳しく見ることができます。
最後に、最終的なパラメータを見てみましょう- 「ホームワーク」でのみ検索します。 日中に、ホームワークタブに追加した銘柄のみをトレードする場合、ユーティリティが現在ホームワークタブに追加されているシンボルに対してのみレンジを検索するようにパラメータを設定します。
次に、現在レンジな範囲を特徴とするシンボルを並べ替えるコードを見てみましょう。 M5 時間枠のコードは以下のとおりです。
if(air_level_m5 && CopyRates(addonName, PERIOD_M5, 0, air_level_count+1, rates)==air_level_count+1){ if( (!air_level_cur_day || getmeinfoday_symbol(addonName, 0)<=0) && (!air_level_prev_day || getmeinfoday_symbol(addonName, 1)<=0) && rates[0].high<rates[1].high ){ bool isOk=true; for( int j=1; j<air_level_count; j++ ){ if( MathAbs(rates[1].high-rates[j+1].high) <= air_level_offset*SymbolInfoDouble(addonName, SYMBOL_POINT) ){ }else{ isOk=false; } } if(isOk && !skip_symbol(addonName)){ addonArr.Add(addonName+" (M5)"); arrTT.Add(rates[1].high); } }else if( (!air_level_cur_day || getmeinfoday_symbol(addonName, 0)>=0) && (!air_level_prev_day || getmeinfoday_symbol(addonName, 1)>=0) && rates[0].low>rates[1].low ){ bool isOk=true; for( int j=1; j<air_level_count; j++ ){ if( MathAbs(rates[1].low-rates[j+1].low) <= air_level_offset*SymbolInfoDouble(addonName, SYMBOL_POINT) ){ }else{ isOk=false; } } if(isOk && !skip_symbol(addonName)){ addonArr.Add(addonName+" (M5)"); arrTT.Add(rates[1].low); } } }
自動並べ替えタブの他のすべてのコードサンプルと同様に、ここでは、呼び出しの直後にCopyRates関数呼び出しの結果を使用してタスクを開始します。 これが完全に正しいわけではありません。 MQL ヘルプでは、ユーティリティーが配列にデータを受信して書き込むのをしばらく待っていることをお勧めしています。 しかし、50ミリ秒を待っている場合、100シンボルをチェックすると5秒の遅延になりますが、多くのブローカーは、株式相場のシンボルの数百を提供します。 その結果、遅延を使用した場合、タブの内容を表示するのにかなりの時間がかかることがあります。
したがって、すぐに結果の配列でタスクを開始します。 実際には、遅延がないことによって引き起こされたものを除いて、問題はありません。
実際のデータは、 CopyRates関数の結果として、常に配列に転送されるとは限りません。 並べ替えで古いデータが使用することがあります。 この場合は、タブ (R キー) を更新するだけで、関連するシンボルリストを取得できます。
さて、コードに戻りましょう。 カスタム自動並べ替えタブを追加する場合は、シンボルの選択がどのように行われるかに注意してください。
シンボルが条件に適合する場合は、その名前をaddonArr配列に配置します。 また、括弧内のデフォルトの時間枠ではなく、シンボルチャートを開くときに使用する時間枠を指定することができます。
また、 arrTT配列に値をインプットする必要があります。 配列で値0を設定すると、何も起こりません。 しかし、代わりに価格を追加すると、適切な銘柄のチャートを開くときに、指定された価格レベルで水平線が作成されます。 すぐにレンジが検出された価格を見ることができるように行われます。
パラボリックラウンディング
パラボリックラウンディングは、価格が反対方向に移動を開始したときに方向の動きの後に表示されます。 そして、それぞれの新しい足の高値または安値は、以前のものよりも高いか低いです。 この場合、価格は、安値の上昇または高減少に向かって行く可能性が高いと考えられています。 この場合、小さいストップロス を使用することができます。
言い換えれば、減少した後、価格が上昇し始め、各足の安値は、前のものよりも高いです。 この場合、前の足の少なくとも1つの後ろにストップレベルを置いてください。
例として、次のチャートを考えてみましょう。
サンプルパラボリックラウンディングは矢印でマークされています。
次のコードを使用して、M5 でパラボリックラウンディングを詳しく見ることができます。
if(CopyRates(addonName, PERIOD_M5, 0, 6, rates)==6){ if( rates[0].low>rates[1].low && rates[1].low>rates[2].low && rates[2].low<=rates[3].low && rates[3].low<=rates[4].low && rates[4].low<=rates[5].low ){ if(!skip_symbol(addonName)){ addonArr.Add(addonName+" (M5)"); arrTT.Add(0); } }else if( rates[0].high<rates[1].high && rates[1].high<rates[2].high && rates[2].high>=rates[3].high && rates[3].high>=rates[4].high && rates[4].high>=rates[5].high ){ if(!skip_symbol(addonName)){ addonArr.Add(addonName+" (M5)"); arrTT.Add(0); } } }
言い換えれば、現在の足の安値が前のもの安値を超えた場合、その足の安値は、それ自体の前の足の安値を超えます。 残りの3つの前の足は、安値で互いに等しいか、それぞれが他よりも小さいです。 言い換えると、3つの足が下降して2つ上に続く場合、ロングパラボリックラウンディングの始まりとみなされます。
ギャップ
一方の方向にギャップがある銘柄を扱うトレードストラテジーを使用する場合、ギャップタブは必要な銘柄を選択するのに役立ちます。 現在の日付の間にギャップがあるシンボルが表示されます。 最小ギャップサイズインプットを使用して、最小ギャップ (現在の価格に対する割合) を変更できます。
デフォルトでは、少なくとも 1% のギャップを持つシンボルのみが表示されます。
タブのソースコードはシンプルです。
if(CopyRates(addonName, PERIOD_D1, 0, 2, rates)==2){ if( rates[0].open>rates[1].close+(rates[0].open*(gap_min/100)) || rates[0].open<rates[1].close-(rates[0].open*(gap_min/100)) ){ if(!skip_symbol(addonName)){ addonArr.Add(addonName+" (M5)"); arrTT.Add(0); } } }
4週間の高値/安値
[ 4 週間の最小/最大] タブには、4週間以内の最高/最低点での現在の価格を持つ銘柄のリストが表示されます。 そのコードは次のとおりです。
if(CopyRates(addonName, PERIOD_W1, 0, 4, rates)==4){ bool newMin=true; bool newMax=true; if( rates[0].close!=rates[0].high && rates[0].close!=rates[0].low ){ newMin=false; newMax=false; }else{ for( int j=1; j<4; j++ ){ if( rates[0].high < rates[j].high ){ newMax=false; } if( rates[0].low > rates[j].low ){ newMin=false; } } } if( newMin || newMax ){ if(!skip_symbol(addonName)){ addonArr.Add(addonName+" (M5)"); arrTT.Add(0); } } }
年の高値/安値
前のタブと同様に、現在のものは、1年以内の最高/最低点での価格のシンボルを表示します。
if(CopyRates(addonName, PERIOD_W1, 0, 52, rates)==52){ bool newMin=true; bool newMax=true; if( rates[0].close!=rates[0].high && rates[0].close!=rates[0].low ){ newMin=false; newMax=false; }else{ for( int j=1; j<52; j++ ){ if( rates[0].high < rates[j].high ){ newMax=false; } if( rates[0].low > rates[j].low ){ newMin=false; } } } if( newMin || newMax ){ if(!skip_symbol(addonName)){ addonArr.Add(addonName+" (M5)"); arrTT.Add(0); } } }
ラウンドレベルの近くの価格
株価は「自然」のサポート/レジスタンスレベルであると考えられています。 したがって、トレードシステムは、現在、ラウンドレベルでトレードツールに焦点を当てています。
ラウンド価格は0または50セントで終了するもので、たとえば、125ドル0セントまたは79ドル50セントです。
その結果、次のコードになります。
switch((int) SymbolInfoInteger(addonName, SYMBOL_DIGITS)){ case 0: break; case 2: if(CopyRates(addonName, PERIOD_M5, 0, 1, rates)==1){ double tmpRound=rates[0].close - (int) rates[0].close; if( (tmpRound>0.46 && tmpRound<0.54) || tmpRound>0.96 || tmpRound<0.04 ){ if(!skip_symbol(addonName)){ addonArr.Add(addonName+" (M5)"); arrTT.Add(0); } } } break; }つまり、価格が小数点以下2桁のシンボルに対してのみ、ラウンド価格を定義します。 他のツールを使用する場合は、同様の方法で独自のチェックを追加するだけです。
時間のアップ/ダウン
時間のアップ/ダウンは、特に興味深い場合もあります。 次のインプットを追加して検索してみましょう。
sinput string delimeter_08=""; //---その他の主なアップ/ダウンタブ--- input int mostly_count=15; //最後に指定した日数を確認する input int mostly_percent=90; //指定された1方向の割合を超えた
最後に指定された日数を確認パラメータでは、必要なツールを検索する日数を定義できます。 言い換えれば、主に D1 で一方向の動きを探します。
1 つの方向で指定されたパーセンテージを超えると、1つの移動方向を超える最小パーセントを指定できます。 デフォルト値は90です。 このタブを取得するために、価格は分析期間全体のうちの特定の方向 90% の日数で移動する必要があることを意味します。
一般に、そのようなシンボルの数は少ないです。 したがって、この割合を減らす必要があるかもしれません。
タブコードは次のとおりです。
if(CopyRates(addonName, PERIOD_D1, 1, mostly_count, rates)==mostly_count){ int mostlyLong=0; int mostlyShort=0; for( int j=0; j<mostly_count; j++ ){ if(rates[j].close>rates[j].open){ mostlyLong++; }else if(rates[j].close<rates[j].open){ mostlyShort++; } } if( !mostlyLong || !mostlyShort ){ addonArr.Add(addonName); arrTT.Add(0); }else if( ((mostlyLong*100)/(mostlyLong+mostlyShort)) >= mostly_percent ){ addonArr.Add(addonName); arrTT.Add(0); }else if( ((mostlyShort*100)/(mostlyLong+mostlyShort)) >= mostly_percent ){ addonArr.Add(addonName); arrTT.Add(0); } }
新しい高値/安値を持つ各足
このタブは、シンボル内のアキュムレーションプロセスを検出することができます。すなわち、価格はゆっくりと、しかし一貫して一方向に移動する期間です。 一般的に、アキュムレーションは、その方向にブレイクスルー (大きな足) で終了します。
次のインプットは、一方向の動きを検出するのに役立ちます。
sinput string delimeter_09=""; //---追加のすべての時間の高値/安値タブ--- input ENUM_TIMEFRAMES alltime_period=PERIOD_D1; //期間 input int alltime_count=15; //最後に指定した小節数を確認する
並べ替えのコードは次のとおりです。
if(CopyRates(addonName, alltime_period, 1, alltime_count, rates)==alltime_count){ bool alltimeHigh=true; bool alltimeLow=true; for( int j=1; j<alltime_count; j++ ){ if(rates[j].high>rates[j-1].high){ alltimeHigh=false; } if(rates[j].low<rates[j-1].low){ alltimeLow=false; } } if( alltimeHigh || alltimeLow ){ addonArr.Add(addonName); arrTT.Add(0); } }
セッションが日の高値/安値で終了
これが、最後に追加するタブです。 呼び出しの時間に応じて、次のものを検出できます。
- セッションが開始する前に-前の日の高値/安値で閉じたシンボル。
- セッションが開始した後-現在の日の高値/安値であるシンボル。
価格は、その日の高値/安値で閉じた場合、買い手/売り手はまだ計画を実施する時間を持っていないと考えられています。 これは、価格が次の日に同じ方向に行くことを意味します。
次のパラメータは、適切なシンボルを検索するのに役立ちます。
sinput string delimeter_10=""; //---追加の高値 = 終値 タブ--- input ENUM_TIMEFRAMES highclose_period=PERIOD_D1; //期間 input int highclose_offset=0; //ポイントの高低オフセット
日の高値/安値を検索する場合, 価格は必ずしも極値点に直接閉じることはできません。 ボーダー価格から数またはダースポイントのロールバックする可能性があります。 [ポイントの高値/安値の誤差マージン] パラメータを使用すると、許容ロールバックをポイントで定義できます。
タブコードは次のとおりです。
if(CopyRates(addonName, highclose_period, 0, 1, rates)==1){ if( rates[0].close+highclose_offset >= rates[0].high ){ addonArr.Add(addonName); arrTT.Add(0); }else if( rates[0].close-highclose_offset <= rates[0].low ){ addonArr.Add(addonName); arrTT.Add(0); } }
カスタムタブの追加
もちろん、すべての可能なパターンを考慮していません。 MQL で他のパターンを使用し、プログラミングスキルがある場合は、ユーティリティに独自のタブを追加できます。 ぜひ、コメントでダウンして検索パターンの説明を使用して、独自のタブのコードを投稿してください。
上記のコードを改善するための提案も高く評価されています。
結論として、自身の自動ソートタブをユーティリティに追加する方法を提案してください。 これは、2つのステップで行われます。
最初に、新しいタブの名前をpanelNamesAddonタブ名の配列に追加します。 配列のサイズを1ずつ増やすことを忘れないでください。
第2に、 show_symbols関数のスイッチ演算子は、適用されたもの高値を1つ上回る新しいcaseを特徴とします。 現在のシンボルが条件に適合するかどうかをチェックするコードは、 case演算子の内部に実装されています。 コードテンプレートは次のとおりです。
case index: //タブ名 for( int i=0; i<tmpSymbols.Total(); i++ ){ addonName=tmpSymbols[i]; // check code } break;
結論
ユーティリティの機能をさらに拡張しました。 トレーダーにとって有用になると思っています。
この記事では、MQL4 と MQL5 の両方で動作するため、MQL 言語バージョンに応じてコードを書き換えていません。
ご覧のように、MQL でのクロスプラットフォームユーティリティの開発は大きな課題ではありません。 ほとんどの MQL5 関数は同様の方法で MQL4 でサポートされています。 したがって、MQL5 のあらゆる種類のクラスやその他のユニークな関数を一時的に忘れ、タスクをできるだけ多くのトレーダーが利用できるようにする価値があるかもしれません。
もちろん、クラスに対して宣戦布告はしません。 クラスはすでに MQL4 に存在し、コードベースに表示されます。 しばらくの間、MQL5 言語のこの機能を延期した方がいいかもしれません。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/5517
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索