Creating_My_Rules.mq5 を修正しました。
・H のみや L のみが複数あると検索がうまくできなかった部分ですが、1080行目辺りの InequalitySignResultToNum() の中で RL と RH を間違ってました。
誤 else if(L<=RL) structure[csNum].results[index][ohlc]= 正 else if(L<=RH) structure[csNum].results[index][ohlc]=
・また、検索全体に関しては、自作パターンの並び方の情報をチャート側の並び方の情報にコピーしていたのが原因でした。そもそもチャート側の並び方は陽線か陰線かだけでよかったのに必要のないことをやってそれが問題になってました。構造体に入れていた自作パターンの並び方の情報を削除して、それを配列に変更・それに関係する処理や名称を変更しました。
・上記修正で、自作パターンの例えば左端のローソク足を陽線・陰線と切り替えていった場合、以前は [陰線 = 陽線陰線どちらでも] になったりしましたが、[(陽線+陰線) =< 陽線陰線どちらでも] になりました。ただ、= になるのが普通ですが数が増えてくると =< になってしまいます。頭の中で?が出てきてしまって何も閃かないので使いながら原因探していきます。
ソースコードを下記に公開するので興味がある方はご自由にお使いください。
//+------------------------------------------------------------------+ //| Creating_My_Rules.mq5 | //| Copyright K.I. | //| https://keita-isuzu.hatenablog.com/ | //+------------------------------------------------------------------+ #property copyright "K.I." #property link "https://keita-isuzu.hatenablog.com/" #property version "1.06" #property description "サブウィンドウ表示" #property description "ローソク足のパターンを作成してチャートを検索します" #property indicator_separate_window #property indicator_buffers 0 #property indicator_plots 0 // 外部ファイル実行用 // ShellExecuteW については右を参照 https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew #import "shell32.dll" int ShellExecuteW(int hwnd,string operation,string file,string parameters,string directory,int showCmd); #import // 構造体 struct pattern_struct { int x; // x軸 double open; // y軸 open。自作パターンのときは int型を入れること。 double high; // y軸 high double low; // y軸 low double close; // y軸 close int results[190][4]; // 左側のローソク足と比較した結果を[0][OHLC]から順番に入れていく。[190][4] 1次元は最大190。2次元は0=open, 1=high, 2=low, 3=close }; pattern_struct pattern[20]; // 自作パターン用。構造体の限界は20で設定 pattern_struct chart[]; // メインチャート用。OnInit()でリサイズ。 // グローバル変数 long chart_id=0; // チャートID int sub_w=1; // サブウィンドウの番号 int csType[20]; // ローソク足の種類 0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ int patternNow=3; // 作成するパターンのローソク足の数 const int patternMin=2; // 作成するパターンのローソク足の最小値 const int patternMax=20; // 作成するパターンのローソク足の最大値 int mode=0; // 作業切り替えボタンの状態 char saveOHLC=-1; // OHLCのどれを選択しているか保存 int saveNum=-1; // クリックしたローソク足の番号 double saveChartShiftSize=0; // チャート右境界線の値の保存 datetime chartTime[]; // OnCalculateのtime[]のコピー int prefixLen=0; // Prefix の文字列の数 int signDrawing[]; // サインを描画するフラグ int signNow=0; // 今のサインの位置 int signMax=0; // 見つかったサインの総数 const int signMin=0; // 最小の数。0で固定 // フラグ bool mouseMoveFlag=false; // マウスの位置情報 取得フラグ bool saveCHART_AUTOSCROLL=false; // 起動時のチャートの自動スクロールの状態を保存 bool startValueFlag[]; // 比較処理のときパターンの先頭を判断するためのフラグ // マクロ代入 #define Prefix "MY_Rules_" // 描画オブジェクトプレフィックス #define csvName "Creating_My_Rules.csv" // CSVファイル名 #define csvName_bk "Creating_My_Rules_backup.csv" // CSVファイル名 // Z oeder マウスクリックの優先度 #define zorderLine 300 // 価格変更の水平線が最優先 #define zorderOHLC 200 // OHLCのラべル #define zorderCsRect 100 // ローソク足のクリック用のレクタングル #define zorderCsRect2 99 // ローソク足のクリック用のレクタングルが押されたとき #define zorderButton 100 // 全てのボタン // input設定 input int candlesToCalculate=10000; // 処理するローソク足の数(増やしすぎると時間軸によってはエラーになります) input group "" input color InpCsColorW=clrBlue; // 陽線の色 input color InpCsColorB=clrRed; // 陰線の色 input color InpCsColorHL=clrYellowGreen; // HLのみの色 input group "" input color InpLineColor=clrBeige; // 価格変更の水平線の色 input group "" input uchar InpSignArrowwCode=222; // 描画するサイン 矢印コード(上側) input uchar InpSignArrowwCode2=221; // 描画するサイン 矢印コード(下側) input color InpSignColor=clrPurple; // 描画するサイン 色 input int InpSignWidth=1; // 描画するサイン サイズ string InpFont="Arial Black"; // フォント種類 int InpFontsize=10; // フォントサイズ //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- 実行するチャートにサブウィンドがある場合、サブウィンドウの値を変更 string shortname="Creating_My_Rules"; // このインジケーターの短縮名(同じ名前のファイル等がなければ何でもいい) IndicatorSetString(INDICATOR_SHORTNAME,shortname); // 短縮名を設定 int window=GetIndicatorsub_windowNumber(chart_id,shortname); if(window!=-1) Print("Indicator "+shortname+" is in the window #"+(string)window); else Print("Indicator "+shortname+" is not found. window = "+(string)window); sub_w = window; // サブウィンドウの値の代入 //--- サブウィンドウの最大値と最小値を設定する IndicatorSetDouble(INDICATOR_MAXIMUM,400); // 400は適当。500や300でもいい。変更時はローソク足クリック用のレクタングルの値に注意。 IndicatorSetDouble(INDICATOR_MINIMUM,0); //--- 起動時のチャート画面の状態 // チャートの右境界線の値の保存 saveChartShiftSize=ChartShiftSizeGet(chart_id); // チャート自動スクロールの状態の保存 long value; if(ChartGetInteger(chart_id,CHART_AUTOSCROLL,0,value)) saveCHART_AUTOSCROLL=true; //--- 構造体・配列の初期化 StructReset(pattern,patternNow,0); // 処理するローソク足の数は patternNow StructReset(chart,candlesToCalculate,1); // 処理するローソク足の数は candlesToCalculate // 時刻 ArrayResize(chartTime,candlesToCalculate); // フラグのリサイズ ArrayResize(startValueFlag,candlesToCalculate); ArrayResize(signDrawing,candlesToCalculate); //--- Prefix の文字列の数を取得 prefixLen=StringLen(Prefix); //--- マウスのイベント無効 ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_w,false); //--- チャート画面移動の準備 // チャートの自動スクロールを無効 ChartSetInteger(chart_id,CHART_AUTOSCROLL,false); // チャートの右端のシフトを設定する ChartSetInteger(chart_id,CHART_SHIFT,true); // ローソク足を描画する ChartSetInteger(chart_id,CHART_MODE,CHART_CANDLES); // 初期化完了。ゼロ値を返す。 return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // 同じプレフィックスのオブジェクトをすべて削除(メインチャートのみ。サブウィンドウは勝手に削除される) ObjectsDeleteAll(chart_id,Prefix); // チャート右境界線の値を戻す ChartSetDouble(chart_id,CHART_SHIFT_SIZE,saveChartShiftSize); // 起動時チャートの自動スクロールが true だったら戻す if(saveCHART_AUTOSCROLL) ChartSetInteger(chart_id,CHART_AUTOSCROLL,true); // 再描画 ChartRedraw(); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, // 入力時系列のサイズ const int prev_calculated, // 以前の呼び出しで処理されたバー const datetime &time[], // 時間 const double &open[], // 始値 const double &high[], // 高値 const double &low[], // 安値 const double &close[], // 終値 const long &tick_volume[], // ティックボリューム const long &volume[], // ボリューム const int &spread[]) // スプレッド { // ローソク足が同じときは何もせずにreturn(rates_total)を返す if(rates_total==prev_calculated) return(rates_total); // 左側の情報の作成は初回のみ if(prev_calculated==0) { // 通貨ペア・時間足のラベル作成 Info(); //--- 初期画面の描画 // サブウィンドウに描画するローソク足の作成 CandlestickCreate(); // 画面下部のボタン設定・作成 LowerButton(); // 価格リセットボタン ButtonCreate(chart_id,Prefix+"Reset_Price_Button",sub_w,"価格リセット",100,230,80,20,clrBlack,clrWhite); // CSV読込ボタン作成 ButtonCreate(chart_id,Prefix+"File_Read",sub_w,"CSV読込",100,170,80,20,clrBlack,clrWhite); // ローソク足の数変更ボタン作成 ButtonCreate(chart_id,Prefix+"CSNum_Label",sub_w,"ローソク足増減",100,110,80,20,clrWhite,clrNONE); ButtonCreate(chart_id,Prefix+"CSNum_L",sub_w,"<-",100,80,20,20,clrBlack,clrWhite); ButtonCreate(chart_id,Prefix+"CSNum_R",sub_w,"->",40,80,20,20,clrBlack,clrWhite); LabelCreate(chart_id,Prefix+"CSNum",sub_w,(string)patternNow,CORNER_RIGHT_LOWER,60,70,ANCHOR_CENTER,InpFont,InpFontsize,clrWhite,false,0,0); // モード切替ボタン作成 ButtonCreate(chart_id,Prefix+"Mode_Button",sub_w,"陰陽 変更",100,30,80,20,clrBlack,clrWhite); } // 時系列に変更 ArraySetAsSeries(open,true); ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArraySetAsSeries(close,true); ArraySetAsSeries(time,true); // チャートの価格を構造体 chart にコピー。時間を配列にコピー。 for(int i=0; i<candlesToCalculate; i++) { chart[i].open = open[i]; chart[i].high = high[i]; chart[i].low = low[i]; chart[i].close = close[i]; chartTime[i] = time[i]; } // 次の呼び出しのために prev_calculated の値を返す return(rates_total); } //+------------------------------------------------------------------+ //| ChartEvent 関数 | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- グラフィックオブジェクトのクリック if(id==CHARTEVENT_OBJECT_CLICK) { // Print("クリックしたオブジェクト名 '"+sparam+"'"); // テスト用。残しておく。 //--- 右下のモード切り替えボタンを押したとき if(sparam == Prefix+"Mode_Button") { OperationalModesChange(sparam); // 操作モードの変更 return; } switch(mode) { case 0: Candlestick_WB_ModificationMode(sparam,dparam); return; // 陰線・陽線の変更 case 1: SearchForPatternMode(sparam); return; // ローソク足の検索・チェック } return; } //--- マウス移動イベント if(id==CHARTEVENT_MOUSE_MOVE) { // printf("マウスの位置 : x=%d, y=%d", (int)lparam, (int)dparam); // テスト用。残しておく。 if((mode==0) && (mouseMoveFlag==true)) { datetime time_x; // ChartXYToTimePrice を使用するのに必要。取得したx軸の値は使わない。 double price_y; // 価格をY軸に変更 // 価格からy軸に変更 ChartXYToTimePrice(chart_id,(int)lparam,(int)dparam,sub_w,time_x,price_y); // 水平線描画 Y軸(価格)を渡す LineCreate(chart_id,Prefix+"Line",sub_w,price_y); return; } return; } } //+------------------------------------------------------------------+ //| 操作モード変更 //+------------------------------------------------------------------+ void OperationalModesChange(const string sparam) { switch(mode) { case 0: // 今[陰陽変更]で、これから[検索] //--- 操作モード切替 mode=1; //--- オブジェクトの削除 ObjectsDeleteAll(chart_id,Prefix+"CSNum",sub_w); // ローソク足の数変更ボタンの削除 ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w); // OHLCを削除 ObjectDelete(chart_id,Prefix+"File_Read"); // CSV読込ボタン削除 //--- パターンを検索 SearchForStartValue(); SearchForPattern(); // パターン移動の数が、見つかったパターン数より大きいとき if(signNow > signMax) signNow=signMax; //--- オブジェクトの変更 ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"検索"); ButtonCreate(chart_id,Prefix+"Do_SS_Button",sub_w,"スクリーンショット",100,230,80,20,clrBlack,clrWhite); // スクリーンショットボタン ButtonCreate(chart_id,Prefix+"File_Write",sub_w,"CSV保存",100,200,80,20,clrBlack,clrWhite); // CSVファイル保存ボタン // チャート移動ボタン ButtonCreate(chart_id,Prefix+"Sign_Label",sub_w,"チャート移動",100,110,80,20,clrWhite,clrNONE); ButtonCreate(chart_id,Prefix+"Sign_L",sub_w,"<-",100,80,20,20,clrBlack,clrWhite); ButtonCreate(chart_id,Prefix+"Sign_R",sub_w,"->",40,80,20,20,clrBlack,clrWhite); LabelCreate(chart_id,Prefix+"Sign_Num",sub_w,(string)signNow,CORNER_RIGHT_LOWER,60,70,ANCHOR_CENTER,InpFont,InpFontsize,clrWhite,false,0,0); // 画面下部のボタン LowerButton(); // メインチャートに描画 ArrowCreate(chart_id,Prefix+"Sign_",sub_w,chart,chartTime,InpSignArrowwCode,InpSignArrowwCode2,InpSignColor,InpSignWidth); return; case 1: // 今[検索]で、これから[陰陽変更] //--- 操作モード切替 mode=0; //--- オブジェクトの削除 ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w); ObjectDelete(chart_id,Prefix+"Reset_Price_Button"); // 価格リセットボタンの削除 ObjectsDeleteAll(chart_id,Prefix+"Do_",sub_w); // Prefix+"Do_" で始まるオブジェクトを削除 ObjectsDeleteAll(chart_id,Prefix+"Sign_",sub_w); // パターン該当数削除 ObjectDelete(chart_id,Prefix+"File_Write"); // CSV保存ボタン削除 //--- オブジェクトの変更 ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"陰陽 変更"); //--- オブジェクトの作成 LowerButton(); // 価格リセットボタン ButtonCreate(chart_id,Prefix+"Reset_Price_Button",sub_w,"価格リセット",100,230,80,20,clrBlack,clrWhite); // ローソク足の数変更ボタン ButtonCreate(chart_id,Prefix+"CSNum_Label",sub_w,"ローソク足増減",100,110,80,20,clrWhite,clrNONE); ButtonCreate(chart_id,Prefix+"CSNum_L",sub_w,"<-",100,80,20,20,clrBlack,clrWhite); ButtonCreate(chart_id,Prefix+"CSNum_R",sub_w,"->",40,80,20,20,clrBlack,clrWhite); // CSV読込ボタン作成 ButtonCreate(chart_id,Prefix+"File_Read",sub_w,"CSV読込",100,170,80,20,clrBlack,clrWhite); // ローソク足の本数表示 LabelCreate(chart_id,Prefix+"CSNum",sub_w,(string)patternNow,CORNER_RIGHT_LOWER,60,70,ANCHOR_CENTER,InpFont,InpFontsize,clrWhite,false,0,0); return; } } //+------------------------------------------------------------------+ //| ローソク足の陽線・陰線変更モードの画面 //+------------------------------------------------------------------+ void Candlestick_WB_ModificationMode(const string sparam, const double &dparam) { int find=-1; // 指定する文字列が見つかったら整数が入る変数 //--- オブジェクトがあってボタンが押されたとき、押されていない状態に戻す( 押されるtrue / 押されていないfalse) find=ObjectFind(chart_id,sparam); if(find>0) { ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false); ChartRedraw(); } //--- 画面下部のボタンを押したとき find=StringFind(sparam,"Lower_Button_",prefixLen); // Prefix の後ろから "Lower_Button_" を探す if(find>0) { // 何番目のローソク足か確認 string str=StringSubstr(sparam,prefixLen+13); // Prefix + "Lower_Button_" の後ろの文字列を全部取り出す int num=(int)StringToInteger(str); // 文字列の数字をlongに変換してintに変換 csTypeChange(num); // ローソク足の種類の変更 // オブジェクト削除 ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w); // OHLC オブジェクトを削除 CandlestickCreate(); // サブウィンドウに描画するローソク足の作成 LowerButton(); // 画面下部のボタン作成 SearchForStartValue(); // 開始位置の検索 SearchForPattern(); // パターン検索 return; } //--- [<-][->]ボタンを押したとき if(sparam == Prefix+"CSNum_L") // [<]ボタン { // ローソク足の本数を増やす if(patternNow<patternMax) patternNow++; // 陽線・陰線情報変更 csType[patternNow-1]=1; // ラベルのテキスト更新 ObjectSetString(chart_id,Prefix+"CSNum",OBJPROP_TEXT,(string)patternNow); // オブジェクト削除 ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w); // OHLC オブジェクトを削除 CandlestickCreate(); // ローソク足の描画 LowerButton(); // 画面下部のボタン作成 SearchForStartValue(); // 開始位置の検索 SearchForPattern(); // パターン検索 return; } if(sparam == Prefix+"CSNum_R") // [>]ボタン { // ローソク足の本数を減らす if(patternNow>patternMin) patternNow--; // 陽線・陰線情報変更 csType[patternNow]=0; // ラベルのテキスト更新 ObjectSetString(chart_id,Prefix+"CSNum",OBJPROP_TEXT,(string)patternNow); // オブジェクト削除・描画 ObjectsDeleteAll(chart_id,Prefix+"CS_",sub_w); // 名前に Prefix+"CS_" があるオブジェクトを全部削除 ObjectsDeleteAll(chart_id,Prefix+"Lower_Button_",sub_w); // 名前に Prefix+"Lower_Button_" があるオブジェクトを全部削除 ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w); // OHLC オブジェクトを削除 CandlestickCreate(); // ローソク足の描画 LowerButton(); // 画面下部のボタン作成 SearchForStartValue(); // 開始位置の検索 SearchForPattern(); // パターン検索 return; } // [CSV読込]ボタンを押したとき if(sparam == Prefix+"File_Read") { // ファイルの読込 CsvFileRead(); //--- 再描画・再設定 // 未使用のローソク足の確認 for(int i=0; i<patternMax; i++) { if(csType[i]==0) { patternNow=i; break; } } // オブジェクトの削除と描画 ObjectsDeleteAll(chart_id,Prefix+"CS_",sub_w); // 名前に Prefix+"CS_Body_" があるオブジェクトを全部削除 ObjectsDeleteAll(chart_id,Prefix+"Lower_Button_",sub_w); // 名前に Prefix+"Lower_Button_" があるオブジェクトを全部削除 ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w); // OHLC オブジェクトを削除 CandlestickCreate(); // ローソク足の再描画 LowerButton(); // 画面下部のボタン作成 SearchForStartValue(); // 開始位置の検索 SearchForPattern(); // パターン検索 // ローソク足本数ラベルのテキスト更新 ObjectSetString(chart_id,Prefix+"CSNum",OBJPROP_TEXT,(string)patternNow); return; } //--- [価格リセット]ボタンを押したとき if(sparam == Prefix+"Reset_Price_Button") { // 価格のみを初期化 StructReset(pattern,patternMax,10); // オブジェクト削除 ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w); // OHLC オブジェクトを削除 ObjectsDeleteAll(chart_id,Prefix+"Pattern_Time",sub_w); // パターン該当数を削除 // ローソク足の削除・再描画 ObjectsDeleteAll(chart_id,Prefix+"CS_",sub_w); // 名前に Prefix+"CS_Body_" があるオブジェクトを全部削除 CandlestickCreate(); // サブウィンドウに描画するローソク足の作成 return; } //--- ローソク足をクリックしたとき(透明のレクタングルをクリック) find=StringFind(sparam,"CS_Rect_",prefixLen); // prefixLen の後ろから "CS_Rect_" を探す if(find>0) { // ローソク足の番号取得 string str=StringSubstr(sparam,prefixLen+8); // prefixLen+"CS_Rect_" の後ろから文字列を全部取り出す int num=(int)StringToInteger(str); // 文字列の数字をlongに変換してintに変換 saveNum=num; // クリックしたローソク足の番号を保存 // OHLC が表示されていなかったら表示、されていたら削除。OHLCは名前が4種類あるので、レクタングルのOBJPROP_ZORDERの値を利用して判断。 long zorder = ObjectGetInteger(chart_id,sparam,OBJPROP_ZORDER); // z_order の値を取得 if(zorder==zorderCsRect) // zorder が通常の値なら { OhlcLabelCreate(saveNum); // OHLC 描画 ObjectSetInteger(chart_id,sparam,OBJPROP_ZORDER,zorderCsRect2); // z_order を押されたときの値に設定 } else { ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w); // オブジェクトを削除 ObjectSetInteger(chart_id,sparam,OBJPROP_ZORDER,zorderCsRect); // z_order を通常の値に設定 } ChartRedraw(); // 再描画 return; } //--- ローソク足右側の OHLC を押したとき find=-1; find=StringFind(sparam,"OHLC_",prefixLen); // prefixLen の後ろから OHLC_ を探す if(find>0) { // OHLC のどれを押したか string strOHLC=StringSubstr(sparam,prefixLen+5,1); // prefixLen+"OHLC_" の後ろから文字列を1文字取り出す // 文字列をキャラに変換 saveOHLC=StrToChar(strOHLC); // OHLCの選んだ文字を残して他を消す(何番目のローソク足か, 残したい文字) OhlcLabelDelete(saveNum,saveOHLC); // マウスに追尾するラインを作成 if(!mouseMoveFlag) { ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_w,true); mouseMoveFlag=true; } return; } //--- 価格変更の水平線をクリックしたとき if(sparam == Prefix+"Line") { // 指標サブウィンドウの上部フレームとメインチャートウィンドウの上部フレームとの縦 Y 軸の差(ピクセル単位) long result=-1; //--- プロパティ値を受け取る ChartGetInteger(chart_id,CHART_WINDOW_YDISTANCE,sub_w,result); // チャートの高さ(ピクセル単位) long result2=-1; //--- プロパティ値を受け取る ChartGetInteger(chart_id,CHART_HEIGHT_IN_PIXELS,sub_w,result2); // 価格の変更と、OHLC の位置の確認。反転していれば同じ値にする switch(saveOHLC) { case 'O': pattern[saveNum].open=(int)(result2-(dparam-result)); if((csType[saveNum]<10 && pattern[saveNum].open > pattern[saveNum].close) || // 陽線なのに始値が終値より上 又は (csType[saveNum]>10 && csType[saveNum]<20 && pattern[saveNum].open < pattern[saveNum].close)) // 陰線なのに始値が終値より下 pattern[saveNum].close = pattern[saveNum].open; break; case 'H': pattern[saveNum].high=(int)(result2-(dparam-result)); if(pattern[saveNum].high < pattern[saveNum].low) // 高値が安値より下だったら pattern[saveNum].low = pattern[saveNum].high; break; case 'L': pattern[saveNum].low=(int)(result2-(dparam-result)); if(pattern[saveNum].high < pattern[saveNum].low) // 高値が安値より下だったら pattern[saveNum].high = pattern[saveNum].low; break; case 'C': pattern[saveNum].close=(int)(result2-(dparam-result)); if((csType[saveNum]<10 && pattern[saveNum].open > pattern[saveNum].close) || // 陽線なのに始値が終値より上 又は (csType[saveNum]>10 && csType[saveNum]<20 && pattern[saveNum].open < pattern[saveNum].close)) // 陰線なのに始値が終値より下 pattern[saveNum].open = pattern[saveNum].close; break; } // 水平線削除 ObjectDelete(chart_id,Prefix+"Line"); // ローソク足の描画 CandlestickCreate(); // OHLC の描画 OhlcLabelCreate(saveNum); // マウスに追尾するラインの停止 ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_w,false); mouseMoveFlag=false; // 価格を変更するたびにパターンを探す SearchForPattern(); return; } } //+------------------------------------------------------------------+ //| 検索モードの画面 //+------------------------------------------------------------------+ void SearchForPatternMode(const string sparam) { int find=-1; // 指定する文字列が見つかったら整数が入る変数 //--- オブジェクトがあってボタンが押されたとき、押されていない状態に戻す( 押されるtrue / 押されていないfalse) find=ObjectFind(chart_id,sparam); if(find>0) { ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false); ChartRedraw(); } //--- [スクリーンショット]ボタンが押されたら if(sparam == Prefix+"Do_SS_Button") { // スクリーンショット保存 ScreenShot(); return; } //--- [保存]ボタンが押されたら if(sparam == Prefix+"File_Write") { // ファイルの作成 CsvFileWrite(); return; } //--- [<-][->]ボタンが押されたら if(sparam == Prefix+"Sign_L") // [<]ボタン { // 表示するローソク足の位置番号を増やす if(signNow<signMax) signNow++; // 表示するローソク足のテキスト更新 ObjectSetString(chart_id,Prefix+"Sign_Num",OBJPROP_TEXT,(string)signNow); // 画面移動 ChartMove(signNow); return; } if(sparam == Prefix+"Sign_R") // [>]ボタン { // 表示するローソク足の位置番号を減らす if(signNow>signMin) signNow--; // 表示するローソク足のテキスト更新 ObjectSetString(chart_id,Prefix+"Sign_Num",OBJPROP_TEXT,(string)signNow); // 画面移動 ChartMove(signNow); return; } } //+------------------------------------------------------------------+ //| 開始位置の検索 //+------------------------------------------------------------------+ int SearchForStartValue() { //--- 初期化が必要なもの // フラグの配列を初期化 ArrayInitialize(startValueFlag,false); //--- 自作パターンの陽線・陰線の並びと、チャート価格の陽線・陰線の並びが同じなら .status を上書き // csType 0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ for(int i=1, k=0; i<candlesToCalculate-patternNow; i++) { // 陽線・陰線の並び方が同じか確認 for(int j=0; j<patternNow; j++) { if(((chart[i+j].open<chart[i+j].close) && (csType[j]>0) && (csType[j]<10)) || // チャート陽線でパターン陽線 又は ((chart[i+j].open>chart[i+j].close) && (csType[j]>10) && (csType[j]<20)) || // チャート陰線でパターン陰線 又は ((csType[j]>20) && (csType[j]<30))) // 陽線・陰線どちらも可 { k++; continue; } break; // 該当無しはjループ終了 } // 陽線・陰線の並び方が同じなら、パターンの開始位置のフラグを立てる if(k==patternNow) startValueFlag[i]=true; // カウンタリセット k=0; } return(0); } //+------------------------------------------------------------------+ //| パターンを検索 //+------------------------------------------------------------------+ int SearchForPattern() { //--- 初期化が必要なもの // フラグの配列を初期化 ArrayInitialize(signDrawing,0); // 比較結果を入れる構造体.results[][] を初期化 StructReset(pattern,patternMax,20); StructReset(chart,candlesToCalculate,20); //--- ① 自作パターンの不等号の比較結果の保存 startValueFlag[0]=true; // [0]は自作パターンでのみ使用。[0]=trueにしないと次の関数で処理されない。 InequalitySignResultToNum(0, 1, pattern); //--- ② チャート側の不等号の比較結果の保存(未確定の足は除くので1を渡す。(candlesToCalculate - 自作パターン数) をチェック) InequalitySignResultToNum(1, candlesToCalculate-patternNow, chart); //--- ③ 自作パターンとチャートの比較結果の比較 // 自作パターンの比較の組み合わせの数がいくつになるか計算 int compareNow=0; // 比較の組み合わせの数 for(int i=patternNow; i>=patternMin; i--) compareNow = compareNow+i-1; // 比較の比較 for(int i=1; i<candlesToCalculate-patternNow; i++) // i はチャートのローソク足の番号。未確定の足は除くので1から始める。 { for(int k=0; k<compareNow; k++) // k は比較の組み合わせの数の位置 { if(!((chart[i].results[k][0] == pattern[0].results[k][0]) && (chart[i].results[k][1] == pattern[0].results[k][1]) && (chart[i].results[k][2] == pattern[0].results[k][2]) && (chart[i].results[k][3] == pattern[0].results[k][3]))) { break; // 同じではないとき k ループ終了 } // チャートと自作パターンが同じだったら該当するローソク足の番号のフラグを立てる if(k==compareNow-1) { for(int j=0; j<patternNow; j++) { if(j==0) signDrawing[j+i]=2; // パターンの開始位置のみ 2 else signDrawing[j+i]=1; // それ以外は 1 } } } } //--- ④ 最大描画数の取得・確認表示 for(int i=0, j=0; i<candlesToCalculate; i++) { if(signDrawing[i]==2) j++; if(i==candlesToCalculate-1) { signMax=j; // 見つかったサインの総数 // 左下に表示 LabelCreate(chart_id,Prefix+"Pattern_Time",sub_w,"パターン該当数",CORNER_LEFT_UPPER, 70, 200, ANCHOR_CENTER, InpFont, InpFontsize, clrWhite,false,0,0); LabelCreate(chart_id,Prefix+"Pattern_Time2",sub_w,(string)signMax,CORNER_LEFT_UPPER, 70, 220, ANCHOR_CENTER, InpFont, InpFontsize, clrWhite,false,0,0); ChartRedraw(); break; } } return(0); } //+------------------------------------------------------------------+ //| ローソク足の比較の結果を数字に変換する //+------------------------------------------------------------------+ void InequalitySignResultToNum(int start, // 処理を開始するローソク足の番号 int end, // 処理を終了するローソク足の番号 pattern_struct &structure[]) // 価格の取り出しと、比較結果を入れる構造体 { // 比較結果の位置番号は [csNum]。structure[csNum].results[index][ohlc] に比較結果を入れる。 // R側のローソク足の位置番号は [i+csNum]。 // L側のローソク足の位置番号は [j+csNum]。 // LRの比較する位置番号は左上が直角二等辺三角形の逆ピラミッド型になる。 for(int csNum=start; csNum<end; csNum++) // 処理するローソク足のループ。csNum は処理するローソク足の番号 { if(startValueFlag[csNum]) // パターンの開始位置フラグが true なら { for(int i=0, index=0; i<patternNow; i++) // [i] はカウンタとして使用。処理するローソク足は [i+csNum] { for(int j=i+1; j<patternNow; j++) // j はL側の位置番号。L側のローソク足は [j+csNum] { // ohlc の比較・結果の保存 for(int ohlc=0; ohlc<4; ohlc++) { char type='A'; // 計算式の種類 bool SwapTheLR=false; // LRを入れ替える double L=0; // L側の値 double RO=0, RH=0, RL=0, RC=0; // R側の値 // csType[j]=L側, csType[i]=R側 0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ // L側を確認したあとR側を確認 switch(csType[j]) { //--- L OHLCのとき case 1: case 11: switch(csType[i]) { // R OHLC -> LRそのまま case 1: case 11: switch(ohlc) { case 0: L=structure[j+csNum].open; break; case 1: L=structure[j+csNum].high; break; case 2: L=structure[j+csNum].low; break; case 3: L=structure[j+csNum].close; break; } SwapTheLR=false; type='A'; break; // R HL -> LR入替 case 2: case 12: case 22: switch(ohlc) { case 0: case 3: structure[csNum].results[index][ohlc]=0; continue; // int ohlc のループへ戻る case 1: L=structure[i+csNum].high; break; case 2: L=structure[i+csNum].low; break; } SwapTheLR=true; type='A'; break; // High -> LR入替 case 3: case 13: case 23: switch(ohlc) { case 0: case 2: case 3: structure[csNum].results[index][ohlc]=0; continue; case 1: L=structure[i+csNum].high; break; } SwapTheLR=true; type='A'; break; // Low -> LR入替 case 4: case 14: case 24: switch(ohlc) { case 0: case 1: case 3: structure[csNum].results[index][ohlc]=0; continue; case 2: L=structure[i+csNum].low; break; } SwapTheLR=true; type='A'; break; } break; //--- L HLのとき case 2: case 12: case 22: switch(csType[i]) { // R OHLC -> LRそのまま case 1: case 11: // R HL -> LRそのまま case 2: case 12: case 22: switch(ohlc) { case 0: case 3: structure[csNum].results[index][ohlc]=0; continue; case 1: L=structure[j+csNum].high; break; case 2: L=structure[j+csNum].low; break; } SwapTheLR=false; if(csType[i]==1 || csType[i]==11) type='A'; else type='B'; break; // High -> LR入替 case 3: case 13: case 23: switch(ohlc) { case 0: case 2: case 3: structure[csNum].results[index][ohlc]=0; continue; case 1: L=structure[i+csNum].high; break; } SwapTheLR=true; type='C'; break; // Low -> LR入替 case 4: case 14: case 24: switch(ohlc) { case 0: case 1: case 3: structure[csNum].results[index][ohlc]=0; continue; case 2: L=structure[i+csNum].low; break; } SwapTheLR=true; type='D'; break; } break; //--- L Highのみ case 3: case 13: case 23: switch(ohlc) { case 0: case 2: case 3: structure[csNum].results[index][ohlc]=0; continue; case 1: L=structure[j+csNum].high; break; } SwapTheLR=false; switch(csType[i]) { // R OHLC -> LRそのまま case 1: case 11: type='A'; break; // R HL -> LRそのまま case 2: case 12: case 22: type='B'; break; // High -> LRそのまま case 3: case 13: case 23: type='C'; break; // Low -> LRそのまま case 4: case 14: case 24: type='D'; break; } break; //--- L Lowのみ case 4: case 14: case 24: switch(ohlc) { case 0: case 1: case 3: structure[csNum].results[index][ohlc]=0; continue; case 2: L=structure[j+csNum].low; break; } SwapTheLR=false; switch(csType[i]) { // R OHLC -> LRそのまま case 1: case 11: type='A'; break; // R HL -> LRそのまま case 2: case 12: case 22: type='B'; break; // High -> LRそのまま case 3: case 13: case 23: type='C'; break; // Low -> LRそのまま case 4: case 14: case 24: type='D'; break; } break; } // OHLC 入替 if(SwapTheLR) { // 入替 RO=structure[j+csNum].open; RH=structure[j+csNum].high; RL=structure[j+csNum].low; RC=structure[j+csNum].close; } else { // そのまま RO=structure[i+csNum].open; RH=structure[i+csNum].high; RL=structure[i+csNum].low; RC=structure[i+csNum].close; } //--- 不等号で比較 // structure[csNum]は処理を開始した番号で固定。[index]はohlcループの後にindex++する。 switch(type) { case 'A': // OHLCのとき if(L>=RH) structure[csNum].results[index][ohlc]=1; // high 以上 else if(L<=RH && L>=RO) structure[csNum].results[index][ohlc]=2; // high 以下, open 以上 else if(L<=RO && L>=RC) structure[csNum].results[index][ohlc]=3; // open 以下, close 以上 else if(L<=RC && L>=RL) structure[csNum].results[index][ohlc]=4; // close 以下, low 以上 else if(L<=RL) structure[csNum].results[index][ohlc]=5; // low 以下 break; case 'B': // HLのとき if(L>=RH) structure[csNum].results[index][ohlc]=11; // high 以上 else if(L<=RH && L>=RL) structure[csNum].results[index][ohlc]=12; // high 以下, low 以上 else if(L<=RL) structure[csNum].results[index][ohlc]=13; // low 以下 break; case 'C': // Hのみ if(L>=RH) structure[csNum].results[index][ohlc]=21; // high 以上 else if(L<=RH) structure[csNum].results[index][ohlc]=22; // high 以下 break; case 'D': // Lのみ if(L>=RL) structure[csNum].results[index][ohlc]=31; // low 以上 else if(L<=RL) structure[csNum].results[index][ohlc]=32; // low 以下 break; } } // ここまでが int ohlc のループ index++; // int ohlcのループが終わったら保存場所を一つずらす } } } } } //+------------------------------------------------------------------+ //| ローソク足の種類の変更 //| csType[] 0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ //+------------------------------------------------------------------+ void csTypeChange(int num) // ローソク足の位置番号 { if(csType[num]==4 || csType[num]==14) { if(csType[num]==4) csType[num]=11; // 4 の次は 11 else csType[num]=22; // 14 の次は 22 // 始値・終値の入替 double temp=0; temp=pattern[num].open; pattern[num].open=pattern[num].close; pattern[num].close=temp; return; } else if(csType[num]==24) // 24 の次は 1 { csType[num]=1; return; } else csType[num]++; } //+------------------------------------------------------------------+ //| ローソク足を描画 //+------------------------------------------------------------------+ void CandlestickCreate() { double y; int width=10; // 幅(x軸) double height; // 高さ(y軸) color clr; for(int i=0; i<patternNow; i++) { //--- 色の設定 if(csType[i]<10) clr=InpCsColorW; // 10 より下なら陽線 else if(csType[i]<20) clr=InpCsColorB; // 20 より下なら陰線 else clr=InpCsColorHL; // それ以外はどちらでも可 //--- 実体 string name = Prefix+"CS_Body_"+IntegerToString(i); // 実体の名前 // 陽線OHLC・陰線OHLCのとき実体を描画 if(csType[i]==1 || csType[i]==11) { // 始値と終値の位置変更 if(csType[i]==11) // 陰線OHLC { y = pattern[i].open; // y(価格軸、ピクセル) height = pattern[i].open - pattern[i].close; // y(ラベルの高さ) } else // 陽線OHLC { y = pattern[i].close; // y(価格軸、ピクセル) height = pattern[i].close - pattern[i].open; // y(ラベルの高さ) } // 実体描画 RectLabelCreate(chart_id,name,sub_w,pattern[i].x+width,(int)y,width,(int)height,clr,BORDER_FLAT,CORNER_RIGHT_LOWER,clr,STYLE_SOLID,1,true,false,true,0); } else ObjectDelete(chart_id,name); // OHLC以外なら実体のオブジェクト削除 //--- ヒゲ string name2 = Prefix+"CS_Shadow_"+IntegerToString(i); // ヒゲの名前 // HL と H(L) で表示を変える if((csType[i]==3 || csType[i]==4) || (csType[i]==13 || csType[i]==14) || (csType[i]==23 || csType[i]==24)) { height = 30; // ラベルの高さ // H か L か if(csType[i]==3 || csType[i]==13 || csType[i]==23) // high { y = pattern[i].high; // y(価格軸、ピクセル) // ラベル作成 LabelCreate(chart_id,name2+"_Char",sub_w,"H",CORNER_RIGHT_LOWER,pattern[i].x+10,(int)y-30,ANCHOR_LEFT_UPPER,InpFont,12,clrWhite,true,0,0); // 最後の true は背景表示にする } else // low { y = pattern[i].low+30; // ラベルの高さ分上にずらす(プラスする) // ラベル作成 yは30+文字の大きさ。適当。 LabelCreate(chart_id,name2+"_Char",sub_w,"L",CORNER_RIGHT_LOWER,pattern[i].x+10,(int)y+30,ANCHOR_LEFT_UPPER,InpFont,12,clrWhite,true,0,0); // 最後の true は背景表示にする } } else { ObjectDelete(chart_id,name2+"_Char"); // H・Lの文字のオブジェクト削除 y = pattern[i].high; // y(価格軸、ピクセル) height = pattern[i].high - pattern[i].low; // ラベルの高さ } // ヒゲ描画 RectLabelCreate(chart_id,name2,sub_w,pattern[i].x+(width/2),(int)y,2,(int)height,clr,BORDER_FLAT,CORNER_RIGHT_LOWER,clr,STYLE_SOLID,1,true,false,true,0); //--- マウスクリック用のレクタングル string name3 = Prefix+"CS_Rect_"+IntegerToString(i); // 透明のレクタングルの名前 clr = clrNONE; // 色無し // 400-51 -> サブウインドゥの高さ - 画面下部のボタンの大きさ RectLabelCreate(chart_id,name3,sub_w,pattern[i].x+width,400,width,400-51,clr,BORDER_FLAT,CORNER_RIGHT_LOWER,clr,STYLE_SOLID,1,false,false,true,zorderCsRect); } //--- チャートを再描画 ChartRedraw(); } //+------------------------------------------------------------------+ //| 四角形ラベルを作成する //+------------------------------------------------------------------+ bool RectLabelCreate(const long chart_ID, // チャート識別子 const string name, // ラベル名 const int sub_window, // サブウィンドウ番号 const int x, // X 座標 const int y, // Y 座標 const int width, // 幅 const int height, // 高さ const color back_clr, // 背景色 const ENUM_BORDER_TYPE border, // 境界線の種類 const ENUM_BASE_CORNER corner, // アンカーに使用されるチャートのコーナー const color clr, // フラット境界線の色 (Flat) const ENUM_LINE_STYLE style=STYLE_SOLID, // フラット境界スタイル const int line_width=1, // フラット境界幅 const bool back=false, // 背景で表示する const bool selection=false, // 強調表示して移動 const bool hidden=true, // オブジェクトリストに隠す const long z_order=0) // マウスクリックの優先順位 { //--- エラー値をリセットする ResetLastError(); //--- 四角形ラベルを作成する if(!ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0)) { Print(__FUNCTION__,": failed to create a rectangle label! Error code = ",GetLastError()); return(false); } ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); // ラベル座標を設定する ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width); // ラベルサイズを設定する ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height); ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr); // 背景色を設定する ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border); // 境界線を設定する ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner); // ポイント座標が相対的に定義されているチャートのコーナーを設定 ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); // フラット境界線色を設定する(Flat モード) ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style); // フラット境界線スタイルを設定する ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width); // フラット境界線幅を設定する ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); // 前景(false)または背景(true)に表示 ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection); // マウスでラベルを移動させるモードを有効(true)か無効(false)にする ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection); ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden); // オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order); // チャートのマウスクリックのイベントを受信するための優先順位を設定する // 再描画 ChartRedraw(0); return(true); } //+------------------------------------------------------------------+ //| OHLC ラベルを削除する //+------------------------------------------------------------------+ void OhlcLabelDelete(int num, char ohlc_char) // ローソク足の番号, 残したい文字 { for(int i=0; i<4; i++) { // 残したい文字のときは continue。それ以外は break で次へすすむ。 switch(ohlc_char) { case 'O': if(i==0) continue; break; case 'H': if(i==1) continue; break; case 'L': if(i==2) continue; break; case 'C': if(i==3) continue; break; } string name; // オブジェクト名 switch(i) { case 0: name=Prefix+"OHLC_O_"+IntegerToString(num); break; case 1: name=Prefix+"OHLC_H_"+IntegerToString(num); break; case 2: name=Prefix+"OHLC_L_"+IntegerToString(num); break; case 3: name=Prefix+"OHLC_C_"+IntegerToString(num); break; } ObjectDelete(chart_id,name); } ChartRedraw(); } //+------------------------------------------------------------------+ //| OHLC ラベルを作成する //+------------------------------------------------------------------+ void OhlcLabelCreate(int num) // ローソク足の番号 { ObjectsDeleteAll(chart_id,Prefix+"OHLC_"); // OHLCラベルを全削除 string text; // 表示するテキスト string name; // オブジェクト名 // y (高さ)を設定 int y = (int)(pattern[num].high-(pattern[num].high-pattern[num].low)/2)+40; for(int i=0; i<4; i++) { // 表示しないものは continue。それ以外は次へ。 switch(csType[num]) { // HLのとき、open・closeはcontinue case 2: case 12: case 22: if(i==1 || i==2) continue; break; // Hのみのとき、high以外はcontinue case 3: case 13: case 23: if(i!=0) continue; break; // Lのみのとき、low以外はcontinue case 4: case 14: case 24: if(i!=3) continue; break; } // 陰線のときの名称 if(csType[num]>10 && csType[num]<20) switch(i) { case 0: text="H"; name=Prefix+"OHLC_H_"+IntegerToString(num); break; case 1: text="O"; name=Prefix+"OHLC_O_"+IntegerToString(num); break; case 2: text="C"; name=Prefix+"OHLC_C_"+IntegerToString(num); break; case 3: text="L"; name=Prefix+"OHLC_L_"+IntegerToString(num); break; } // 陰線以外の名称 else switch(i) { case 0: text="H"; name=Prefix+"OHLC_H_"+IntegerToString(num); break; case 1: text="C"; name=Prefix+"OHLC_C_"+IntegerToString(num); break; case 2: text="O"; name=Prefix+"OHLC_O_"+IntegerToString(num); break; case 3: text="L"; name=Prefix+"OHLC_L_"+IntegerToString(num); break; } // ラベルの作成 LabelCreate(chart_id,name,sub_w,text,CORNER_RIGHT_LOWER,pattern[num].x-10,y-(i*20),ANCHOR_LEFT_UPPER,InpFont,InpFontsize,clrWhite,false,zorderOHLC,0); } //--- チャートを再描画 ChartRedraw(); } //+------------------------------------------------------------------+ //| ラベル作成 //+------------------------------------------------------------------+ bool LabelCreate(const long chart_ID, // チャート識別子 string name, // オブジェクト名 const int sub_window, // サブウィンドウ番号 string text, // 表示するテキスト ENUM_BASE_CORNER corner, // チャートの四隅の指定 int xshift, // OBJPROP_CORNERからの距離(横) int yshift, // OBJPROP_CORNERからの距離(縦) int anchor, // アンカーの位置 string font, // フォントの種類 int fontSize, // フォントのサイズ color fontColor, // フォントの色 bool back=false, // 背景表示 const long z_order=0, // マウスクリックの優先順位 double angle=0) // 角度 { ResetLastError(); // エラー値をリセットする if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)) // ラベルを作成する { Print(__FUNCTION__,": failed to create the button! Error code = ",GetLastError()); return(false); } ObjectSetString( chart_ID,name,OBJPROP_TEXT,text); // テキスト ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner); // チャートの基準点 ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,xshift); // x軸(ピクセル) ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,yshift); // y軸(ピクセル) ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor); // アンカーの種類を設定 ObjectSetString(chart_ID,name,OBJPROP_FONT,font); // フォントを設定する ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,fontSize); // フォントサイズを設定する ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,fontColor); // テキストの色を設定する ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); // 前景(false)または背景(true)に表示 ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,false); // マウスでのボタンを移動させるモードを有効(true)か無効(false)にする ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,false); ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,true); // オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order); // チャートのマウスクリックのイベントを受信するための優先順位を設定する ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle); // テキストの角度 // 再描画 ChartRedraw(0); return(true); } //+------------------------------------------------------------------+ //| メインチャートに描画 //+------------------------------------------------------------------+ void ArrowCreate(const long chart_ID, // チャート識別子 string name, // 名前 const int sub_window, // サブウィンドウ番号 pattern_struct &structure[], // アンカーポイントの価格 datetime &time[], // 時刻 int arrowwCode, // 矢印コード(上側) int arrowwCode2, // 矢印コード(下側) color clr, // 矢印の色 int width) // 矢印のサイズ { // 名前が name で始まる、OBJ_ARROW のオブジェクトを全部削除 ObjectsDeleteAll(chart_ID, name, 0, OBJ_ARROW); // 0 はメインチャート // 矢印の作成 for(int i=0; i<candlesToCalculate; i++) { // // 描画のフラグが0以上のとき(全部表示。見づらい) // if(signDrawing[i]>0) // 描画のフラグが2のとき(開始位置のみ表示) if(signDrawing[i]==2) { // 上側 string name1=name+IntegerToString(i); // オブジェクト名の作成 ObjectCreate(chart_ID,name1,OBJ_ARROW,0,time[i],structure[i].high); // OBJ_ARROW 作成 ObjectSetInteger(chart_ID,name1,OBJPROP_ARROWCODE,arrowwCode); // 矢印コード ObjectSetInteger(chart_ID,name1,OBJPROP_ANCHOR,ANCHOR_BOTTOM); // アンカーの種類 ObjectSetInteger(chart_ID,name1,OBJPROP_COLOR,clr); // 矢印の色 ObjectSetInteger(chart_ID,name1,OBJPROP_WIDTH,width); // 矢印のサイズ // 下側 string name2=name+"bottom_"+IntegerToString(i); // オブジェクト名の作成 ObjectCreate(chart_ID,name2,OBJ_ARROW,0,time[i],structure[i].low); // OBJ_ARROW 作成 ObjectSetInteger(chart_ID,name2,OBJPROP_ARROWCODE,arrowwCode2); // 矢印コード ObjectSetInteger(chart_ID,name2,OBJPROP_ANCHOR,ANCHOR_TOP); // アンカーの種類 ObjectSetInteger(chart_ID,name2,OBJPROP_COLOR,clr); // 矢印の色 ObjectSetInteger(chart_ID,name2,OBJPROP_WIDTH,width); // 矢印のサイズ } } // 再描画 ChartRedraw(0); } //+------------------------------------------------------------------+ //| 画面下部のボタンの設定 //+------------------------------------------------------------------+ void LowerButton() { color clr=clrBlack; // 文字の色 color back_clr=clrWhite; // ボタンと境界線の色 if(mode==1) // 検索モードのとき色変更 { clr=clrWhite; // 文字の色 back_clr=clrNONE; // ボタンと境界線の色 } string text; // 表示するテキスト for(int i=0; i<patternNow; i++) { string name = Prefix+"Lower_Button_"+IntegerToString(i); // ボタンに表示するテキストの設定 if(mode==0) { switch(csType[i]) { case 1: case 2: text="W"; break; case 11: case 12: text="B"; break; case 22: text="HL"; break; case 3: case 13: case 23: text="H"; break; case 4: case 14: case 24: text="L"; break; } } else text=IntegerToString(i); ButtonCreate(chart_id,name,sub_w,text,pattern[i].x+15,30,20,20,clr,back_clr); } //--- チャートを再描画 ChartRedraw(); } //+------------------------------------------------------------------+ //| ボタン作成 マウスクリックの優先度は 100 //+------------------------------------------------------------------+ bool ButtonCreate(const long chart_ID, // チャート識別子 string name, // オブジェクト名 const int sub_window, // サブウィンドウ番号 string text, // テキスト int x, // x軸(ピクセル) int y, // y軸(ピクセル) int x_button, // ボタンの幅 int y_button, // ボタンの高さ color clr, // テキストの色 color back_clr) // 背景色 { ResetLastError(); // エラー値をリセットする if(!ObjectCreate(chart_ID,name,OBJ_BUTTON,sub_window,0,0)) // ボタンを作成する { Print(__FUNCTION__,": failed to create the button! Error code = ",GetLastError()); return(false); } ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); // x軸(ピクセル) ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); // y軸(ピクセル) ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,x_button); // ボタンの幅 ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,y_button); // ボタンの高さ ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,CORNER_RIGHT_LOWER); // x=0,y=0 のコーナーを設定(右下) ObjectSetString(chart_ID,name,OBJPROP_TEXT,text); // テキストを設定する ObjectSetString(chart_ID,name,OBJPROP_FONT,InpFont); // フォントを設定する ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,InpFontsize); // フォントサイズを設定する ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); // テキストの色を設定する ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr); // 背景色を設定する ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_COLOR,back_clr); // 境界線の色を設定する ObjectSetInteger(chart_ID,name,OBJPROP_BACK,false); // 前景(false)または背景(true)に表示 ObjectSetInteger(chart_ID,name,OBJPROP_STATE,false); // ボタンの状態(押されるtrue / 押されてないfalse) ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,false); // マウスでのボタンを移動させるモードを有効(true)か無効(false)にする ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,false); ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,true); // オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,zorderButton); // チャートのマウスクリックのイベントを受信するための優先順位を設定する //--- チャートを再描画 ChartRedraw(); return(true); } //+------------------------------------------------------------------+ //| 水平線を描画 //+------------------------------------------------------------------+ void LineCreate(const long chart_ID, // チャート識別子 string name, // オブジェクト名 const int sub_window, // サブウィンドウ番号 double y) // y(価格) { ObjectCreate(chart_ID,name,OBJ_HLINE,sub_window,0,y); ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,InpLineColor); ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,1); ObjectSetInteger(chart_ID,name,OBJPROP_BACK,true); // 前景(false)または背景(true)に表示 ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,false); // デフォルトでは true でハイライトと移動を可能にする。 ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,true); ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,true); // オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,zorderLine); // チャートのマウスクリックのイベントを受信するための優先順位を設定する ChartRedraw(0); } //+------------------------------------------------------------------+ //| パターンのあるところまで画面移動 //+------------------------------------------------------------------+ int ChartMove(int num) { int shift=num; /* ChartNavigate 使用時は必要な処理。これらを別の状態へ変更する処理はないので OnInit() に記述。 // チャートの自動スクロールを無効 ChartSetInteger(chart_id,CHART_AUTOSCROLL,false); // チャートの右端のシフトを設定する ChartSetInteger(chart_id,CHART_SHIFT,true); // ローソク足を描画する ChartSetInteger(chart_id,CHART_MODE,CHART_CANDLES); */ // 移動先の位置を決める(先頭から i 番目の位置に移動) for(int i=1, j=0; i<candlesToCalculate; i++) { if(signDrawing[i]==2) { j++; if(j==shift) { shift=i; break; } } } // チャート右境界線を中央へ移動(チャート右上についている小さな逆三角形) // shift が 0 のときは起動時の位置へ移動 double value=0; if(shift==0) value=saveChartShiftSize; else value=50; // 右境界線の位置セット ChartShiftSizeSet(value,chart_id); // チャートの移動。プラスの値は未来方面へ、マイナスの値は過去方面へ移動。 ChartNavigate(chart_id,CHART_END,shift*(-1)); // 基準が CHART_END (最新のローソク足)なので shift はマイナスにする。 //--- 該当パターンの時刻の表示 datetime time = iTime(Symbol(),PERIOD_CURRENT,shift); string text = (string)num + " / "+ (string)signMax + " の時刻"; string text2 = TimeToString(time); // ラベル作成 LabelCreate(chart_id,Prefix+"Pattern_Time",sub_w,text,CORNER_LEFT_UPPER, 70, 200, ANCHOR_CENTER, "Arial Black", 10, clrWhite,false,0,0); LabelCreate(chart_id,Prefix+"Pattern_Time2",sub_w,text2,CORNER_LEFT_UPPER, 70, 220, ANCHOR_CENTER, "Arial Black", 10, clrWhite,false,0,0); ChartRedraw(); return(0); } //+-----------------------------------------------------------------+ //| 右境界線からのゼロバーのシフトサイズを取得する(MQL5リファレンスから) //| (10% から 50%) //+-----------------------------------------------------------------+ double ChartShiftSizeGet(const long chart_ID=0) { //--- 結果取得のために変数を準備する double result=EMPTY_VALUE; //--- エラー値をリセットする ResetLastError(); //--- プロパティ値を受け取る if(!ChartGetDouble(chart_ID,CHART_SHIFT_SIZE,0,result)) { //--- エキスパート操作ログでエラーメッセージを表示する Print(__FUNCTION__+", Error Code = ",GetLastError()); } //--- チャートプロパティの値を返す return(result); } //+-----------------------------------------------------------------------------+ //| 右境界線からのゼロバーのシフトサイズを設定する(MQL5リファレンスから) //| (10% から50%) //| シフトモードを有効にするには、CHART_SHIFT プロパティ値を true に設定する必要がある //+-----------------------------------------------------------------------------+ bool ChartShiftSizeSet(const double value,const long chart_ID=0) { //--- エラー値をリセットする ResetLastError(); //--- プロパティ値を設定する if(!ChartSetDouble(chart_ID,CHART_SHIFT_SIZE,value)) { //--- エキスパート操作ログでエラーメッセージを表示する Print(__FUNCTION__+", Error Code = ",GetLastError()); return(false); } //--- 実行成功 return(true); } //+------------------------------------------------------------------+ //| チャートのスクリーンショット //+------------------------------------------------------------------+ void ScreenShot() { //--- ファイル名の作成(ファイル名に時間を入れたい) string str=TimeToString(TimeLocal(),TIME_DATE); string str2=TimeToString(TimeLocal(),TIME_SECONDS); StringReplace(str2,":","."); // 12:34:56 --> 12.34.56 に変更(:がファイル名に使用できないため) string name="Creating_My_Rules_"+str+"_"+str2+".gif"; // 例: Creating_My_Rules_2024.10.01_12.34.56.gif //--- キャプチャする幅と高さ long width=0; // 幅 ChartGetInteger(chart_id,CHART_WIDTH_IN_PIXELS,sub_w,width); long height=0; // サブウィンドウの高さ ChartGetInteger(chart_id,CHART_HEIGHT_IN_PIXELS,sub_w,height); long height2=0; // メインチャートからサブウィンドウまでの高さ ChartGetInteger(chart_id,CHART_WINDOW_YDISTANCE,sub_w,height2); //--- スクリーンショットの保存 (保存先 terminal_directory\MQL5\Files\ ) if(ChartScreenShot(chart_id,name,(int)width,(int)(height+height2),ALIGN_CENTER)) printf("スクリーンショットを保存しました。file name = %s",name); //--- スクリーンショットの保存先を開く string dir=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files"; ShellExecuteW(0,"open",dir,"","",1); } //+------------------------------------------------------------------+ //| 通貨ペア・時間足の表示 //+------------------------------------------------------------------+ void Info() { // 通貨ペア LabelCreate(chart_id,Prefix+"Symbol",sub_w,_Symbol,CORNER_LEFT_UPPER, 70, 30, ANCHOR_CENTER, "Arial Black", 14, clrWhite, false, 0, 0); // タイムフレーム(時間軸) ENUM_TIMEFRAMES timeframe = _Period; string text_timeframe = EnumToString(timeframe); // "PERIOD_M30" "PERIOD_H1" のような文字列を取得 LabelCreate(chart_id,Prefix+"TimeFrame",sub_w,StringSubstr(text_timeframe, 7),CORNER_LEFT_UPPER, 70, 60, ANCHOR_CENTER, "Arial Black", 14, clrWhite, false, 0, 0); // 検索期間 datetime timeFirst = iTime(Symbol(),PERIOD_CURRENT,0); datetime timeLast = iTime(Symbol(),PERIOD_CURRENT,candlesToCalculate); string textFirst = TimeToString(timeFirst); string textLast = TimeToString(timeLast); LabelCreate(chart_id,Prefix+"TimeLabel",sub_w,"検索期間",CORNER_LEFT_UPPER, 70, 100, ANCHOR_CENTER, "Arial Black", 10, clrWhite, false, 0, 0); LabelCreate(chart_id,Prefix+"TimeFirst",sub_w,textFirst,CORNER_LEFT_UPPER, 70, 120, ANCHOR_CENTER, "Arial Black", 10, clrWhite, false, 0, 0); LabelCreate(chart_id,Prefix+"Time~",sub_w,"~",CORNER_LEFT_UPPER, 70, 140, ANCHOR_CENTER, "Arial Black", 10, clrWhite, false, 0, 90); // ~を90度回転して表示 LabelCreate(chart_id,Prefix+"TimeLast",sub_w,textLast,CORNER_LEFT_UPPER, 70, 160, ANCHOR_CENTER, "Arial Black", 10, clrWhite, false, 0, 0); } //+------------------------------------------------------------------+ //| ファイルの保存 //+------------------------------------------------------------------+ int CsvFileWrite() { // バックアップファイルがあって、さらに保存ファイルもあるならバックアップファイルを削除 // バックアップがあって保存ファイルが無いことは有りえるのでそのときは削除しない if(FileIsExist(csvName_bk)) if(FileIsExist(csvName)) FileDelete(csvName_bk); // 保存ファイルがあったらファイル名変更 if(FileIsExist(csvName)) FileMove(csvName,0,csvName_bk,0); // 4番目のフラグ 0 は何もしない。これがないとコンパイルエラーになる。 // CSVファイルの作成 ResetLastError(); int handle=FileOpen(csvName,FILE_READ|FILE_WRITE|FILE_CSV|FILE_UNICODE); if(handle!=INVALID_HANDLE) { // カラム FileWrite(handle, "ローソク足番号", "陽線陰線", "y軸 open", "y軸 high", "y軸 low", "y軸 close"); // csvの1行目にカラムを付ける // 保存するデータの出力 for(int i=0; i<patternMax; i++) FileWrite(handle, i, csType[i], pattern[i].open, pattern[i].high, pattern[i].low, pattern[i].close); // ファイルを閉じる FileClose(handle); PrintFormat("%s を作成しました",csvName); return(1); } else { printf("ファイルの作成を失敗しました %s , エラーコード %d", csvName, GetLastError()); return(-1); } return(0); } //+------------------------------------------------------------------+ //| ファイルの読込 //+------------------------------------------------------------------+ int CsvFileRead() { ResetLastError(); int handle=FileOpen(csvName,FILE_READ|FILE_CSV|FILE_UNICODE); if(handle!=INVALID_HANDLE) { // 1行目(カラム)は変数に入れない。行の最後になるまで移動 while(!FileIsLineEnding(handle)) FileReadNumber(handle); int i=0; while(!FileIsEnding(handle)) // 2行目からファイルの最後になるまで移動 { FileReadNumber(handle); // ローソク足の番号(1列目のデータは取得せず移動のみ) csType[i] = (int)FileReadNumber(handle); // 陽線・陰線情報 pattern[i].open = (int)FileReadNumber(handle); // open pattern[i].high = (int)FileReadNumber(handle); // high pattern[i].low = (int)FileReadNumber(handle); // low pattern[i].close = (int)FileReadNumber(handle); // close i++; } //--- ファイルを閉じる FileClose(handle); return(1); } else { PrintFormat("ファイルの読込を失敗しました %s , エラーコード %d",csvName,GetLastError()); return(-1); } return(0); } //+------------------------------------------------------------------+ //| 文字列をキャラに変換 //+------------------------------------------------------------------+ char StrToChar(string str) { if(str=="O") return 'O'; if(str=="H") return 'H'; if(str=="L") return 'L'; if(str=="C") return 'C'; return(0); } //+------------------------------------------------------------------+ //| 構造体の初期設定 //+------------------------------------------------------------------+ int StructReset(pattern_struct &structure[], // 初期化する構造体 int num, // 処理するローソク足の数 int type) // 初期化の処理の種類 0=pattern構造体の初期化, 1=chart構造体の初期化, 10=.results[][]のみ初期化 { switch(type) { case 0: // pattern構造体の初期化 { // xの200は画面右側にボタンを配置するため // yの50は画面下側にボタンを配置するため // 初期値を代入 for(int i=0; i<patternMax; i++) { if(i<num) csType[i]=1; // 使用する分のみ 1 を設定 else csType[i]=0; // 使用しない分は 0 structure[i].x=200+(i*40); // x軸 structure[i].open=50+30+15; // y軸 open structure[i].high=50+75+15; // y軸 high structure[i].low=50+15+15; // y軸 low structure[i].close=50+60+15; // y軸 close } return(1); } case 10: // pattern構造体の価格のみ初期化 { for(int i=0; i<patternMax; i++) { structure[i].open=50+30+15; // y軸 open structure[i].high=50+75+15; // y軸 high structure[i].low=50+15+15; // y軸 low structure[i].close=50+60+15; // y軸 close } return(1); } case 1: // chart構造体の初期化 { // 配列ではないけど ArrayResize しておかないとおかしくなる ArrayResize(chart,num); // .x は使用しないが念のため 0 で初期化 for(int i=0; i<num; i++) chart[i].x=0; return(1); } case 20: // 構造体の .results[][] のみ初期化 { // 0 で上書き for(int i=0; i<num; i++) for(int index=0; index<190; index++) for(int ohlc=0; ohlc<4; ohlc++) structure[i].results[index][ohlc]=0; return(1); } } return(0); } //+------------------------------------------------------------------+ //| この指標のチャートウィンドウの番号を返す(MQL5リファレンスから) //| https://www.mql5.com/ja/docs/chart_operations/chartwindowfind //+------------------------------------------------------------------+ int GetIndicatorsub_windowNumber(long chart_ID=0,string short_name="") { int window=-1; if((ENUM_PROGRAM_TYPE)MQL5InfoInteger(MQL5_PROGRAM_TYPE)==PROGRAM_INDICATOR) { //--- 関数が指標から呼び出されているので名称は必須でない window=ChartWindowFind(); } else { //--- 関数がエキスパートアドバイザーやスクリプトから呼び出されている window=ChartWindowFind(chart_ID,short_name); if(window==-1) Print(__FUNCTION__+"(): Error = ",GetLastError()); } return(window); } //+------------------------------------------------------------------+
それでは良い一日を!