KI’s blog

中年男性によるFXとMQL5のメモ

私の取引ルールの作り方

久しぶりの投稿です。
今回は私の取引ルールの作り方を紹介します。

まず初めに必要な条件があります。


・MQLが使えること
MQL5、又はMQL4が使えること。EAは作れなくてもエントリーポイントの表示ができればいいです。


次は選択できる条件です。下記は私の場合です。


・通貨ペア....USD/JPY
慣れている通貨ペアがいいです。


・取引スタイル....デイトレード
ルール通りに損切りと利確が出来れば何でもいいのですが、15分足以上の時間軸でパターンを作る方がいいです。


・リスク/リターン....ローリスク/ローリターン
勝てるなら「ハイリスク/ハイリターン」。底で買って天井で売れる、又は天井で売って底で買い戻せるなら「ローリスク・ハイリターン」。勝てないなら「ローリスク/ローリターン」

いずれにしても勝率は高くないと駄目です。宝くじを買い続けている状態になっては駄目です。いつか来るはずのリターンは来ません。


・経済指標前後や要人発言等で荒れた時....取引しない
荒れてない相場状況で取引ルールを作るためです。


・取引するのは....EA
手動は大変です。EAはチャンスを逃さないため。ルール通りの取引をするため。あと、EAに[ON][OFF]スイッチを付けると結構便利です。ブレイクイーブンやトレーリングストップを使いたいならEAを勧めます。



では、取引ルールの作り方です。


1,まずはチャートを表示します。私の場合はデイトレードで15分足を使うので15分足のチャートを表示します。それから、1時間足、4時間足、日足も画面に表示します。


2,それらのチャートにテクニカル指標が表示されていたら消してください。テクニカル指標で考えないためです。


3,値動き(ローソク足)だけでルールを作ります。15分足をメインに、1時間足や日足等の始値・高値・安値とかも考慮します。ローソク足の本数は連続3本とかでもいいですし、他の時間軸の始値・高値・安値などを使うのであれば連続してないローソク足になりますけど全然いいと思います。勝てそうなパターンを見つけましょう。いきなりパターン作成は難しいので、酒田五法やプライスアクション、チャートパターンを参考にしたり、www.forexfactory.com の Forums の Trading Systems に色々な手法が公開されているので参考にしてください。


4,パターンが見つかったら、それをMQLでエントリーポイントが表示されるように書いて実行します。


5,過去1年くらいを見てみます。指標時間や、短い時間で大きく動いているところは外して確認します。それで勝ちが多いのであれば、そのパターンにテクニカル指標をあてます。勝ちが増えるか負けが減るかのどちらかの使い方になりますが、プラスになる使い方をしてください。あと、テクニカル指標はローソク足が確定しないと今見ているチャートの表示になりません。成行でテクニカル指標があるレベルを超えたからエントリーしたのに、時間が経ったらレベルを超えてなくてしかもマイナス方向へ動いてるというのは良くあります。なので、あるレベルを超えていた場合はエントリーしない(あるレベルを超えていなければエントリーする)という考え方の方がいいと思います。


ちなみにテクニカル指標はケンドールの順位相関係数を勧めます。これは「時間が進めば価格が高くなる/時間が進めば価格が安くなる」をレベルで表示していて、さらにサンプル(ローソク足の数)が少なくても機能するからです。RCIとはほんのちょっとですが違います。ケンドールの順位相関係数は、www.mql5.comで「取引における相関の実用化」と検索すれば出てきます。


6,パターンが見つかって、それをサポートするテクニカル指標も決まったら、そのルールをノートや word にまとめます。


7,あとはEAにするか、手動で取引するかです。


ざっとですが私の取引ルールの作り方はこんな感じです。
それでは良い一日を!

Creating_My_Rules.mq5 (Ver.1.07)

Creating_My_Rules.mq5 を修正しました。


・パターン数で、陽線、陰線を足したものとHLの数が異なるのは、陽線・陰線のときに十字線が含まれていないからでした。SearchForStartValue() で十字線を判断して陽線OHLC・陰線OHLCのときに数に含むようにしました。陽線HL・陰線HLなどでは含まれないので、それらの合計とHLの数は異なります。
現状では価格変更モードで陽線か陰線で始値と安値を交差させて水平線をクリックすれば同じ価格になる処理になってますのでとりあえず十字線は使用できます。私の取引ルールでは十字線を使わないので気付きませんでした。構造体に .jyujisen を追加すればソースコードをあまり変更せずに他の処理もできそうな気がしますが、十字線を自分で使わないのでどうするかちょっと考えます。


・陽線を陽線のままで処理していたので比較結果がおかしかったのを修正しました。OHLCの陽線と陰線を使ったときに、陰線の並びで比較する処理なのに陽線のままで処理していたためおかしな比較結果になってました。ごめんなさい。始値終値を使うとパターン数が少ないため、途中から高値安値だけでパターン探したりテストしていたため今更になって気付きました。InequalitySignResultToNum() に始値終値を入れ替える処理を追加しました。


・以上でおかしなところはなくなったと思いますが、自分でいろいろ使いながらまた変なところがあったら修正したものを公開します。



ソースコードを下記に公開するので興味がある方はご自由にお使いください。

//+------------------------------------------------------------------+
//|                                            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.07"
#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;

      // 価格を変更するたびにパターンを探す
      SearchForStartValue();
      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);


   //--- 自作パターンとチャートの陽線・陰線の並びと同じなら、パターンの開始位置のフラグを立てる。
   // 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)) ||  // チャート陰線でパターン陰線 又は
            ((chart[i+j].open==chart[i+j].close) && (pattern[j].open)==(pattern[j].close) && ((csType[j]==1)||(csType[j]==11))) || // チャートとパターンが十字線で、さらにOHLCのとき 又は
            ((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]
         {
            // L側が陽線の場合、陰線へ変更
            // ローソク足の状態は csType[] にしかないので、チャート側のローソク足もこの配列で判断する
            if(csType[i]==1)
            {
               double temp_OC=structure[i+csNum].open;
               structure[i+csNum].open=structure[i+csNum].close;
               structure[i+csNum].close=temp_OC;
            }

            for(int j=i+1; j<patternNow; j++) //  j はL側の位置番号。L側のローソク足は [j+csNum]
            {
               // R側が陽線の場合、陰線へ変更
               if(csType[j]==1)
               {
                  double temp_OC=structure[j+csNum].open;
                  structure[j+csNum].open=structure[j+csNum].close;
                  structure[j+csNum].close=temp_OC;
               }

               // 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 のループ

               // R側の入れ替えた陰線を陽線へ戻す
               if(csType[j]==1)
               {
                  double temp_OC=structure[j+csNum].open;
                  structure[j+csNum].open=structure[j+csNum].close;
                  structure[j+csNum].close=temp_OC;
               }

               index++; // int ohlcのループが終わったら保存場所を一つずらす
            }

            // L側の入れ替えた陰線を陽線へ戻す
            if(csType[i]==1)
            {
               double temp_OC=structure[i+csNum].open;
               structure[i+csNum].open=structure[i+csNum].close;
               structure[i+csNum].close=temp_OC;
            }

         } // ここまでが int i のループ
      }
   }
}
//+------------------------------------------------------------------+
//| ローソク足の種類の変更
//| 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);
}
//+------------------------------------------------------------------+


それでは良い一日を!

Creating_My_Rules.mq5 (Ver.1.06)

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);
}
//+------------------------------------------------------------------+


それでは良い一日を!

Creating_My_Rules.mq5 (Ver.1.05)

Creating_My_Rules.mq5 を修正・変更しました。


・主な変更点は、SearchForPattern() で MqlRates を使うのをやめ、OnCalculate() で値をコピーするようにしました。


・操作画面を[ローソク足の変更]と[検索]の2つに変更しました。また、操作するたびにパターンの検索を実行するように変更しました。
 ローソク足の価格を変更するときは、ローソク足をクリックしてください。陽線・陰線の変更は今までと同じです。

起動時の画面
検索画面


・Ver.1.04 は[価格リセット]ボタンの追加と、気になったところの修正・変更・関数の分割なので公開はやめました。


注意点
・H のみや L のみが複数あると検索がうまくできないです。解決に時間かかりそうです。注意して使用してください。ごめんなさい。


ソースコードを下記に公開するので興味がある方はご自由にお使いください。

//+------------------------------------------------------------------+
//|                                            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.05"
#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 status;  // 0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ

   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 patternNow=3;             // 作成するパターンのローソク足の数
const int patternMin=2;       // 作成するパターンのローソク足の最小値
const int patternMax=20;      // 作成するパターンのローソク足の最大値

int mode=0;                   // 作業切り替えボタンの状態
char saveOHLC=-1;             // OHLCのどれを選択しているか保存
int saveNum=-1;               // クリックしたローソク足の番号
double saveChartShiftSize=0;  // チャート右境界線の値の保存

int startValue[];             // 関数で処理するときにパターンの先頭だけを処理するためのフラグ

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; // 起動時のチャートの自動スクロールの状態を保存

// マクロ代入
#define Prefix "MY_Rules_"                         // 描画オブジェクトプレフィックス
#define csvName "Creating_My_Rules.csv"            // CSVファイル名
#define csvName_bk "Creating_My_Rules_backup.csv"  // CSVファイル名

// 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;            // 描画するサイン サイズ
//input group ""
//input string InpFont="Arial Black";    // フォント種類
//input int InpFontsize=10;              // フォントサイズ
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(startValue,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読込ボタン削除
         
         //--- パターンを検索
         CopyForPattern();
         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に変換

      StatusChange(num);   // ローソク足の種類の変更

      // オブジェクト削除
      ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w);   // OHLC オブジェクトを削除

      CandlestickCreate(); // サブウィンドウに描画するローソク足の作成
      LowerButton();       // 画面下部のボタン作成
      CopyForPattern();    // 自作パターンのコピー

      SearchForPattern();  // パターン検索

      return;
   }
         

   //--- [<-][->]ボタンを押したとき
   if(sparam == Prefix+"CSNum_L")  // [<]ボタン
   {
      // ローソク足の本数を増やす
      if(patternNow<patternMax) patternNow++;
            
      // 陽線・陰線情報変更
      pattern[patternNow-1].status=1;
           
      // ラベルのテキスト更新
      ObjectSetString(chart_id,Prefix+"CSNum",OBJPROP_TEXT,(string)patternNow);
            
      // オブジェクト削除
      ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w);   // OHLC オブジェクトを削除

      CandlestickCreate(); // ローソク足の描画
      LowerButton();       // 画面下部のボタン作成
      CopyForPattern();    // 自作パターンのコピー
      SearchForPattern();  // パターン検索

      return;
   }
   
   if(sparam == Prefix+"CSNum_R")  // [>]ボタン
   {
      // ローソク足の本数を減らす
      if(patternNow>patternMin) patternNow--;

      // 陽線・陰線情報変更
      pattern[patternNow].status=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();       // 画面下部のボタン作成
      CopyForPattern();    // 自作パターンのコピー
      SearchForPattern();  // パターン検索
      
      return;
   }
   
   
   // [CSV読込]ボタンを押したとき
   if(sparam == Prefix+"File_Read")
   {
      // ファイルの読込
      CsvFileRead();

      //--- 再描画・再設定
      // 未使用のローソク足の確認
      for(int i=0; i<patternMax; i++)
      {
         if(pattern[i].status==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();       // 画面下部のボタン作成
      CopyForPattern();    // 自作パターンのコピー
      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==100)
      {
         OhlcLabelCreate(saveNum); // OHLC 描画
         ObjectSetInteger(chart_id,sparam,OBJPROP_ZORDER,99); // z_order の値を99に設定
      }
      else
      {
         ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w);      // オブジェクトを削除
         ObjectSetInteger(chart_id,sparam,OBJPROP_ZORDER,100); // z_order の値を100に設定
      }

      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((pattern[saveNum].status<10 && pattern[saveNum].open > pattern[saveNum].close) ||                             // 陽線なのに始値が終値より上 又は
               (pattern[saveNum].status>10 && pattern[saveNum].status<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((pattern[saveNum].status<10 && pattern[saveNum].open > pattern[saveNum].close) ||                             // 陽線なのに始値が終値より上 又は
               (pattern[saveNum].status>10 && pattern[saveNum].status<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 CopyForPattern()
{
   //--- 初期化が必要なもの

   // フラグの配列を初期化
   ArrayInitialize(startValue,0);


   //--- 自作パターンの陽線・陰線の並びと、チャート価格の陽線・陰線の並びが同じなら .status を上書き
   // .status     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) && (pattern[j].status>0)  && (pattern[j].status<10)) ||   // チャート陽線でパターン陽線 又は
            ((chart[i+j].open>chart[i+j].close) && (pattern[j].status>10) && (pattern[j].status<20)) ||   // チャート陰線でパターン陰線 又は
            ((pattern[j].status>20) && (pattern[j].status<30)))                                           // 陽線・陰線どちらも可
         {
            k++;
            continue;
         }
         break;   // 該当無しはjループ終了
      }
      
      // 陽線・陰線の並び方が同じなら その部分に自作パターンの並び方を上書きする
      if(k==patternNow)
      {
         for(int j=0; j<patternNow; j++)
            chart[i+j].status=pattern[j].status;
         
         startValue[i]=1; // パターンの先頭フラグを立てる
      }

      k=0; // カウンタリセット
   }

   return(0);
}
//+------------------------------------------------------------------+
//| パターンを検索
//+------------------------------------------------------------------+
int SearchForPattern()
{
   //--- 初期化が必要なもの
   
   // フラグの配列を初期化
   ArrayInitialize(signDrawing,0);

   // 比較結果を入れる構造体.results[][] を初期化
   StructReset(pattern,patternMax,20);
   StructReset(chart,candlesToCalculate,20);


   //--- ① 自作パターンの不等号の比較結果の保存
   startValue[0]=1; // [0]は自作パターンでのみ使用。[0]=1にしないと次の関数で処理されない。
   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]。
   // R側のローソク足の位置番号は [i+csNum]。
   // L側のローソク足の位置番号は [j+csNum]。
   // LRの比較する位置番号は左上が直角二等辺三角形の逆ピラミッド型になる。

   for(int csNum=start; csNum<end; csNum++) // 処理するローソク足のループ。csNum は処理するローソク足の番号
   {
      if(startValue[csNum]>0) // パターンの先頭フラグチェック
      {
         for(int i=0, index=0; i<patternNow; i++) // [i] はカウンタとして使用。処理するローソク足は [i+csNum]
         {
            for(int j=i+1; j<patternNow; j++) //  j は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側の値

                  // .status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ

                  // L側から確認
                  switch(structure[j+csNum].status)
                  {
                     //--- L OHLCのとき
                     case 1:
                     case 11:
                        switch(structure[i+csNum].status)
                        {
                           // 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(structure[i+csNum].status)
                        {
                           // 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(structure[i+csNum].status==1 || structure[i+csNum].status==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(structure[i+csNum].status)
                        {
                           // 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(structure[i+csNum].status)
                        {
                           // 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]=1; // high 以上
                        else if(L<=RH && L>=RL)   structure[csNum].results[index][ohlc]=6; // high 以下, low 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // low 以下
                        break;

                     case 'C': // Hのみ
                        if(L>=RH)                 structure[csNum].results[index][ohlc]=1; // high 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // high 以下
                        break;

                     case 'D': // Lのみ
                        if(L>=RL)                 structure[csNum].results[index][ohlc]=1; // low 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // low 以下
                        break;
                  }

               } // ここまでが int ohlc のループ

               index++; // int ohlcのループが終わったら保存場所を一つずらす
            }
         }
      }
   }
}
//+------------------------------------------------------------------+
//| ローソク足の種類の変更
//| pattern[].status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ
//+------------------------------------------------------------------+
void StatusChange(int num)
{

   if(pattern[num].status==4 || pattern[num].status==14)
   {
      if(pattern[num].status==4) pattern[num].status=11; // 4 の次は 11
      else pattern[num].status=22;                       // 14 の次は 22

      // 始値・終値の入替
      double temp=0;
      temp=pattern[num].open;
      pattern[num].open=pattern[num].close;
      pattern[num].close=temp;
      return;
   }
   else if(pattern[num].status==24) // 24 の次は 1
   {
      pattern[num].status=1;
      return;
   }
   else pattern[num].status++;

}
//+------------------------------------------------------------------+
//| ローソク足を描画
//+------------------------------------------------------------------+
void CandlestickCreate()
{
   double y;
   int width=10;     // 幅(x軸)
   double height;    // 高さ(y軸)
   color clr;

   for(int i=0; i<patternNow; i++)
   {
      //--- 色の設定
      if(pattern[i].status<10)      clr=InpCsColorW;  // 10 より下なら陽線
      else if(pattern[i].status<20) clr=InpCsColorB;  // 20 より下なら陰線
      else                          clr=InpCsColorHL; // それ以外はどちらでも可

      //--- 実体

      string name = Prefix+"CS_Body_"+IntegerToString(i); // 実体の名前

      // 陽線OHLC・陰線OHLCのとき実体を描画
      if(pattern[i].status==1 || pattern[i].status==11)
      {
         // 始値と終値の位置変更
         if(pattern[i].status==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((pattern[i].status==3 || pattern[i].status==4) ||
         (pattern[i].status==13 || pattern[i].status==14) ||
         (pattern[i].status==23 || pattern[i].status==24))
      {
         height = 30;   // ラベルの高さ

         // H か L か
         if(pattern[i].status==3 || pattern[i].status==13 || pattern[i].status==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,100);

   }

   //--- チャートを再描画
   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(pattern[num].status)
      {
         // 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(pattern[num].status>10 && pattern[num].status<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,200,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(pattern[i].status)
         {
            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,100);            // チャートのマウスクリックのイベントを受信するための優先順位を設定する

   //--- チャートを再描画
   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,300);       // チャートのマウスクリックのイベントを受信するための優先順位を設定する

   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, pattern[i].status, 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列目のデータは取得せず移動のみ)
         pattern[i].status = (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) structure[i].status=1; // 使用する分のみ 1 を設定
            else structure[i].status=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);
         
         // 0 で初期化。.x は使用しないが念のため。
         for(int i=0; i<num; i++)
         {
            chart[i].status=0;
            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);
}
//+------------------------------------------------------------------+


それでは良い一日を!

Creating_My_Rules.mq5 (Ver.1.03)

Creating_My_Rules.mq5 を修正しました。

・前回の [自作パターンを変更して検索実行を繰り返すと、検索結果が減少していたのを修正] が間違っていたので再度修正しました。原因は比較結果を入れる構造体の配列に古い結果の値が残っていたためです。それを初期化するようにしました。


今後の予定

・構造体の初期化は StructReset() でするようにまとめます。そのあと、[価格変更] の画面でマウスで高値や安値などを変更するたびに該当パターン数の表示を出来るように変更する予定です。


ソースコードを下記に公開するので興味がある方はご自由にお使いください。

//+------------------------------------------------------------------+
//|                                            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.03"
#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 status;  // 0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ

   int x;         // x軸
   int y_open;    // y軸 open。価格ではなくy軸としてなのでint型
   int y_high;    // y軸 high
   int y_low;     // y軸 low
   int y_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 main_cs[];     // メインチャート用。OnInit()でリサイズ。

// グローバル変数
long chart_id=0;  // チャートID
int sub_w=1;      // サブウィンドウの番号

int patternNow=3;          // 作成するパターンのローソク足の数
const int patternMin=2;    // 作成するパターンのローソク足の最小値
const int patternMax=20;   // 作成するパターンのローソク足の最大値

int mode=0;                   // 作業切り替えボタンの状態
char saveOHLC=-1;             // OHLCのどれを選択しているか保存
int saveNum=-1;               // クリックしたローソク足の番号
double saveChartShiftSize=0;  // チャート右境界線の値の保存

int startValue[];             // 関数で処理するときにパターンの先頭だけを処理するためのフラグ

int prefixLen=0;     // Prefix の文字列の数
int signDrawing[];   // サインを描画するフラグ
int signNow=0;       // 今のサインの位置
int signMax=0;       // 見つかったサインの総数
const int signMin=0; // 最小の数。0で固定

// フラグ
bool mouseMoveFlag=false;        // マウスの位置情報 取得フラグ
bool saveCHART_AUTOSCROLL=false; // 起動時のチャートの自動スクロールの状態を保存

// マクロ代入
#define Prefix "MY_Rules_"                         // 描画オブジェクトプレフィックス
#define csvName "Creating_My_Rules.csv"            // CSVファイル名
#define csvName_bk "Creating_My_Rules_backup.csv"  // CSVファイル名

// 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;            // 描画するサイン サイズ
//input group ""
//input string InpFont="Arial Black";    // フォント種類
//input int InpFontsize=10;              // フォントサイズ
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);
   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
   
   ArrayResize(main_cs,candlesToCalculate);                       // 配列ではないけど ArrayResize しないとおかしくなる
   for(int i=0; i<candlesToCalculate; i++) main_cs[i].status=0;   // main_cs[].statusのみ 0 で初期化

   // フラグのリサイズ
   ArrayResize(startValue,candlesToCalculate);
   ArrayResize(signDrawing,candlesToCalculate);


   //--- Prefix の文字列の数を調べる
   prefixLen=StringLen(Prefix);

   //--- マウスのイベント無効
   ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_w,false);

   // 初期化完了。ゼロ値を返す。
   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();

      // 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,65,80,ANCHOR_LEFT_UPPER,InpFont,InpFontsize,clrWhite);

      // モード切替ボタン作成
      ButtonCreate(chart_id,Prefix+"Mode_Button",sub_w,"陰陽 変更",100,30,80,20,clrBlack,clrWhite);
   }

   // 次の呼び出しのために 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); return;             // 陰線・陽線の変更
         case 1: Candlestick_Price_ModificationMode(sparam, dparam); return;  // ローソク足の価格の変更
         case 2: SearchForPatternMode(sparam); return;                        // ローソク足の検索・チェック
      }

      return;
   }


   //--- マウス移動イベント
   if(id==CHARTEVENT_MOUSE_MOVE)
   {

//      printf("マウスの位置 : x=%d, y=%d", (int)lparam, (int)dparam); // テスト用。残しておく。

      if((mode==1) && (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); // ローソク足の数変更ボタンの削除
         ObjectDelete(chart_id,Prefix+"File_Read");            // CSV読込ボタン削除

         //--- オブジェクトの変更
         ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"価格 変更");

         //--- オブジェクトの作成
         LowerButton();

         return;

      case 1:  // 今[価格変更]で、これから[検索]

         //--- 操作モード切替
         mode=2;

         //-- オブジェクトの削除
         ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w);
         
         //--- オブジェクトの変更
         ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"検索");
         
         //--- オブジェクトの作成
         LowerButton();

         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,140,80,20,clrWhite,clrNONE);
         ButtonCreate(chart_id,Prefix+"Sign_L",sub_w,"<-",100,110,20,20,clrBlack,clrWhite);
         ButtonCreate(chart_id,Prefix+"Sign_R",sub_w,"->",40,110,20,20,clrBlack,clrWhite);
         LabelCreate(chart_id,Prefix+"Sign_Num",sub_w,(string)signNow,CORNER_RIGHT_LOWER,65,110,ANCHOR_LEFT_UPPER,InpFont,InpFontsize,clrWhite);

         // 確認ボタン作成
         ButtonCreate(chart_id,Prefix+"Do_Search_Button",sub_w,"検索実行",100,80,80,20,clrBlack,clrWhite);

         return;

      case 2:  // 今[検索]で、これから[陰陽変更]

         //--- 操作モード切替
         mode=0;

         //--- オブジェクトの削除
         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+"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,65,80,ANCHOR_LEFT_UPPER,InpFont,InpFontsize,clrWhite);

         return;
   }
}
//+------------------------------------------------------------------+
//| ローソク足の陽線・陰線変更モードの画面
//+------------------------------------------------------------------+
void Candlestick_WB_ModificationMode(const string sparam)
{
   int find=-1; // 指定する文字列が見つかったら整数が入る変数

   //--- 画面下部のボタンを押したとき
   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に変換

      StatusChange(num);   // ローソク足の種類の変更

      CandlestickCreate(); // サブウィンドウに描画するローソク足の作成
      LowerButton();       // 画面下部のボタン作成

      return;
   }
         
   if(sparam == Prefix+"CSNum_Label") // [ローソク足増減]ボタン。設定なし。
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      return;
   }

   //--- 画面右側の[<][>]ボタンを押したとき
   if(sparam == Prefix+"CSNum_L")  // [<]ボタン
   {
      // ローソク足の本数を増やす
      if(patternNow<patternMax) patternNow++;
            
      // 陽線・陰線情報変更
      pattern[patternNow-1].status=1;
           
      // ラベルのテキスト更新
      ObjectSetString(chart_id,Prefix+"CSNum",OBJPROP_TEXT,(string)patternNow);
            
      CandlestickCreate(); // ローソク足の描画
      LowerButton();       // 画面下部のボタン作成
            
      return;
   }
   
   if(sparam == Prefix+"CSNum_R")  // [>]ボタン
   {
      // ローソク足の本数を減らす
      if(patternNow>patternMin) patternNow--;

      // 陽線・陰線情報変更
      pattern[patternNow].status=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_" があるオブジェクトを全部削除

      CandlestickCreate(); // ローソク足の描画
      LowerButton();       // 画面下部のボタン作成

      return;
   }
   
   if(sparam == Prefix+"File_Read") // [CSV読込]ボタン
   {
      // ファイルの読込
      CsvFileRead();

      //--- 再描画・再設定
      // 未使用のローソク足の確認
      for(int i=0; i<patternMax; i++)
      if(pattern[i].status==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_" があるオブジェクトを全部削除
      CandlestickCreate();                                           // ローソク足の再描画
      LowerButton();                                                 // 画面下部のボタン作成

      // ローソク足本数ラベルのテキスト更新
      ObjectSetString(chart_id,Prefix+"CSNum",OBJPROP_TEXT,(string)patternNow);

      return;
   }
}
//+------------------------------------------------------------------+
//| ローソク足の価格変更モードの画面
//+------------------------------------------------------------------+
void Candlestick_Price_ModificationMode(const string sparam, const double dparam)
{
   int find=-1; // 指定する文字列が見つかったら整数が入る変数

   //--- 画面下部の[P]ボタンを押したとき
   find=StringFind(sparam,"Lower_Button_",prefixLen);   // prefixLen の後ろから "Lower_Button_" を探す
   if(find>0)
   {
      // ローソク足の番号取得
      string str=StringSubstr(sparam,prefixLen+13); // prefixLen+"Lower_Button_" の後ろから文字列を全部取り出す
      int num=(int)StringToInteger(str);  // 文字列の数字をlongに変換してintに変換

      saveNum=num;   // クリックした[P]ボタンのローソク足の番号を保存

      // OHLC が表示されていなかったら表示、されていたら削除
      long findOBJ=ObjectGetInteger(chart_id,sparam,OBJPROP_STATE);
      if(findOBJ==1) 
      {
         OhlcLabelCreate(saveNum);                             // OHLC 描画
         ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,true); // ボタンの状態(押されるtrue / 押されてないfalse)
      }
      else
      {
         ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w);    // オブジェクトを削除
         ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されてないfalse)
      }
            
      return;
   }


   //--- ローソク足右側の OHLC を押したとき
   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].y_open=(int)(result2-(dparam-result));
            
            if((pattern[saveNum].status<10 && pattern[saveNum].y_open > pattern[saveNum].y_close) ||                             // 陽線なのに始値が終値より上 又は
               (pattern[saveNum].status>10 && pattern[saveNum].status<20 && pattern[saveNum].y_open < pattern[saveNum].y_close)) // 陰線なのに始値が終値より下
               pattern[saveNum].y_close = pattern[saveNum].y_open;

            break;
         
         case 'H':
            pattern[saveNum].y_high=(int)(result2-(dparam-result));
            
            if(pattern[saveNum].y_high < pattern[saveNum].y_low) // 高値が安値より下だったら
               pattern[saveNum].y_low = pattern[saveNum].y_high;
            
            break;
         
         case 'L':
            pattern[saveNum].y_low=(int)(result2-(dparam-result));

            if(pattern[saveNum].y_high < pattern[saveNum].y_low) // 高値が安値より下だったら
               pattern[saveNum].y_high = pattern[saveNum].y_low;

            break;

         case 'C':
            pattern[saveNum].y_close=(int)(result2-(dparam-result));

            if((pattern[saveNum].status<10 && pattern[saveNum].y_open > pattern[saveNum].y_close) ||                             // 陽線なのに始値が終値より上 又は
               (pattern[saveNum].status>10 && pattern[saveNum].status<20 && pattern[saveNum].y_open < pattern[saveNum].y_close)) // 陰線なのに始値が終値より下
               pattern[saveNum].y_open = pattern[saveNum].y_close;
            
            break;
      }

      // 水平線削除
      ObjectDelete(chart_id,Prefix+"Line");

      // ローソク足の描画
      CandlestickCreate();

      // OHLC の描画
      OhlcLabelCreate(saveNum);

      // マウスに追尾するラインの停止
      ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_w,false);
      mouseMoveFlag=false;
         
      return;
   }
}
//+------------------------------------------------------------------+
//| 検索モードの画面
//+------------------------------------------------------------------+
void SearchForPatternMode(const string sparam)
{
   // [スクリーンショット]ボタンが押されたら
   if(sparam == Prefix+"Do_SS_Button")
   {
      // スクリーンショット保存
      ScreenShot();
      return;
   }

   // [検索実行]ボタンが押されたら
   if(sparam == Prefix+"Do_Search_Button")
   {
      // パターンを検索
      SearchForPattern();
      return;
   }

   // [保存]ボタンが押されたら CSV 出力
   if(sparam == Prefix+"File_Write")
   {
      // ファイルの作成
      CsvFileWrite();
      return;
   }

   // [画面下部]の番号ボタンを押したとき。このボタンに何か設定する予定無し。
   int find=-1;
   find=StringFind(sparam,"Lower_Button_",prefixLen);   // prefixLen の後ろから "Lower_Button_" を探す
   if(find>0)
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      return;
   }
         
   if(sparam == Prefix+"Sign_Label") // [チャート移動]ボタン。設定なし。
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      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 SearchForPattern()
{
   // チャートのローソク足の価格情報の取得
   MqlRates rates[];
   ArraySetAsSeries(rates,true); 
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,candlesToCalculate,rates);
   if(copied < 0)
   {
      printf("CopyRates取得エラー。copied = %d, error code = %d", copied, GetLastError());
      return(-1);
   }

   // 関数に渡すための価格の配列
   double RO[]; // open
   double RH[]; // high
   double RL[]; // low
   double RC[]; // close
   ArrayResize(RO,candlesToCalculate);
   ArrayResize(RH,candlesToCalculate);
   ArrayResize(RL,candlesToCalculate);
   ArrayResize(RC,candlesToCalculate);

   // フラグの配列初期化
   ArrayInitialize(startValue,0);
   ArrayInitialize(signDrawing,0);

   // 比較結果を入れる構造体の .results[][] リセット 
   StructReset(pattern,patternMax,1);
   StructReset(main_cs,0,1);


   // ①配列初期化
   ArrayInitialize(RO,0);
   ArrayInitialize(RH,0);
   ArrayInitialize(RL,0);
   ArrayInitialize(RC,0);

   // ①パターンの価格(y座標)を構造体から配列へコピー
   for(int i=0; i<patternMax; i++)
   {
      RO[i]=pattern[i].y_open;
      RH[i]=pattern[i].y_high;
      RL[i]=pattern[i].y_low;
      RC[i]=pattern[i].y_close;
   }   


   // ①自作パターンの不等号の比較結果の保存
   startValue[0]=1; // [0]は自作パターンでのみ使用。[0]=1にしないと次の関数で処理されない。
   InequalitySignResultToNum(0, 1, pattern, RO, RH, RL, RC);

   //---② メインチャートの比較結果の保存
   // ②陽線・陰線で必要なものをHLの値に変更(HLのみのチェックに対応するため)
   // .status     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(((rates[i+j].open<rates[i+j].close) && (pattern[j].status>0)  && (pattern[j].status<10)) ||   // チャート陽線でパターン陽線 又は
            ((rates[i+j].open>rates[i+j].close) && (pattern[j].status>10) && (pattern[j].status<20)) ||   // チャート陰線でパターン陰線 又は
            ((pattern[j].status>20) && (pattern[j].status<30)))                                           // 陽線・陰線どちらも可
         {
            k++;
            continue;
         }
         break;   // 該当無しはjループ終了
      }
      
      // 陽線・陰線の並び方が同じなら その部分に作成したパターンの並び方を上書きする
      if(k==patternNow)
      {
         for(int j=0; j<patternNow; j++)
            main_cs[i+j].status=pattern[j].status;
         
         startValue[i]=1; // パターンの先頭フラグを立てる
      }

      k=0; // カウンタリセット
   }

   // ②配列初期化
   ArrayInitialize(RO,0);
   ArrayInitialize(RH,0);
   ArrayInitialize(RL,0);
   ArrayInitialize(RC,0);

   // ②価格をコピー
   for(int i=0; i<candlesToCalculate; i++)
   {
      RO[i]=rates[i].open;
      RH[i]=rates[i].high;
      RL[i]=rates[i].low;
      RC[i]=rates[i].close;
   }

   // ②チャート側の不等号の比較結果の保存(ローソク足の数の分をチェック)
   InequalitySignResultToNum(1, candlesToCalculate-patternNow, main_cs, RO, RH, RL, RC);


   //--- ①自作パターンと②チャートの比較結果の比較
   
   // 自作パターンの比較結果の数がいくつになるか計算
   int compareNow=0;
   for(int i=patternNow; i>=patternMin; i--) compareNow = compareNow+i-1;
   
   // 比較の比較
   for(int i=1; i<candlesToCalculate-patternNow; i++) // i はチャートのローソク足の番号
   {
      for(int k=0; k<compareNow; k++) // k はチャートと自作パターンの比較結果の番号
      {
         if(!((main_cs[i].results[k][0] == pattern[0].results[k][0]) &&
              (main_cs[i].results[k][1] == pattern[0].results[k][1]) &&
              (main_cs[i].results[k][2] == pattern[0].results[k][2]) &&
              (main_cs[i].results[k][3] == pattern[0].results[k][3])))
         {
            break;
         }

         // チャートと自作パターンが同じだったら該当するローソク足の番号のフラグを立てる
         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);
         LabelCreate(chart_id,Prefix+"Pattern_Time2",sub_w,(string)signMax,CORNER_LEFT_UPPER, 70, 220, ANCHOR_CENTER, InpFont, InpFontsize, clrWhite);
         ChartRedraw();
         break;
      }
   }

   // メインチャートに描画
   ArrowCreate(chart_id,Prefix+"Sign_",sub_w,rates,InpSignArrowwCode,InpSignArrowwCode2,InpSignColor,InpSignWidth);

   return(0);
}
//+------------------------------------------------------------------+
//| ローソク足の比較の結果を数字に変換する
//+------------------------------------------------------------------+
void InequalitySignResultToNum(int start,                   // 処理を開始するローソク足の番号
                               int end,                     // 処理を終了するローソク足の番号
                               pattern_struct &structure[], // 結果を入れる構造体
                               double &open[],              // open
                               double &high[],              // high
                               double &low[],               // low
                               double &close[])             // close
{
   // 比較結果の位置番号は [csNum]。
   // R側のローソク足の位置番号は [i+csNum]。
   // L側のローソク足の位置番号は [j+csNum]。
   // LRの比較する位置番号は左上が直角二等辺三角形の逆ピラミッド型になる。

   for(int csNum=start; csNum<end; csNum++) // 処理するローソク足のループ。csNum は処理したいローソク足の番号
   {
      if(startValue[csNum]>0) // パターンの先頭フラグチェック
      {
         for(int i=0, index=0; i<patternNow; i++) // [i] はカウンタとして使用。処理するローソク足は [i+csNum]
         {
            for(int j=i+1; j<patternNow; j++) //  j は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側の値

                  // .status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ

                  // L側から確認
                  switch(structure[j+csNum].status)
                  {
                     //--- L OHLCのとき
                     case 1:
                     case 11:
                        switch(structure[i+csNum].status)
                        {
                           // R OHLC -> LRそのまま
                           case 1:
                           case 11:
                              switch(ohlc)
                              {
                                 case 0: L= open[j+csNum]; break;
                                 case 1: L= high[j+csNum]; break;
                                 case 2: L=  low[j+csNum]; break;
                                 case 3: L=close[j+csNum]; 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=high[i+csNum]; break;
                                 case 2: L= low[i+csNum]; 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=high[i+csNum]; 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=low[i+csNum]; break;
                              }
                              SwapTheLR=true;
                              type='A';
                              break;
                        }
                        break;


                     //--- L HLのとき
                     case 2:
                     case 12:
                     case 22:
                        switch(structure[i+csNum].status)
                        {
                           // 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=high[j+csNum]; break;
                                 case 2: L= low[j+csNum]; break;
                              }
                              SwapTheLR=false;

                              if(structure[i+csNum].status==1 || structure[i+csNum].status==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=high[i+csNum]; 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= low[i+csNum]; 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=high[j+csNum]; break;
                        }
                        SwapTheLR=false;
                     
                        switch(structure[i+csNum].status)
                        {
                           // 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=  low[j+csNum]; break;
                        }
                        SwapTheLR=false;

                        switch(structure[i+csNum].status)
                        {
                           // 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= open[j+csNum];
                     RH= high[j+csNum];
                     RL=  low[j+csNum];
                     RC=close[j+csNum];
                  }
                  else
                  {
                     // そのまま
                     RO= open[i+csNum];
                     RH= high[i+csNum];
                     RL=  low[i+csNum];
                     RC=close[i+csNum];
                  }


                  //--- 不等号で比較
                  // 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]=1; // high 以上
                        else if(L<=RH && L>=RL)   structure[csNum].results[index][ohlc]=6; // high 以下, low 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // low 以下
                        break;

                     case 'C': // Hのみ
                        if(L>=RH)                 structure[csNum].results[index][ohlc]=1; // high 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // high 以下
                        break;

                     case 'D': // Lのみ
                        if(L>=RL)                 structure[csNum].results[index][ohlc]=1; // low 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // low 以下
                        break;
                  }

               } // ここまでが int ohlc のループ

               index++; // int ohlcのループが終わったら保存場所を一つずらす
            }
         }
      }
   }
}
//+------------------------------------------------------------------+
//| ローソク足の種類の変更
//| pattern[].status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ
//+------------------------------------------------------------------+
void StatusChange(int num)
{

   if(pattern[num].status==4 || pattern[num].status==14)
   {
      if(pattern[num].status==4) pattern[num].status=11; // 4 の次は 11
      else pattern[num].status=22;                       // 14 の次は 22

      // 始値・終値の入替
      int temp=0;
      temp=pattern[num].y_open;
      pattern[num].y_open=pattern[num].y_close;
      pattern[num].y_close=temp;
   }
   else if(pattern[num].status==24) pattern[num].status=1;  // 24 の次は 1
   else pattern[num].status++;

}
//+------------------------------------------------------------------+
//| ローソク足を描画
//+------------------------------------------------------------------+
void CandlestickCreate()
{
   int y;
   int width=10;  // 幅(x軸)
   int height;    // 高さ(y軸)
   color clr;

   for(int i=0; i<patternNow; i++)
   {
      //--- 色の設定
      if(pattern[i].status<10)      clr=InpCsColorW;  // 10 より下なら陽線
      else if(pattern[i].status<20) clr=InpCsColorB;  // 20 より下なら陰線
      else                          clr=InpCsColorHL; // それ以外はどちらでも可

      //--- 実体

      string name = Prefix+"CS_Body_"+IntegerToString(i); // 実体の名前

      // 陽線OHLC・陰線OHLCのとき実体を描画
      if(pattern[i].status==1 || pattern[i].status==11)
      {
         // 始値と終値の位置変更
         if(pattern[i].status==11) // 陰線OHLC
         {
            y = pattern[i].y_open;                             // y(価格軸、ピクセル)
            height = pattern[i].y_open - pattern[i].y_close;   // y(ラベルの高さ)
         }
         else // 陽線OHLC
         {
            y = pattern[i].y_close;                            // y(価格軸、ピクセル)
            height = pattern[i].y_close - pattern[i].y_open;   // y(ラベルの高さ)
         }

         // 実体描画
         RectLabelCreate(chart_id,name,sub_w,pattern[i].x+width,y,width,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((pattern[i].status==3 || pattern[i].status==4) ||
         (pattern[i].status==13 || pattern[i].status==14) ||
         (pattern[i].status==23 || pattern[i].status==24))
      {
         height = 30;   // ラベルの高さ

         // H か L か
         if(pattern[i].status==3 || pattern[i].status==13 || pattern[i].status==23) // high
         {
            y = pattern[i].y_high;   // y(価格軸、ピクセル)

            // ラベル作成
            LabelCreate(chart_id,name2+"_Char",sub_w,"H",CORNER_RIGHT_LOWER,pattern[i].x+10,y-30,ANCHOR_LEFT_UPPER,InpFont,12,clrWhite,0,true); // 最後の true は背景表示にする
         }
         else // low
         {
            y = pattern[i].y_low+30;   // ラベルの高さ分上にずらす(プラスする)

            // ラベル作成  yは30+文字の大きさ。適当。
            LabelCreate(chart_id,name2+"_Char",sub_w,"L",CORNER_RIGHT_LOWER,pattern[i].x+10,y+30,ANCHOR_LEFT_UPPER,InpFont,12,clrWhite,0,true); // 最後の true は背景表示にする
         }
      }
      else
      {
         ObjectDelete(chart_id,name2+"_Char"); // H・Lの文字のオブジェクト削除
         
         y = pattern[i].y_high;                          // y(価格軸、ピクセル)
         height = pattern[i].y_high - pattern[i].y_low;  // ラベルの高さ
      }

      // ヒゲ描画
      RectLabelCreate(chart_id,name2,sub_w,pattern[i].x+(width/2),y,2,height,clr,BORDER_FLAT,CORNER_RIGHT_LOWER,clr,STYLE_SOLID,1,true,false,true,0);
   }
   
   //--- チャートを再描画
   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
      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=0;
   y=(pattern[num].y_high-(pattern[num].y_high-pattern[num].y_low)/2)+40;

   for(int i=0; i<4; i++)
   {
      // 表示しないものは continue。それ以外は次へ。
      switch(pattern[num].status)
      {
         // 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(pattern[num].status>10 && pattern[num].status<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,0);
   }
   
   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
//| ラベル作成
//+------------------------------------------------------------------+
void 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,   // フォントの色
                 double angle=0,    // 角度
                 bool back=false)   // 背景表示
{

   ResetLastError(); // エラー値をリセットする
   if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0))   // ラベルを作成する
   {
      Print(__FUNCTION__,": failed to create the button! Error code = ",GetLastError());
      return;
   }

   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,0);              // チャートのマウスクリックのイベントを受信するための優先順位を設定する
   ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);            // テキストの角度

   // 再描画
   ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| メインチャートに描画
//+------------------------------------------------------------------+
void ArrowCreate(const long chart_ID,  // チャート識別子
                 string name,          // 名前
                 const int sub_window, // サブウィンドウ番号
                 MqlRates &rates[],    // アンカーポイントの価格と時刻
                 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,rates[i].time,rates[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,rates[i].time,rates[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==2) // 検索モードのとき色変更
   {
      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(pattern[i].status)
         {
            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 if(mode==1) text="P";
      else text=IntegerToString(i);
   
      ButtonCreate(chart_id,name,sub_w,text,pattern[i].x+15,30,20,20,clr,back_clr);
   }

   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
//| ボタン作成      マウスクリックの優先度は 100
//+------------------------------------------------------------------+
void 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;
   }

   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,100);            // チャートのマウスクリックのイベントを受信するための優先順位を設定する

   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
//| 水平線を描画
//+------------------------------------------------------------------+
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)にする

   ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| パターンのあるところまで画面移動
//+------------------------------------------------------------------+
int ChartMove(int num)
{
   int shift=num;

   // チャートの自動スクロールを無効
   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;
   time=iTime(Symbol(),PERIOD_CURRENT,shift);

   string text, text2;
   text= (string)num + "/"+ (string)signMax + "の時刻";
   text2= TimeToString(time);

   // ラベル作成
   LabelCreate(chart_id,Prefix+"Pattern_Time",sub_w,text,CORNER_LEFT_UPPER, 70, 200, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   LabelCreate(chart_id,Prefix+"Pattern_Time2",sub_w,text2,CORNER_LEFT_UPPER, 70, 220, ANCHOR_CENTER, "Arial Black", 10, clrWhite);


   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+(int)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);

   // タイムフレーム(時間軸)
   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);

   // 検索期間
   datetime timeFirst, timeLast;
   timeFirst=iTime(Symbol(),PERIOD_CURRENT,0);
   timeLast=iTime(Symbol(),PERIOD_CURRENT,candlesToCalculate);

   string textFirst, textLast;
   textFirst= TimeToString(timeFirst);
   textLast= TimeToString(timeLast);

   LabelCreate(chart_id,Prefix+"TimeLabel",sub_w,"検索期間",CORNER_LEFT_UPPER, 70, 100, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   LabelCreate(chart_id,Prefix+"TimeFirst",sub_w,textFirst,CORNER_LEFT_UPPER, 70, 120, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   LabelCreate(chart_id,Prefix+"Time~",sub_w,"~",CORNER_LEFT_UPPER, 70, 140, ANCHOR_CENTER, "Arial Black", 10, clrWhite, 90); // ~を90度回転して表示
   LabelCreate(chart_id,Prefix+"TimeLast",sub_w,textLast,CORNER_LEFT_UPPER, 70, 160, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
}
//+------------------------------------------------------------------+
//| ファイルの保存
//+------------------------------------------------------------------+
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, pattern[i].status, pattern[i].y_open, pattern[i].y_high, pattern[i].y_low, pattern[i].y_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列目のデータは取得せず移動のみ)
         pattern[i].status = (int)FileReadNumber(handle); // 陽線・陰線情報
         pattern[i].y_open = (int)FileReadNumber(handle); // open
         pattern[i].y_high = (int)FileReadNumber(handle); // high
         pattern[i].y_low  = (int)FileReadNumber(handle); // low
         pattern[i].y_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 -1;
}
//+------------------------------------------------------------------+
//| 構造体の初期設定
//+------------------------------------------------------------------+
void StructReset(pattern_struct &structure[], int now, int type=0) // 初期化する構造体、使用するローソク足の数、初期化の処理の種類
{
   // xの200は画面右側にボタンを配置するため
   // yの50は画面下側にボタンを配置するため
   // .status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 10=HL, 11=陰線, 12=陰線HL, 13=陰線Lのみ

   if(type==0) // pattern構造体の初期化
   {
      // 初期値を代入
      for(int i=0; i<patternMax; i++)
      {
         if(i<now) structure[i].status=1; // 使用する分のみ 1 を設定
         else structure[i].status=0;      // 使用しない分は 0
      
         structure[i].x=200+(i*40);    // x軸

         structure[i].y_open=50+30;    // y軸 open
         structure[i].y_high=50+75;    // y軸 high
         structure[i].y_low=50+15;     // y軸 low
         structure[i].y_close=50+60;   // y軸 close
      }
   }
   else if(type==1) // 構造体の .results[][] 初期化
   {
      int limit=0;
      if(now==0) limit=candlesToCalculate;
      else limit=now;

      for(int csNum=0; csNum<limit; csNum++)
         for(int index=0; index<190; index++)
            for(int ohlc=0; ohlc<4; ohlc++) structure[csNum].results[index][ohlc]=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);
}
//+------------------------------------------------------------------+


それでは良い一日を!

Creating_My_Rules.mq5 (Ver.1.02)

Creating_My_Rules.mq5 を修正しました。


・自作パターンを変更して検索実行を繰り返すと、検索結果が減少していたのを修正。自作パターンを変更するとき時間軸を切り替えて戻すことをしていたので気付かなかったです。フラグの配列を初期化するようにしたので大丈夫だと思います。

CSVファイル保存時、ファイルがすでにあるときはファイル名を Creating_My_Rules_backup.csv に変更してから、新規に Creating_My_Rules.csv を作成するようにしました。上書きで Creating_My_Rules.csv を作成すると変な値が入ることがあるため上書きをしないようにしました。

・変数名の修正や変な処理の削除など、ソースコードの整理整頓をしました。


ソースコードを下記に公開するので興味がある方はご自由にお使いください。

//+------------------------------------------------------------------+
//|                                            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.02"
#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 status;  // 0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ

   int x;         // x軸
   int y_open;    // y軸 open。価格ではなくy軸としてなのでint型
   int y_high;    // y軸 high
   int y_low;     // y軸 low
   int y_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 main_cs[];     // メインチャート用。OnInit()でリサイズ。

// グローバル変数
long chart_id=0;  // チャートID
int sub_w=1;      // サブウィンドウの番号

int patternNow=3;          // 作成するパターンのローソク足の数
const int patternMin=2;    // 作成するパターンのローソク足の最小値
const int patternMax=20;   // 作成するパターンのローソク足の最大値

int mode=0;                   // 作業切り替えボタンの状態
char saveOHLC=-1;             // OHLCのどれを選択しているか保存
int saveNum=-1;               // クリックしたローソク足の番号
double saveChartShiftSize=0;  // チャート右境界線の値の保存

int startValue[];             // 関数で処理するときにパターンの先頭だけを処理するためのフラグ

int prefixLen=0;     // Prefix の文字列の数
int signDrawing[];   // サインを描画するフラグ
int signNow=0;       // 今のサインの位置
int signMax=0;       // 見つかったサインの総数
const int signMin=0; // 最小の数。0で固定

// フラグ
bool mouseMoveFlag=false;        // マウスの位置情報 取得フラグ
bool saveCHART_AUTOSCROLL=false; // 起動時のチャートの自動スクロールの状態を保存

// マクロ代入
#define Prefix "MY_Rules_"                         // 描画オブジェクトプレフィックス
#define csvName "Creating_My_Rules.csv"            // CSVファイル名
#define csvName_bk "Creating_My_Rules_backup.csv"  // CSVファイル名

// 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;            // 描画するサイン サイズ
//input group ""
//input string InpFont="Arial Black";    // フォント種類
//input int InpFontsize=10;              // フォントサイズ
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);
   IndicatorSetDouble(INDICATOR_MINIMUM,0);

   //--- チャートの右境界線の値の取得。終了時に値を戻す。
   saveChartShiftSize=ChartShiftSizeGet(chart_id);

   //--- チャートの自動スクロールの状態を保存
   long value;
   if(ChartGetInteger(chart_id,CHART_AUTOSCROLL,0,value)) saveCHART_AUTOSCROLL=true;


   //--- 構造体・配列の初期化。
   StructReset(pattern,patternNow); // 限界値はpatternNow
   
   ArrayResize(main_cs,candlesToCalculate);                       // 配列ではないけど ArrayResize しないとおかしくなる
   for(int i=0; i<candlesToCalculate; i++) main_cs[i].status=0;   // main_cs[].statusのみ 0 で初期化

   // フラグのリサイズ
   ArrayResize(startValue,candlesToCalculate);
   ArrayResize(signDrawing,candlesToCalculate);


   //--- Prefix の文字列の数を調べる
   prefixLen=StringLen(Prefix);

   //--- マウスのイベント無効
   ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_w,false);

   // 初期化完了。ゼロ値を返す。
   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();

      // 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,65,80,ANCHOR_LEFT_UPPER,InpFont,InpFontsize,clrWhite);

      // モード切替ボタン作成
      ButtonCreate(chart_id,Prefix+"Mode_Button",sub_w,"陰陽 変更",100,30,80,20,clrBlack,clrWhite);
   }

   // 次の呼び出しのために 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); return;             // 陰線・陽線の変更
         case 1: Candlestick_Price_ModificationMode(sparam, dparam); return;  // ローソク足の価格の変更
         case 2: SearchForPatternMode(sparam); return;                        // ローソク足の検索・チェック
      }

      return;
   }


   //--- マウス移動イベント
   if(id==CHARTEVENT_MOUSE_MOVE)
   {

//      printf("マウスの位置 : x=%d, y=%d", (int)lparam, (int)dparam); // テスト用。残しておく。

      if((mode==1) && (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); // ローソク足の数変更ボタンの削除
         ObjectDelete(chart_id,Prefix+"File_Read");            // CSV読込ボタン削除

         //--- オブジェクトの変更
         ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"価格 変更");

         //--- オブジェクトの作成
         LowerButton();

         return;

      case 1:  // 今[価格変更]で、これから[検索]

         //--- 操作モード切替
         mode=2;

         //-- オブジェクトの削除
         ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w);
         
         //--- オブジェクトの変更
         ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"検索");
         
         //--- オブジェクトの作成
         LowerButton();

         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,140,80,20,clrWhite,clrNONE);
         ButtonCreate(chart_id,Prefix+"Sign_L",sub_w,"<-",100,110,20,20,clrBlack,clrWhite);
         ButtonCreate(chart_id,Prefix+"Sign_R",sub_w,"->",40,110,20,20,clrBlack,clrWhite);
         LabelCreate(chart_id,Prefix+"Sign_Num",sub_w,(string)signNow,CORNER_RIGHT_LOWER,65,110,ANCHOR_LEFT_UPPER,InpFont,InpFontsize,clrWhite);

         // 確認ボタン作成
         ButtonCreate(chart_id,Prefix+"Do_Search_Button",sub_w,"検索実行",100,80,80,20,clrBlack,clrWhite);

         return;

      case 2:  // 今[検索]で、これから[陰陽変更]

         //--- 操作モード切替
         mode=0;

         //--- オブジェクトの削除
         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+"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,65,80,ANCHOR_LEFT_UPPER,InpFont,InpFontsize,clrWhite);

         return;
   }
}
//+------------------------------------------------------------------+
//| ローソク足の陽線・陰線変更モードの画面
//+------------------------------------------------------------------+
void Candlestick_WB_ModificationMode(const string sparam)
{
   int find=-1; // 指定する文字列が見つかったら整数が入る変数

   //--- 画面下部のボタンを押したとき
   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に変換

      StatusChange(num);   // ローソク足の種類の変更

      CandlestickCreate(); // サブウィンドウに描画するローソク足の作成
      LowerButton();       // 画面下部のボタン作成

      return;
   }
         
   if(sparam == Prefix+"CSNum_Label") // [ローソク足増減]ボタン。設定なし。
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      return;
   }

   //--- 画面右側の[<][>]ボタンを押したとき
   if(sparam == Prefix+"CSNum_L")  // [<]ボタン
   {
      // ローソク足の本数を増やす
      if(patternNow<patternMax) patternNow++;
            
      // 陽線・陰線情報変更
      pattern[patternNow-1].status=1;
           
      // ラベルのテキスト更新
      ObjectSetString(chart_id,Prefix+"CSNum",OBJPROP_TEXT,(string)patternNow);
            
      CandlestickCreate(); // ローソク足の描画
      LowerButton();       // 画面下部のボタン作成
            
      return;
   }
   
   if(sparam == Prefix+"CSNum_R")  // [>]ボタン
   {
      // ローソク足の本数を減らす
      if(patternNow>patternMin) patternNow--;

      // 陽線・陰線情報変更
      pattern[patternNow].status=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_" があるオブジェクトを全部削除

      CandlestickCreate(); // ローソク足の描画
      LowerButton();       // 画面下部のボタン作成

      return;
   }
   
   if(sparam == Prefix+"File_Read") // [CSV読込]ボタン
   {
      // ファイルの読込
      CsvFileRead();

      //--- 再描画・再設定
      // 未使用のローソク足の確認
      for(int i=0; i<patternMax; i++)
      if(pattern[i].status==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_" があるオブジェクトを全部削除
      CandlestickCreate();                                           // ローソク足の再描画
      LowerButton();                                                 // 画面下部のボタン作成

      // ローソク足本数ラベルのテキスト更新
      ObjectSetString(chart_id,Prefix+"CSNum",OBJPROP_TEXT,(string)patternNow);

      return;
   }
}
//+------------------------------------------------------------------+
//| ローソク足の価格変更モードの画面
//+------------------------------------------------------------------+
void Candlestick_Price_ModificationMode(const string sparam, const double dparam)
{
   int find=-1; // 指定する文字列が見つかったら整数が入る変数

   //--- 画面下部の[P]ボタンを押したとき
   find=StringFind(sparam,"Lower_Button_",prefixLen);   // prefixLen の後ろから "Lower_Button_" を探す
   if(find>0)
   {
      // ローソク足の番号取得
      string str=StringSubstr(sparam,prefixLen+13); // prefixLen+"Lower_Button_" の後ろから文字列を全部取り出す
      int num=(int)StringToInteger(str);  // 文字列の数字をlongに変換してintに変換

      saveNum=num;   // クリックした[P]ボタンのローソク足の番号を保存

      // OHLC が表示されていなかったら表示、されていたら削除
      long findOBJ=ObjectGetInteger(chart_id,sparam,OBJPROP_STATE);
      if(findOBJ==1) 
      {
         OhlcLabelCreate(saveNum);                             // OHLC 描画
         ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,true); // ボタンの状態(押されるtrue / 押されてないfalse)
      }
      else
      {
         ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_w);    // オブジェクトを削除
         ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されてないfalse)
      }
            
      return;
   }


   //--- ローソク足右側の OHLC を押したとき
   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].y_open=(int)(result2-(dparam-result));
            
            if((pattern[saveNum].status<10 && pattern[saveNum].y_open > pattern[saveNum].y_close) ||                             // 陽線なのに始値が終値より上 又は
               (pattern[saveNum].status>10 && pattern[saveNum].status<20 && pattern[saveNum].y_open < pattern[saveNum].y_close)) // 陰線なのに始値が終値より下
               pattern[saveNum].y_close = pattern[saveNum].y_open;

            break;
         
         case 'H':
            pattern[saveNum].y_high=(int)(result2-(dparam-result));
            
            if(pattern[saveNum].y_high < pattern[saveNum].y_low) // 高値が安値より下だったら
               pattern[saveNum].y_low = pattern[saveNum].y_high;
            
            break;
         
         case 'L':
            pattern[saveNum].y_low=(int)(result2-(dparam-result));

            if(pattern[saveNum].y_high < pattern[saveNum].y_low) // 高値が安値より下だったら
               pattern[saveNum].y_high = pattern[saveNum].y_low;

            break;

         case 'C':
            pattern[saveNum].y_close=(int)(result2-(dparam-result));

            if((pattern[saveNum].status<10 && pattern[saveNum].y_open > pattern[saveNum].y_close) ||                             // 陽線なのに始値が終値より上 又は
               (pattern[saveNum].status>10 && pattern[saveNum].status<20 && pattern[saveNum].y_open < pattern[saveNum].y_close)) // 陰線なのに始値が終値より下
               pattern[saveNum].y_open = pattern[saveNum].y_close;
            
            break;
      }

      // 水平線削除
      ObjectDelete(chart_id,Prefix+"Line");

      // ローソク足の描画
      CandlestickCreate();

      // OHLC の描画
      OhlcLabelCreate(saveNum);

      // マウスに追尾するラインの停止
      ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_w,false);
      mouseMoveFlag=false;
         
      return;
   }
}
//+------------------------------------------------------------------+
//| 検索モードの画面
//+------------------------------------------------------------------+
void SearchForPatternMode(const string sparam)
{
   // [スクリーンショット]ボタンが押されたら
   if(sparam == Prefix+"Do_SS_Button")
   {
      // スクリーンショット保存
      ScreenShot();
      return;
   }

   // [検索実行]ボタンが押されたら
   if(sparam == Prefix+"Do_Search_Button")
   {
      // パターンを検索
      SearchForPattern();
      return;
   }

   // [保存]ボタンが押されたら CSV 出力
   if(sparam == Prefix+"File_Write")
   {
      // ファイルの作成
      CsvFileWrite();
      return;
   }

   // [画面下部]の番号ボタンを押したとき。このボタンに何か設定する予定無し。
   int find=-1;
   find=StringFind(sparam,"Lower_Button_",prefixLen);   // prefixLen の後ろから "Lower_Button_" を探す
   if(find>0)
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      return;
   }
         
   if(sparam == Prefix+"Sign_Label") // [チャート移動]ボタン。設定なし。
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      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 SearchForPattern()
{
   // チャートのローソク足の価格情報の取得
   MqlRates rates[];
   ArraySetAsSeries(rates,true); 
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,candlesToCalculate,rates);
   if(copied < 0)
   {
      printf("CopyRates取得エラー。copied = %d, error code = %d", copied, GetLastError());
      return(-1);
   }

   // 関数に渡すための価格の配列
   double RO[]; // open
   double RH[]; // high
   double RL[]; // low
   double RC[]; // close

   int limit=candlesToCalculate;
   ArrayResize(RO,limit);
   ArrayResize(RH,limit);
   ArrayResize(RL,limit);
   ArrayResize(RC,limit);

   // フラグの配列初期化
   ArrayInitialize(startValue,0);
   ArrayInitialize(signDrawing,0);


   // ①配列初期化
   ArrayInitialize(RO,0);
   ArrayInitialize(RH,0);
   ArrayInitialize(RL,0);
   ArrayInitialize(RC,0);



   // ①パターンの価格(y座標)を構造体から配列へコピー
   for(int i=0; i<patternMax; i++)
   {
      RO[i]=pattern[i].y_open;
      RH[i]=pattern[i].y_high;
      RL[i]=pattern[i].y_low;
      RC[i]=pattern[i].y_close;
   }   


   // ①自作パターンの不等号の比較結果の保存
   startValue[0]=1; // [0]は自作パターンでのみ使用。[0]=1にしないと次の関数で処理されない。
   InequalitySignResultToNum(0, 1, pattern, RO, RH, RL, RC);


   //---② メインチャートの比較結果の保存
   // ②陽線・陰線で必要なものをHLの値に変更(HLのみのチェックに対応するため)
   // .status     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(((rates[i+j].open<rates[i+j].close) && (pattern[j].status>0)  && (pattern[j].status<10)) ||   // チャート陽線でパターン陽線 又は
            ((rates[i+j].open>rates[i+j].close) && (pattern[j].status>10) && (pattern[j].status<20)) ||   // チャート陰線でパターン陰線 又は
            ((pattern[j].status>20) && (pattern[j].status<30)))                                           // 陽線・陰線どちらも可
         {
            k++;
            continue;
         }
         break;   // 該当無しはjループ終了
      }
      
      // 陽線・陰線の並び方が同じなら その部分に作成したパターンの並び方を上書きする
      if(k==patternNow)
      {
         for(int j=0; j<patternNow; j++)
            main_cs[i+j].status=pattern[j].status;
         
         startValue[i]=1; // パターンの先頭フラグを立てる
      }

      k=0; // カウンタリセット
   }

   // ②配列初期化
   ArrayInitialize(RO,0);
   ArrayInitialize(RH,0);
   ArrayInitialize(RL,0);
   ArrayInitialize(RC,0);

   // ②価格をコピー
   for(int i=0; i<limit; i++)
   {
      RO[i]=rates[i].open;
      RH[i]=rates[i].high;
      RL[i]=rates[i].low;
      RC[i]=rates[i].close;
   }

   // ②チャート側の不等号の比較結果の保存(ローソク足の数の分をチェック)
   InequalitySignResultToNum(1, candlesToCalculate-patternNow, main_cs, RO, RH, RL, RC);


   //--- ①自作パターンと②チャートの比較結果の比較
   
   // 自作パターンの比較結果の数がいくつになるか計算
   int compareNow=0;
   for(int i=patternNow; i>=patternMin; i--) compareNow = compareNow+i-1;
   
   // 比較の比較
   for(int i=1; i<candlesToCalculate-patternNow; i++) // i はチャートのローソク足の番号
   {
      for(int k=0; k<compareNow; k++) // k はチャートと自作パターンの比較結果の番号
      {
         if(!((main_cs[i].results[k][0] == pattern[0].results[k][0]) &&
              (main_cs[i].results[k][1] == pattern[0].results[k][1]) &&
              (main_cs[i].results[k][2] == pattern[0].results[k][2]) &&
              (main_cs[i].results[k][3] == pattern[0].results[k][3])))
         {
            break;
         }

         // チャートと自作パターンが同じだったら該当するローソク足の番号のフラグを立てる
         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);
         LabelCreate(chart_id,Prefix+"Pattern_Time2",sub_w,(string)signMax,CORNER_LEFT_UPPER, 70, 220, ANCHOR_CENTER, InpFont, InpFontsize, clrWhite);
         ChartRedraw();
         break;
      }
   }

   // メインチャートに描画
   ArrowCreate(chart_id,Prefix+"Sign_",sub_w,rates,InpSignArrowwCode,InpSignArrowwCode2,InpSignColor,InpSignWidth);

   return(0);
}
//+------------------------------------------------------------------+
//| ローソク足の比較の結果を数字に変換する
//+------------------------------------------------------------------+
void InequalitySignResultToNum(int start,                   // 処理を開始するローソク足の番号
                               int end,                     // 処理を終了するローソク足の番号
                               pattern_struct &structure[], // 結果を入れる構造体
                               double &open[],              // open
                               double &high[],              // high
                               double &low[],               // low
                               double &close[])             // close
{
   // 比較結果の位置番号は [csNum]。
   // R側のローソク足の位置番号は [i+csNum]。
   // L側のローソク足の位置番号は [j+csNum]。
   // LRの比較する位置番号は左上が直角二等辺三角形の逆ピラミッド型になる。

   for(int csNum=start; csNum<end; csNum++) // 処理するローソク足のループ。csNum は処理したいローソク足の番号
   {
      if(startValue[csNum]>0) // パターンの先頭フラグチェック
      {
         for(int i=0, index=0; i<patternNow; i++) // [i] はカウンタとして使用。処理するローソク足は [i+csNum]
         {
            for(int j=i+1; j<patternNow; j++) //  j は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側の値

                  // .status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ

                  // L側から確認
                  switch(structure[j+csNum].status)
                  {
                     //--- L OHLCのとき
                     case 1:
                     case 11:
                        switch(structure[i+csNum].status)
                        {
                           // R OHLC -> LRそのまま
                           case 1:
                           case 11:
                              switch(ohlc)
                              {
                                 case 0: L= open[j+csNum]; break;
                                 case 1: L= high[j+csNum]; break;
                                 case 2: L=  low[j+csNum]; break;
                                 case 3: L=close[j+csNum]; 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=high[i+csNum]; break;
                                 case 2: L= low[i+csNum]; 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=high[i+csNum]; 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=low[i+csNum]; break;
                              }
                              SwapTheLR=true;
                              type='A';
                              break;
                        }
                        break;


                     //--- L HLのとき
                     case 2:
                     case 12:
                     case 22:
                        switch(structure[i+csNum].status)
                        {
                           // 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=high[j+csNum]; break;
                                 case 2: L= low[j+csNum]; break;
                              }
                              SwapTheLR=false;

                              if(structure[i+csNum].status==1 || structure[i+csNum].status==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=high[i+csNum]; 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= low[i+csNum]; 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=high[j+csNum]; break;
                        }
                        SwapTheLR=false;
                     
                        switch(structure[i+csNum].status)
                        {
                           // 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=  low[j+csNum]; break;
                        }
                        SwapTheLR=false;

                        switch(structure[i+csNum].status)
                        {
                           // 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= open[j+csNum];
                     RH= high[j+csNum];
                     RL=  low[j+csNum];
                     RC=close[j+csNum];
                  }
                  else
                  {
                     // そのまま
                     RO= open[i+csNum];
                     RH= high[i+csNum];
                     RL=  low[i+csNum];
                     RC=close[i+csNum];
                  }


                  //--- 不等号で比較
                  // 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]=1; // high 以上
                        else if(L<=RH && L>=RL)   structure[csNum].results[index][ohlc]=6; // high 以下, low 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // low 以下
                        break;

                     case 'C': // Hのみ
                        if(L>=RH)                 structure[csNum].results[index][ohlc]=1; // high 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // high 以下
                        break;

                     case 'D': // Lのみ
                        if(L>=RL)                 structure[csNum].results[index][ohlc]=1; // low 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // low 以下
                        break;
                  }

               } // ここまでが int ohlc のループ

               index++; // int ohlcのループが終わったら保存場所を一つずらす
            }
         }
      }
   }

}
//+------------------------------------------------------------------+
//| ローソク足の種類の変更
//| pattern[].status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ
//+------------------------------------------------------------------+
void StatusChange(int num)
{

   if(pattern[num].status==4 || pattern[num].status==14)
   {
      if(pattern[num].status==4) pattern[num].status=11; // 4 の次は 11
      else pattern[num].status=22;                       // 14 の次は 22

      // 始値・終値の入替
      int temp=0;
      temp=pattern[num].y_open;
      pattern[num].y_open=pattern[num].y_close;
      pattern[num].y_close=temp;
   }
   else if(pattern[num].status==24) pattern[num].status=1;  // 24 の次は 1
   else pattern[num].status++;

}
//+------------------------------------------------------------------+
//| ローソク足を描画
//+------------------------------------------------------------------+
void CandlestickCreate()
{
   int y;
   int width=10;  // 幅(x軸)
   int height;    // 高さ(y軸)
   color clr;

   for(int i=0; i<patternNow; i++)
   {
      //--- 色の設定
      if(pattern[i].status<10)      clr=InpCsColorW;  // 10 より下なら陽線
      else if(pattern[i].status<20) clr=InpCsColorB;  // 20 より下なら陰線
      else                          clr=InpCsColorHL; // それ以外はどちらでも可

      //--- 実体

      string name = Prefix+"CS_Body_"+IntegerToString(i); // 実体の名前

      // 陽線OHLC・陰線OHLCのとき実体を描画
      if(pattern[i].status==1 || pattern[i].status==11)
      {
         // 始値と終値の位置変更
         if(pattern[i].status==11) // 陰線OHLC
         {
            y = pattern[i].y_open;                             // y(価格軸、ピクセル)
            height = pattern[i].y_open - pattern[i].y_close;   // y(ラベルの高さ)
         }
         else // 陽線OHLC
         {
            y = pattern[i].y_close;                            // y(価格軸、ピクセル)
            height = pattern[i].y_close - pattern[i].y_open;   // y(ラベルの高さ)
         }

         // 実体描画
         RectLabelCreate(chart_id,name,sub_w,pattern[i].x+width,y,width,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((pattern[i].status==3 || pattern[i].status==4) ||
         (pattern[i].status==13 || pattern[i].status==14) ||
         (pattern[i].status==23 || pattern[i].status==24))
      {
         height = 30;   // ラベルの高さ

         // H か L か
         if(pattern[i].status==3 || pattern[i].status==13 || pattern[i].status==23) // high
         {
            y = pattern[i].y_high;   // y(価格軸、ピクセル)

            // ラベル作成
            LabelCreate(chart_id,name2+"_Char",sub_w,"H",CORNER_RIGHT_LOWER,pattern[i].x+10,y-30,ANCHOR_LEFT_UPPER,InpFont,12,clrWhite,0,true); // 最後の true は背景表示にする
         }
         else // low
         {
            y = pattern[i].y_low+30;   // ラベルの高さ分上にずらす(プラスする)

            // ラベル作成  yは30+文字の大きさ。適当。
            LabelCreate(chart_id,name2+"_Char",sub_w,"L",CORNER_RIGHT_LOWER,pattern[i].x+10,y+30,ANCHOR_LEFT_UPPER,InpFont,12,clrWhite,0,true); // 最後の true は背景表示にする
         }
      }
      else
      {
         ObjectDelete(chart_id,name2+"_Char"); // H・Lの文字のオブジェクト削除
         
         y = pattern[i].y_high;                          // y(価格軸、ピクセル)
         height = pattern[i].y_high - pattern[i].y_low;  // ラベルの高さ
      }

      // ヒゲ描画
      RectLabelCreate(chart_id,name2,sub_w,pattern[i].x+(width/2),y,2,height,clr,BORDER_FLAT,CORNER_RIGHT_LOWER,clr,STYLE_SOLID,1,true,false,true,0);
   }
   
   //--- チャートを再描画
   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
      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=0;
   y=(pattern[num].y_high-(pattern[num].y_high-pattern[num].y_low)/2)+40;

   for(int i=0; i<4; i++)
   {
      // 表示しないものは continue。それ以外は次へ。
      switch(pattern[num].status)
      {
         // 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(pattern[num].status>10 && pattern[num].status<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,0);
   }
   
   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
//| ラベル作成
//+------------------------------------------------------------------+
void 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,   // フォントの色
                 double angle=0,    // 角度
                 bool back=false)   // 背景表示
{

   ResetLastError(); // エラー値をリセットする
   if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0))   // ラベルを作成する
   {
      Print(__FUNCTION__,": failed to create the button! Error code = ",GetLastError());
      return;
   }

   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,0);              // チャートのマウスクリックのイベントを受信するための優先順位を設定する
   ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);            // テキストの角度

   // 再描画
   ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| メインチャートに描画
//+------------------------------------------------------------------+
void ArrowCreate(const long chart_ID,  // チャート識別子
                 string name,          // 名前
                 const int sub_window, // サブウィンドウ番号
                 MqlRates &rates[],    // アンカーポイントの価格と時刻
                 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,rates[i].time,rates[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,rates[i].time,rates[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==2) // 検索モードのとき色変更
   {
      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(pattern[i].status)
         {
            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 if(mode==1) text="P";
      else text=IntegerToString(i);
   
      ButtonCreate(chart_id,name,sub_w,text,pattern[i].x+15,30,20,20,clr,back_clr);
   }

   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
//| ボタン作成      マウスクリックの優先度は 100
//+------------------------------------------------------------------+
void 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;
   }

   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,100);            // チャートのマウスクリックのイベントを受信するための優先順位を設定する

   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
//| 水平線を描画
//+------------------------------------------------------------------+
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)にする

   ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| パターンのあるところまで画面移動
//+------------------------------------------------------------------+
int ChartMove(int num)
{
   int shift=num;

   // チャートの自動スクロールを無効
   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;
   time=iTime(Symbol(),PERIOD_CURRENT,shift);

   string text, text2;
   text= (string)num + "/"+ (string)signMax + "の時刻";
   text2= TimeToString(time);

   // ラベル作成
   LabelCreate(chart_id,Prefix+"Pattern_Time",sub_w,text,CORNER_LEFT_UPPER, 70, 200, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   LabelCreate(chart_id,Prefix+"Pattern_Time2",sub_w,text2,CORNER_LEFT_UPPER, 70, 220, ANCHOR_CENTER, "Arial Black", 10, clrWhite);


   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+(int)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);

   // タイムフレーム(時間軸)
   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);

   // 検索期間
   datetime timeFirst, timeLast;
   timeFirst=iTime(Symbol(),PERIOD_CURRENT,0);
   timeLast=iTime(Symbol(),PERIOD_CURRENT,candlesToCalculate);

   string textFirst, textLast;
   textFirst= TimeToString(timeFirst);
   textLast= TimeToString(timeLast);

   LabelCreate(chart_id,Prefix+"TimeLabel",sub_w,"検索期間",CORNER_LEFT_UPPER, 70, 100, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   LabelCreate(chart_id,Prefix+"TimeFirst",sub_w,textFirst,CORNER_LEFT_UPPER, 70, 120, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   LabelCreate(chart_id,Prefix+"Time~",sub_w,"~",CORNER_LEFT_UPPER, 70, 140, ANCHOR_CENTER, "Arial Black", 10, clrWhite, 90); // ~を90度回転して表示
   LabelCreate(chart_id,Prefix+"TimeLast",sub_w,textLast,CORNER_LEFT_UPPER, 70, 160, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
}
//+------------------------------------------------------------------+
//| ファイルの保存
//+------------------------------------------------------------------+
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, pattern[i].status, pattern[i].y_open, pattern[i].y_high, pattern[i].y_low, pattern[i].y_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列目のデータは取得せず移動のみ)
         pattern[i].status = (int)FileReadNumber(handle); // 陽線・陰線情報
         pattern[i].y_open = (int)FileReadNumber(handle); // open
         pattern[i].y_high = (int)FileReadNumber(handle); // high
         pattern[i].y_low  = (int)FileReadNumber(handle); // low
         pattern[i].y_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 -1;
}
//+------------------------------------------------------------------+
//| 構造体の初期設定
//+------------------------------------------------------------------+
void StructReset(pattern_struct &structure[], int now)
{
   // xの200は画面右側にボタンを配置するため
   // yの50は画面下側にボタンを配置するため
   // .status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 10=HL, 11=陰線, 12=陰線HL, 13=陰線Lのみ

   // 初期値を代入
   for(int i=0; i<patternMax; i++)
   {
      if(i<now) structure[i].status=1; // 使用する分のみ 1 を設定
      else structure[i].status=0;      // 使用しない分は 0
      
      structure[i].x=200+(i*40);    // x軸

      structure[i].y_open=50+30;    // y軸 open
      structure[i].y_high=50+75;    // y軸 high
      structure[i].y_low=50+15;     // y軸 low
      structure[i].y_close=50+60;   // y軸 close
   }
}
//+------------------------------------------------------------------+
//| この指標のチャートウィンドウの番号を返す(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);
}
//+------------------------------------------------------------------+


それでは良い一日を!

Creating_My_Rules.mq5 (Ver.1.01)

Creating_My_Rules.mq5 で、高値のみと安値のみを検索できるように改良しました。比較の式ですが、以前は組み合わせが4通りだったものが16通りになったのもあり書き方を変更しました。switch()だらけになってますが、if()だらけよりはいいかなと思ってます。

ローソク足の種類の追加


ローソク足の状態の値を変更しているため、前回の Creating_My_Rules で保存したCSVは読み込んでもきちんと動作しないので[CSV読込]しないでください。前回のCSVを使用したい場合はエクセル等で下記の赤丸の部分を該当する番号に変更してください。

赤丸の中を変更

[前回]
0=無し, 1=陽線, 2=陽線HL, 3=HL, 4=陰線, 5=陰線HL

[今回]
0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ,
11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ,
22=HL, 23=Hのみ, 24=Lのみ



ソースコードを下記に公開するので興味がある方はご自由にお使いください。

//+------------------------------------------------------------------+
//|                                            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.01"
#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 status;  // 0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ

   int x;         // x軸
   int y_open;    // y軸 open。価格ではなくy軸としてなのでint型
   int y_high;    // y軸 high
   int y_low;     // y軸 low
   int y_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 main_cs[];     // メインチャート用。OnInit()でリサイズ。

// グローバル変数
long chart_id=0;  // チャートID
int sub_window=1; // サブウィンドウの番号

int patternNow=3;          // 作成するパターンのローソク足の数
const int patternMin=2;    // 作成するパターンのローソク足の最小値
const int patternMax=20;   // 作成するパターンのローソク足の最大値

int mode=0;                   // 作業切り替えボタンの状態
char saveOHLC=-1;             // OHLCのどれを選択しているか保存
int saveNum=-1;               // クリックしたローソク足の番号
double saveChartShiftSize=0;  // チャート右境界線の値の保存

int compareLR[];              // チャートとパターンの陽線・陰線の並び方の比較。同じときにフラグをたてる。
int compareNow=0;             // チャートとパターンの陽線・陰線の並び方の比較結果の数。for()の条件に使用。

int startValue[];             // 関数で処理するときにパターンの先頭だけを処理するためのフラグ

int signDrawing[];   // サインを描画するフラグ
int signNow=0;       // 今のサインの位置
int signMax=0;       // 見つかったサインの総数
const int signMin=0; // 最小の数。0で固定

// フラグ
bool mouseMoveFlag=false;        // マウスの位置情報 取得フラグ
bool saveCHART_AUTOSCROLL=false; // 起動時のチャートの自動スクロールの状態を保存

// マクロ代入
#define Prefix "MY_Rules_"                // 描画オブジェクトプレフィックス
#define csvName "Creating_My_Rules.csv"   // CSVファイル名

// 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;            // 描画するサイン サイズ
//input group ""
//input string InpFont="Arial Black";    // フォント種類
//input int InpFontsize=10;              // フォントサイズ
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_window = window; // サブウィンドウの値の代入

   // 構造体の初期化。初期化の限界値は patternNow で設定。
   structReset(pattern,patternNow);
   
   ArrayResize(main_cs,candlesToCalculate);                       // 配列ではないけど ArrayResize しないとおかしくなる
   for(int i=0; i<candlesToCalculate; i++) main_cs[i].status=0;   // main_cs[].statusのみ初期化


   ArrayResize(startValue,candlesToCalculate);
   ArrayInitialize(startValue,0);

   // 自作パターンの比較結果の数がいくつになるか
   int temp=0;
   for(int i=patternNow; i>=patternMin; i--) temp=temp+i-1;
   compareNow=temp;
   
   // サブウィンドウの最大値と最小値を設定する
   IndicatorSetDouble(INDICATOR_MAXIMUM,400);
   IndicatorSetDouble(INDICATOR_MINIMUM,0);
   
   // マウスのイベント無効
   ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_window,false);

   // チャートの右境界線の値の取得。終了時に値を戻す。
   saveChartShiftSize=ChartShiftSizeGet(chart_id);

   // チャートの自動スクロールの状態を保存
   long value;
   if(ChartGetInteger(chart_id,CHART_AUTOSCROLL,0,value))
      saveCHART_AUTOSCROLL=true;
   
   // 初期化完了。ゼロ値を返す。
   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)
   {
      // 配列準備
      ArrayResize(signDrawing,candlesToCalculate); // signDrawing[変数名]で宣言できないためここでリサイズ
      ArrayInitialize(signDrawing,0);              // 初期化

      // 通貨ペア・時間足のラベル作成
      info();
 
      // サブウィンドウに描画するローソク足の作成
      candlestickCreate();
   
      // 画面下部のボタン設定・作成
      underButton();

      // CSV読込ボタン作成
      ButtonCreate(100,170,80,20,Prefix+"file_read","CSV読込",clrBlack,clrWhite);

      // ローソク足の数変更ボタン作成
      ButtonCreate(100,110,80,20,Prefix+"CSB_label","ローソク足増減",clrWhite,clrNONE);
      ButtonCreate(100,80,20,20,Prefix+"CSB_L","<-",clrBlack,clrWhite);
      ButtonCreate(40,80,20,20,Prefix+"CSB_R","->",clrBlack,clrWhite);
      LabelCreate(65,80,Prefix+"CSB_Num",(string)patternNow,clrWhite); // ローソク足の本数表示

      // モード切替ボタン作成
      ButtonCreate(100, 30, 80, 20, Prefix+"M_Button", "陰陽 変更", clrBlack, clrWhite);
   }

   // 次の呼び出しのために 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+"M_Button")
      {
         OperationalModesChange(sparam); // 操作モードの変更
         
         return;
      }

      switch(mode)
      {
         case 0: Candlestick_WB_ModificationMode(sparam); return;             // 陰線・陽線の変更
         case 1: Candlestick_Price_ModificationMode(sparam, dparam); return;  // ローソク足の価格の変更
         case 2: SearchForPatternMode(sparam); return;                        // ローソク足の検索・チェック
      }

      return;
   }


   //--- マウス移動イベント
   if(id==CHARTEVENT_MOUSE_MOVE)
   {

//      printf("マウスの位置 : x=%d, y=%d", (int)lparam, (int)dparam); // テスト用。残しておく。

      if((mode==1) && (mouseMoveFlag==true))
      {
         datetime time_x;  // ChartXYToTimePrice を使用するのに必要。取得したx軸の値は使わない。
         double price_y;   // 価格をY軸に変更

         // 価格からy軸に変更
         ChartXYToTimePrice(chart_id,(int)lparam,(int)dparam,sub_window,time_x,price_y);

         // 水平線描画 Y軸(価格)を渡す
         CreateLine(Prefix+"line", price_y);

         return;
      }

      return;
   }

}
//+------------------------------------------------------------------+
// 操作モード変更
//+------------------------------------------------------------------+
void OperationalModesChange(const string sparam)
{
   switch(mode)
   {
      case 0:  // 今[陰陽変更]で、これから[価格変更]
         mode=1;

         // ローソク足の数変更ボタンの削除
         ObjectsDeleteAll(chart_id,Prefix+"CSB_",sub_window);  // 余分なオブジェクトを削除
         ObjectDelete(chart_id,Prefix+"file_read");            // CSV読込ボタン削除

         ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"価格 変更");
         underButton();

         return;

      case 1:  // 今[価格変更]で、これから[検索]
         mode=2;
      
         ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_window); // 余分なオブジェクトを削除
         ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"検索");
         underButton();

         ButtonCreate(100,230,80,20,Prefix+"SS_Button","スクリーンショット",clrBlack,clrWhite); // スクリーンショットボタン
         ButtonCreate(100,200,80,20,Prefix+"file_write","CSV保存",clrBlack,clrWhite);  // CSVファイル保存ボタン

         // チャート移動ボタン
         ButtonCreate(100,140,80,20,Prefix+"sign_label","チャート移動",clrWhite,clrNONE);
         ButtonCreate(100,110,20,20,Prefix+"CSB_L","<-",clrBlack,clrWhite);
         ButtonCreate(40,110,20,20,Prefix+"CSB_R","->",clrBlack,clrWhite);
         LabelCreate(65,110,Prefix+"sign_Num",(string)signNow,clrWhite);

         ButtonCreate(100,80,80,20,Prefix+"C_Button","検索実行",clrBlack,clrWhite);    // 確認ボタン作成

         return;

      case 2:  // 今[検索]で、これから[陰陽変更]
         mode=0;
         ObjectDelete(chart_id,Prefix+"C_Button");    // 上記の確認ボタンを削除
         ObjectDelete(chart_id,Prefix+"SS_Button");   // 上記の確認ボタンを削除
         ObjectDelete(chart_id,Prefix+"file_write");  // CSV保存ボタン削除
         ObjectDelete(chart_id,Prefix+"sign_Num");    // パターン該当数削除
         ObjectDelete(chart_id,Prefix+"sign_label");  // チャート移動見出し削除
         ObjectSetString(chart_id,sparam,OBJPROP_TEXT,"陰陽 変更");
         underButton();

         // ローソク足の数変更ボタン
         ButtonCreate(100,110,80,20,Prefix+"CSB_label","ローソク足増減",clrWhite,clrNONE);
         ButtonCreate(100,80,20,20,Prefix+"CSB_L","<-",clrBlack,clrWhite);
         ButtonCreate(40,80,20,20,Prefix+"CSB_R","->",clrBlack,clrWhite);

         // CSV読込ボタン作成
         ButtonCreate(100,170,80,20,Prefix+"file_read","CSV読込",clrBlack,clrWhite);

         // ローソク足の本数表示
         LabelCreate(65,80,Prefix+"CSB_Num",(string)patternNow,clrWhite);

         return;
   }
}
//+------------------------------------------------------------------+
// ローソク足の陽線・陰線変更モードの画面
//+------------------------------------------------------------------+
void Candlestick_WB_ModificationMode(const string sparam)
{
   int find=-1; // 指定する文字列が見つかったら整数が入る変数

   //--- 画面下部の[B][W][HL]ボタンを押したとき
   find=StringFind(sparam,"Button",12);   // 12文字目から Button を探す
   if(find>0)
   {
      // 何番目のローソク足か確認
      string str=StringSubstr(sparam,19); // 19文字目から文字列の数字を取り出す
      int num=(int)StringToInteger(str);  // 文字列の数字をlongに変換してintに変換

      statusChange(num);   // ローソク足の種類の変更

      candlestickCreate(); // サブウィンドウに描画するローソク足の作成
      underButton();       // 画面下部のボタン作成

      return;
   }
         
   if(sparam == Prefix+"CSB_label") // [ローソク足増減]ボタン。設定なし。
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      return;
   }

   //--- 画面右側の[<][>]ボタンを押したとき
   if(sparam == Prefix+"CSB_L")  // [<]ボタン
   {
      // ローソク足の本数を増やす
      if(patternNow<patternMax) patternNow++;
            
      // 陽線・陰線情報変更
      pattern[patternNow-1].status=1;
           
      // ラベルのテキスト更新
      ObjectSetString(chart_id,Prefix+"CSB_Num",OBJPROP_TEXT,(string)patternNow);
            
      candlestickCreate(); // ローソク足の描画
      underButton();       // 画面下部のボタン作成
            
      // 自作パターンの比較結果の数がいくつになるか
      int temp=0;
      for(int i=patternNow; i>=patternMin; i--) temp=temp+i-1;
      compareNow=temp;
      ArrayResize(compareLR,compareNow);

      return;
   }
   
   if(sparam == Prefix+"CSB_R")  // [>]ボタン
   {
      // ローソク足の本数を減らす
      if(patternNow>patternMin) patternNow--;

      // 陽線・陰線情報変更
      pattern[patternNow].status=0;

      // ラベルのテキスト更新
      ObjectSetString(chart_id,Prefix+"CSB_Num",OBJPROP_TEXT,(string)patternNow);

      // オブジェクト削除・描画
      ObjectsDeleteAll(chart_id,Prefix+"cs_",sub_window);         // 名前に Prefix+"cs_" があるオブジェクトを全部削除
      ObjectsDeleteAll(chart_id,Prefix+"cb_Button_",sub_window);  // 名前に Prefix+"cb_Button_" があるオブジェクトを全部削除

      candlestickCreate(); // ローソク足の描画
      underButton();       // 画面下部のボタン作成

      // 自作パターンの比較結果の数がいくつになるか
      int temp=0;
      for(int i=patternNow; i>=patternMin; i--) temp=temp+i-1;
      compareNow=temp;
      ArrayResize(compareLR,compareNow);

      return;
   }
   
   if(sparam == Prefix+"file_read") // [CSV読込]ボタン
   {
      // ファイルの読込
      csvFileRead();

      //--- 再描画・再設定
      // 未使用のローソク足の確認
      for(int i=0; i<patternMax; i++)
      if(pattern[i].status==0)
      {
         patternNow=i;
         break;
      }

      // 自作パターンの比較結果の数がいくつになるか
      int temp=0;
      for(int i=patternNow; i>=patternMin; i--) temp=temp+i-1;
      compareNow=temp;
      ArrayResize(compareLR,compareNow);

      // オブジェクトの削除と描画
      ObjectsDeleteAll(chart_id,Prefix+"cs_",sub_window);         // 名前に Prefix+"cs_" があるオブジェクトを全部削除
      ObjectsDeleteAll(chart_id,Prefix+"cb_Button_",sub_window);  // 名前に Prefix+"cb_Button_" があるオブジェクトを全部削除
      candlestickCreate();                                        // ローソク足の再描画
      underButton();                                              // 画面下部のボタン作成

      // ローソク足本数ラベルのテキスト更新
      ObjectSetString(chart_id,Prefix+"CSB_Num",OBJPROP_TEXT,(string)patternNow);

      return;
   }
}
//+------------------------------------------------------------------+
// ローソク足の価格変更モードの画面
//+------------------------------------------------------------------+
void Candlestick_Price_ModificationMode(const string sparam, const double dparam)
{
   int find=-1; // 指定する文字列が見つかったら整数が入る変数

   //--- 画面下部の[P]ボタンを押したとき
   find=StringFind(sparam,"Button",12);   // 12文字目から Button を探す
   if(find>0)
   {
      // 何番目のローソク足か確認
      string str=StringSubstr(sparam,19); // 19文字目から文字列の数字を取り出す
      int num=(int)StringToInteger(str);  // 文字列の数字をlongに変換してintに変換

      saveNum=num;   // クリックしたローソク足の番号を保存

      // OHLC が表示されていなかったら表示、されていたら削除
      long findOBJ=ObjectGetInteger(chart_id,sparam,OBJPROP_STATE);
      if(findOBJ==1) 
      {
         ohlcButtonCreate(saveNum);                               // OHLC 描画
         ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,true);    // ボタンの状態(押されるtrue / 押されてないfalse)
      }
      else
      {
         ObjectsDeleteAll(chart_id,Prefix+"OHLC_",sub_window);    // 余分なオブジェクトを削除
         ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されてないfalse)
      }
            
      return;
   }


   //--- ローソク足右側の OHLC を押したとき
   find=StringFind(sparam,"OHLC_R_",9);   // 12文字目から OHLC_R_ を探す
   if(find>0)
   {
      string str=StringSubstr(sparam,18); // 16文字目から文字列の数字を取り出す
      int num=(int)StringToInteger(str);  // 文字列の数字をlongに変換してintに変換

      // OHLC のどれを押したか
      int findOHLC=-1;
      string strOHLC;
            
      findOHLC=StringFind(sparam,"O",16); // 16文字目から O を探す
      if(findOHLC>0) strOHLC="O";         // 見つかったらその文字を代入

      findOHLC=StringFind(sparam,"H",16);
      if(findOHLC>0) strOHLC="H";
            
      findOHLC=StringFind(sparam,"L",16);
      if(findOHLC>0) strOHLC="L";

      findOHLC=StringFind(sparam,"C",16);
      if(findOHLC>0) strOHLC="C";
   
      // OHLCの選んだ文字を残して他を消す。16文字目に strOHLC の無いオブジェクトを削除 (何番目のローソク足か, 残したい文字, 何文字目から検索するか)
      ohlcDelete(num,strOHLC,16,0); // 最後の値は右側=0, 左側=1

      // 文字列をキャラに変換
      saveOHLC=strToChar(strOHLC);

      // マウスに追尾するラインを作成
      if(!mouseMoveFlag)
      {
         ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_window,true);
         mouseMoveFlag=true;
      }                  

      return;
   }


   // 価格変更の水平線をクリックしたとき
   if(sparam == Prefix+"line")
   {
      // 指標サブウィンドウの上部フレームとメインチャートウィンドウの上部フレームとの縦 Y 軸の差(ピクセル単位)
      long result=-1; 
      //--- プロパティ値を受け取る 
      ChartGetInteger(chart_id,CHART_WINDOW_YDISTANCE,sub_window,result);

      // チャートの高さ(ピクセル単位)
      long result2=-1; 
      //--- プロパティ値を受け取る 
      ChartGetInteger(chart_id,CHART_HEIGHT_IN_PIXELS,sub_window,result2);

      // 価格の変更と、OHLC の位置の確認。反転していれば同じ値にする
      switch(saveOHLC)
      {
         case 'O':
            pattern[saveNum].y_open=(int)(result2-(dparam-result));
            
            if((pattern[saveNum].status<10 && pattern[saveNum].y_open > pattern[saveNum].y_close) ||                             // 陽線なのに始値が終値より上 又は
               (pattern[saveNum].status>10 && pattern[saveNum].status<20 && pattern[saveNum].y_open < pattern[saveNum].y_close)) // 陰線なのに始値が終値より下
               pattern[saveNum].y_close = pattern[saveNum].y_open;

            break;
         
         case 'H':
            pattern[saveNum].y_high=(int)(result2-(dparam-result));
            
            if(pattern[saveNum].y_high < pattern[saveNum].y_low) // 高値が安値より下だったら
               pattern[saveNum].y_low = pattern[saveNum].y_high;
            
            break;
         
         case 'L':
            pattern[saveNum].y_low=(int)(result2-(dparam-result));

            if(pattern[saveNum].y_high < pattern[saveNum].y_low) // 高値が安値より下だったら
               pattern[saveNum].y_high = pattern[saveNum].y_low;

            break;

         case 'C':
            pattern[saveNum].y_close=(int)(result2-(dparam-result));

            if((pattern[saveNum].status<10 && pattern[saveNum].y_open > pattern[saveNum].y_close) ||                             // 陽線なのに始値が終値より上 又は
               (pattern[saveNum].status>10 && pattern[saveNum].status<20 && pattern[saveNum].y_open < pattern[saveNum].y_close)) // 陰線なのに始値が終値より下
               pattern[saveNum].y_open = pattern[saveNum].y_close;
            
            break;
      }

      // 水平線削除
      ObjectDelete(chart_id,Prefix+"line");

      // ローソク足の描画
      candlestickCreate();

      // OHLC の描画
      ohlcButtonCreate(saveNum);

      // フラグ回収
      ChartSetInteger(chart_id,CHART_EVENT_MOUSE_MOVE,sub_window,false);
      mouseMoveFlag=false;
         
      return;
   }
}
//+------------------------------------------------------------------+
// 検索モードの画面
//+------------------------------------------------------------------+
void SearchForPatternMode(const string sparam)
{
   // [スクリーンショット]ボタンが押されたら
   if(sparam == Prefix+"SS_Button")
   {
      // スクリーンショット保存
      ScreenShot();
      return;
   }

   // [検索実行]ボタンが押されたら
   if(sparam == Prefix+"C_Button")
   {
      // パターンを検索
      searchForPattern();
      return;
   }

   // [保存]ボタンが押されたら CSV 出力
   if(sparam == Prefix+"file_write")
   {
      // ファイルの作成
      csvFileWrite();
      return;
   }

   // [画面下部]の番号ボタンを押したとき。このボタンに何か設定する予定無し。
   int find=-1;
   find=StringFind(sparam,"Button",12);   // 12文字目から Button を探す
   if(find>0)
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      return;
   }
         
   if(sparam == Prefix+"sign_label") // [チャート移動]ボタン。設定なし。
   {
      // ボタンが押されていない状態に戻す
      ObjectSetInteger(chart_id,sparam,OBJPROP_STATE,false);   // ボタンの状態(押されるtrue / 押されていないfalse)
      ChartRedraw();
      return;
   }


   // 該当するパターンが表示されるように画面移動
   // 画面右側の[<][>]ボタンを押したとき
   if(sparam == Prefix+"CSB_L") // [<]ボタン
   {
      // 表示するローソク足の位置番号を増やす
      if(signNow<signMax) signNow++;

      // 表示するローソク足のテキスト更新
      ObjectSetString(chart_id,Prefix+"sign_Num",OBJPROP_TEXT,(string)signNow);
            
      // 画面移動
      chartMove(signNow);

      return;
   }
   if(sparam == Prefix+"CSB_R") // [>]ボタン
   {
      // 表示するローソク足の位置番号を減らす
      if(signNow>signMin) signNow--;

      // 表示するローソク足のテキスト更新
      ObjectSetString(chart_id,Prefix+"sign_Num",OBJPROP_TEXT,(string)signNow);

      // 画面移動
      chartMove(signNow);

      return;
   }

}
//+------------------------------------------------------------------+
// パターンを検索
//+------------------------------------------------------------------+
int searchForPattern()
{
   // チャートのローソク足の価格情報の取得
   MqlRates rates[];
   ArraySetAsSeries(rates,true); 
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,candlesToCalculate,rates);
   if(copied < 0)
   {
      printf("CopyRates取得エラー。copied = %d, error code = %d", copied, GetLastError());
      return(-1);
   }

   // 関数に渡すための価格の配列
   double RO[]; // open
   double RH[]; // high
   double RL[]; // low
   double RC[]; // close

   int limit=candlesToCalculate;
   ArrayResize(RO,limit);
   ArrayResize(RH,limit);
   ArrayResize(RL,limit);
   ArrayResize(RC,limit);


   // ①配列初期化
   ArrayInitialize(RO,0);
   ArrayInitialize(RH,0);
   ArrayInitialize(RL,0);
   ArrayInitialize(RC,0);

   // ①補助情報初期化
   ArrayResize(compareLR,candlesToCalculate);
   ArrayInitialize(compareLR,0);

   // ①描画フラグ初期化
   ArrayInitialize(signDrawing,0);


   // ①パターンの価格(y座標)を構造体から配列へコピー
   for(int i=0; i<patternMax; i++)
   {
      RO[i]=pattern[i].y_open;
      RH[i]=pattern[i].y_high;
      RL[i]=pattern[i].y_low;
      RC[i]=pattern[i].y_close;
   }   


   // ①自作パターンの不等号の比較結果の保存
   startValue[0]=1; // [0]は自作パターンでのみ使用。[0]=1にしないと次の関数で処理されない。
   inequalitySignResultToNum(0, 1, pattern, RO, RH, RL, RC);


   //---② メインチャートの比較結果の保存
   // ②陽線・陰線で必要なものをHLの値に変更(HLのみのチェックに対応するため)
   // .status     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(((rates[i+j].open<rates[i+j].close) && (pattern[j].status>0)  && (pattern[j].status<10)) ||   // チャート陽線でパターン陽線 又は
            ((rates[i+j].open>rates[i+j].close) && (pattern[j].status>10) && (pattern[j].status<20)) ||   // チャート陰線でパターン陰線 又は
            ((pattern[j].status>20) && (pattern[j].status<30)))                                           // 陽線・陰線どちらも可
         {
            k++;
            continue;
         }
         break;   // 該当無しはjループ終了
      }
      
      // 陽線・陰線の並び方が同じなら その部分に作成したパターンの並び方を上書きする
      if(k==patternNow)
      {
         for(int j=0; j<patternNow; j++)
            main_cs[i+j].status=pattern[j].status;
         
         startValue[i]=1; // パターンの先頭フラグを立てる
      }

      k=0; // カウンタリセット
   }

   // ②配列初期化
   ArrayInitialize(RO,0);
   ArrayInitialize(RH,0);
   ArrayInitialize(RL,0);
   ArrayInitialize(RC,0);

   // ②価格をコピー
   for(int i=0; i<limit; i++)
   {
      RO[i]=rates[i].open;
      RH[i]=rates[i].high;
      RL[i]=rates[i].low;
      RC[i]=rates[i].close;
   }

   // ②チャート側の不等号の比較結果の保存(ローソク足の数の分をチェック)
   inequalitySignResultToNum(1, candlesToCalculate-patternNow, main_cs, RO, RH, RL, RC);


   //--- ①自作パターンと②チャートの比較結果の比較
   for(int i=1; i<candlesToCalculate-patternNow; i++) // i はチャートのローソク足の番号
   {
      for(int k=0; k<compareNow; k++) // k はチャートと自作パターンの比較結果の番号
      {
         if(!((main_cs[i].results[k][0] == pattern[0].results[k][0]) &&
              (main_cs[i].results[k][1] == pattern[0].results[k][1]) &&
              (main_cs[i].results[k][2] == pattern[0].results[k][2]) &&
              (main_cs[i].results[k][3] == pattern[0].results[k][3])))
         {
            break;
         }

         // チャートと自作パターンが同じだったら該当するローソク足の番号のフラグを立てる
         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;

         // 左下に表示
         CreateLabel(Prefix+"Pattern_Time","パターン該当数",CORNER_LEFT_UPPER, 70, 200, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
         CreateLabel(Prefix+"Pattern_Time2",(string)signMax,CORNER_LEFT_UPPER, 70, 220, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
         ChartRedraw();
         break;
      }
   }

   // メインチャートに描画
   ArrowCreate(Prefix+"Sign_", rates);

   return(0);
}
//+------------------------------------------------------------------+
// ローソク足の比較の結果を数字に変換する
//+------------------------------------------------------------------+
void inequalitySignResultToNum(int start,                   // 処理を開始するローソク足の番号
                               int end,                     // 処理を終了するローソク足の番号
                               pattern_struct &structure[], // 結果を入れる構造体
                               double &open[],              // open
                               double &high[],              // high
                               double &low[],               // low
                               double &close[])             // close
{
   // 比較結果の位置番号は [csNum]。
   // R側のローソク足の位置番号は [i+csNum]。
   // L側のローソク足の位置番号は [j+csNum]。
   // LRの比較する位置番号は左上が直角二等辺三角形の逆ピラミッド型になる。

   for(int csNum=start; csNum<end; csNum++) // 処理するローソク足のループ。csNum は処理したいローソク足の番号
   {
      if(startValue[csNum]>0) // パターンの先頭フラグチェック
      {
         for(int i=0, index=0; i<patternNow; i++) // [i] はカウンタとして使用。処理するローソク足は [i+csNum]
         {
            for(int j=i+1; j<patternNow; j++) //  j は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側の値

                  // .status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ

                  // L側から確認
                  switch(structure[j+csNum].status)
                  {
                     //--- L OHLCのとき
                     case 1:
                     case 11:
                        switch(structure[i+csNum].status)
                        {
                           // R OHLC -> LRそのまま
                           case 1:
                           case 11:
                              switch(ohlc)
                              {
                                 case 0: L= open[j+csNum]; break;
                                 case 1: L= high[j+csNum]; break;
                                 case 2: L=  low[j+csNum]; break;
                                 case 3: L=close[j+csNum]; 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=high[i+csNum]; break;
                                 case 2: L= low[i+csNum]; 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=high[i+csNum]; 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=low[i+csNum]; break;
                              }
                              SwapTheLR=true;
                              type='A';
                              break;
                        }
                        break;


                     //--- L HLのとき
                     case 2:
                     case 12:
                     case 22:
                        switch(structure[i+csNum].status)
                        {
                           // 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=high[j+csNum]; break;
                                 case 2: L= low[j+csNum]; break;
                              }
                              SwapTheLR=false;

                              if(structure[i+csNum].status==1 || structure[i+csNum].status==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=high[i+csNum]; 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= low[i+csNum]; 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=high[j+csNum]; break;
                        }
                        SwapTheLR=false;
                     
                        switch(structure[i+csNum].status)
                        {
                           // 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=  low[j+csNum]; break;
                        }
                        SwapTheLR=false;

                        switch(structure[i+csNum].status)
                        {
                           // 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= open[j+csNum];
                     RH= high[j+csNum];
                     RL=  low[j+csNum];
                     RC=close[j+csNum];
                  }
                  else
                  {
                     // そのまま
                     RO= open[i+csNum];
                     RH= high[i+csNum];
                     RL=  low[i+csNum];
                     RC=close[i+csNum];
                  }


                  //--- 不等号で比較
                  // 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]=1; // high 以上
                        else if(L<=RH && L>=RL)   structure[csNum].results[index][ohlc]=6; // high 以下, low 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // low 以下
                        break;

                     case 'C': // Hのみ
                        if(L>=RH)                 structure[csNum].results[index][ohlc]=1; // high 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // high 以下
                        break;

                     case 'D': // Lのみ
                        if(L>=RL)                 structure[csNum].results[index][ohlc]=1; // low 以上
                        else if(L<=RL)            structure[csNum].results[index][ohlc]=5; // low 以下
                        break;
                  }

               } // ここまでが int ohlc のループ

               index++; // int ohlcのループが終わったら保存場所を一つずらす
            }
         }
      }
   }

}
//+------------------------------------------------------------------+
// ローソク足の種類の変更
// pattern[].status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 4=陽線Lのみ, 11=陰線, 12=陰線HL, 13=陰線Hのみ, 14=陰線Lのみ, 22=HL, 23=Hのみ, 24=Lのみ
//+------------------------------------------------------------------+
void statusChange(int num)
{

   if(pattern[num].status==4 || pattern[num].status==14)
   {
      if(pattern[num].status==4) pattern[num].status=11; // 4 の次は 11
      else pattern[num].status=22;                       // 14 の次は 22

      // 始値・終値の入替
      int temp=0;
      temp=pattern[num].y_open;
      pattern[num].y_open=pattern[num].y_close;
      pattern[num].y_close=temp;
   }
   else if(pattern[num].status==24) pattern[num].status=1;  // 24 の次は 1
   else pattern[num].status++;

}
//+------------------------------------------------------------------+
//| ローソク足を描画
//+------------------------------------------------------------------+
void candlestickCreate()
{

   int width=10;  // 幅

   color clr=clrNONE;

   for(int i=0; i<patternNow; i++)
   {
      //--- 色の設定
      if(pattern[i].status<10)      clr=InpCsColorW;  // 10 より下なら陽線
      else if(pattern[i].status<20) clr=InpCsColorB;  // 20 より下なら陰線
      else                          clr=InpCsColorHL; // それ以外はどちらでも可

      // 陽線OHLC・陰線OHLCのとき実体を描画
      string name = Prefix+"cs_"+IntegerToString(i); // オブジェクト名を作成

      if(pattern[i].status==1 || pattern[i].status==11)
      {
         ResetLastError(); // エラー値をリセットする
         //--- 四角形ラベルを作成する
         if(!ObjectCreate(chart_id,name,OBJ_RECTANGLE_LABEL,sub_window,0,0)) // ここでx軸・Y軸は入力しない
         {
            Print(__FUNCTION__,": failed to create a rectangle label! Error code = ",GetLastError());
            return;
         }
         ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,pattern[i].x+width);   // x(時間軸、ピクセル)

         // 始値と終値の位置変更
         if(pattern[i].status==11) // 陰線OHLC
         {
            ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,pattern[i].y_open);                // y(価格軸、ピクセル)
            ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,pattern[i].y_open-pattern[i].y_close); // ラベルの高さ
         }
         else // 陽線OHLC
         {
            ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,pattern[i].y_close);               // y(価格軸、ピクセル)
            ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,pattern[i].y_close-pattern[i].y_open); // ラベルの高さ
         }
         ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,width);                 // ラベルの幅(実体の幅)

         ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,clr);                 // 背景色を設定する
         ObjectSetInteger(chart_id,name,OBJPROP_BORDER_TYPE,BORDER_FLAT);     // 境界線を設定する
         ObjectSetInteger(chart_id,name,OBJPROP_CORNER,CORNER_RIGHT_LOWER);   // x=0,y=0 のコーナーを設定(右下)
         ObjectSetInteger(chart_id,name,OBJPROP_COLOR,clr);           // フラット境界線色を設定する(Flat モード)
         ObjectSetInteger(chart_id,name,OBJPROP_STYLE,STYLE_SOLID);   // フラット境界線スタイルを設定する
         ObjectSetInteger(chart_id,name,OBJPROP_WIDTH,1);             // フラット境界線幅を設定する
         ObjectSetInteger(chart_id,name,OBJPROP_BACK,true);           // 前景(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,0);            // チャートのマウスクリックのイベントを受信するための優先順位を設定する
      }
      else ObjectDelete(chart_id,name); // 実体なければオブジェクト削除


      //--- ヒゲを描画
      string name2 = Prefix+"cs_shadow_"+IntegerToString(i); // オブジェクト名を作成

      // HL と H(L) で表示を変える
      if((pattern[i].status==3 || pattern[i].status==4) ||
         (pattern[i].status==13 || pattern[i].status==14) ||
         (pattern[i].status==23 || pattern[i].status==24))
      {
         ResetLastError(); // エラー値をリセットする
         //--- 四角形ラベルを作成する
         if(!ObjectCreate(chart_id,name2,OBJ_RECTANGLE_LABEL,sub_window,0,0)) // ここでx軸・Y軸は入力しない
         {
            Print(__FUNCTION__,": failed to create a rectangle label! Error code = ",GetLastError());
            return;
         }

         // 文字を表示する
         string text;
         int y=0;

         // H か L か
         if(pattern[i].status==3 || pattern[i].status==13 || pattern[i].status==23) // high
         {
            ObjectSetInteger(chart_id,name2,OBJPROP_YDISTANCE,pattern[i].y_high);   // y(価格軸、ピクセル)
            ObjectSetInteger(chart_id,name2,OBJPROP_YSIZE,30);                      // ラベルの高さ

            text="H";
            y=pattern[i].y_high-30;
         }
         else // low
         {
            ObjectSetInteger(chart_id,name2,OBJPROP_YDISTANCE,pattern[i].y_low+30); // ラベルの高さ分上にずらす(プラスする)
            ObjectSetInteger(chart_id,name2,OBJPROP_YSIZE,30);                      // ラベルの高さ

            text="L";
            y=pattern[i].y_low+55; // 30+文字の大きさ。適当。
         }
                  
         // ラベルオブジェクト作成
         LabelCreate(pattern[i].x+10,y,name2+"_moji",text,clr,12,true);
      }
      else
      {
         ObjectDelete(chart_id,name2+"_moji"); // H・Lのオブジェクト削除
         
         ResetLastError(); // エラー値をリセットする
         //--- 四角形ラベルを作成する
         if(!ObjectCreate(chart_id,name2,OBJ_RECTANGLE_LABEL,sub_window,0,0)) // ここでx軸・Y軸は入力しない
         {
            Print(__FUNCTION__,": failed to create a rectangle label! Error code = ",GetLastError());
            return;
         }
         ObjectSetInteger(chart_id,name2,OBJPROP_YDISTANCE,pattern[i].y_high);           // y(価格軸、ピクセル)
         ObjectSetInteger(chart_id,name2,OBJPROP_YSIZE,pattern[i].y_high-pattern[i].y_low);   // ラベルの高さ
      }
      
      ObjectSetInteger(chart_id,name2,OBJPROP_XDISTANCE,pattern[i].x+(width/2)); // x(時間軸、ピクセル)
      ObjectSetInteger(chart_id,name2,OBJPROP_XSIZE,2);                          // ラベルの幅(ヒゲの幅)
      ObjectSetInteger(chart_id,name2,OBJPROP_BGCOLOR,clr);                      // 背景色を設定する
      ObjectSetInteger(chart_id,name2,OBJPROP_BORDER_TYPE,BORDER_FLAT);          // 境界線を設定する
      ObjectSetInteger(chart_id,name2,OBJPROP_CORNER,CORNER_RIGHT_LOWER);        // x=0,y=0 のコーナーを設定(右下)
      ObjectSetInteger(chart_id,name2,OBJPROP_COLOR,clr);                        // フラット境界線色を設定する(Flat モード)
      ObjectSetInteger(chart_id,name2,OBJPROP_WIDTH,1);                          // フラット境界線幅を設定する
      ObjectSetInteger(chart_id,name2,OBJPROP_STYLE,STYLE_SOLID);                // フラット境界線スタイルを設定する
      ObjectSetInteger(chart_id,name2,OBJPROP_BACK,true);        // 前景(false)または背景(true)に表示
      ObjectSetInteger(chart_id,name2,OBJPROP_SELECTABLE,false); // マウスでラベルを移動させるモードを有効(true)か無効(false)にする
      ObjectSetInteger(chart_id,name2,OBJPROP_SELECTED,false);
      ObjectSetInteger(chart_id,name2,OBJPROP_HIDDEN,true);      // オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする
      ObjectSetInteger(chart_id,name2,OBJPROP_ZORDER,0);         // チャートのマウスクリックのイベントを受信するための優先順位を設定する
   }
   
   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
//| OHLC ラベルを削除する
//+------------------------------------------------------------------+
void ohlcDelete(int num, string ohlcMoji="", int moji=16, int side=0) // 何番目のローソク足か, 残したい文字, 何文字目から検索するか
{
   // オブジェクト削除
   for(int i=0; i<4; i++)
   {
      // オブジェクト名
      string name;
      if(side==0) name=Prefix+"OHLC_R_";
      else name=Prefix+"OHLC_L_";

      switch(i)
      {
         case 0: name=name+"H_"+IntegerToString(num); break;
         case 1: name=name+"O_"+IntegerToString(num); break;
         case 2: name=name+"C_"+IntegerToString(num); break;
         case 3: name=name+"L_"+IntegerToString(num); break;
      }

      int find=StringFind(name,ohlcMoji,moji);  // 16文字目から ohlcMoji を探す
      if(find<0) ObjectDelete(chart_id,name);   // 文字がなければ削除
   }

   ChartRedraw();
}
//+------------------------------------------------------------------+
//| OHLC ラベルを作成する
//+------------------------------------------------------------------+
void ohlcButtonCreate(int num)
{

   ObjectsDeleteAll(chart_id,Prefix+"OHLC_"); // OHLCラベルを全削除
      
   color clr=clrWhite;  // テキストの色
   string text;         // 表示するテキスト
   string name;         // オブジェクト名

   // y (高さ)を設定
   int y=0;
   y=(pattern[num].y_high-(pattern[num].y_high-pattern[num].y_low)/2)+40;

   for(int i=0; i<4; i++)
   {
      // 表示しないものは continue。それ以外は次へ。
      switch(pattern[num].status)
      {
         // 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(pattern[num].status>10 && pattern[num].status<20)
         switch(i)
         {
            case 0: text="H"; name=Prefix+"OHLC_R_H_"+IntegerToString(num); break;
            case 1: text="O"; name=Prefix+"OHLC_R_O_"+IntegerToString(num); break;
            case 2: text="C"; name=Prefix+"OHLC_R_C_"+IntegerToString(num); break;
            case 3: text="L"; name=Prefix+"OHLC_R_L_"+IntegerToString(num); break;
         }
      // 陰線以外の名称
      else
         switch(i)
         {
            case 0: text="H"; name=Prefix+"OHLC_R_H_"+IntegerToString(num); break;
            case 1: text="C"; name=Prefix+"OHLC_R_C_"+IntegerToString(num); break;
            case 2: text="O"; name=Prefix+"OHLC_R_O_"+IntegerToString(num); break;
            case 3: text="L"; name=Prefix+"OHLC_R_L_"+IntegerToString(num); break;
         }

      // ラベルの作成
      LabelCreate(pattern[num].x-10,y-(i*20),name,text,clr);
   }
   
   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
// ラベル作成
//+------------------------------------------------------------------+
void LabelCreate(int x, int y, string name, string text, color clr, int fontSize=0, bool back=false)
{
   // fontSizeが渡されなかったらインプットの値を使用
   if(fontSize==0) fontSize=InpFontsize;

   ResetLastError(); // エラー値をリセットする
   if(!ObjectCreate(chart_id,name,OBJ_LABEL,sub_window,0,0))   // ラベルを作成する
   {
      Print(__FUNCTION__,": failed to create the button! Error code = ",GetLastError());
      return;
   }

   ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x);              // x軸(ピクセル)
   ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y);              // y軸(ピクセル)
   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,fontSize);        // フォントサイズを設定する
   ObjectSetInteger(chart_id,name,OBJPROP_COLOR,clr);                // テキストの色を設定する
   ObjectSetDouble(chart_id,name,OBJPROP_ANGLE,0.0);                 // テキストの傾斜を設定する
   ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER); // アンカーの種類を設定
   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,0);                 // チャートのマウスクリックのイベントを受信するための優先順位を設定する
}
//+------------------------------------------------------------------+
// メインチャートに描画
//+------------------------------------------------------------------+
void ArrowCreate(string name,                         // 名前
                 MqlRates &rates[],                   // アンカーポイントの価格と時刻
                 ENUM_ARROW_ANCHOR anchor=ANCHOR_TOP, // アンカーポイント位置
                 color clr=clrBlue)                   // 矢印の色
{

   // 名前が name で始まる、OBJ_ARROW のオブジェクトを全部削除
   ObjectsDeleteAll(chart_id, name, 0, OBJ_ARROW);

   // 矢印の作成
   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,rates[i].time,rates[i].high);   // OBJ_ARROW 作成
         ObjectSetInteger(chart_id,name1,OBJPROP_ARROWCODE,InpSignArrowwCode);   // 矢印コード
         ObjectSetInteger(chart_id,name1,OBJPROP_ANCHOR,ANCHOR_BOTTOM);          // アンカーの種類
         ObjectSetInteger(chart_id,name1,OBJPROP_COLOR,InpSignColor);            // 矢印の色
         ObjectSetInteger(chart_id,name1,OBJPROP_WIDTH,InpSignWidth);            // 矢印のサイズ

         // 下側
         string name2=name+"bottom_"+IntegerToString(i); // オブジェクト名の作成

         ObjectCreate(chart_id,name2,OBJ_ARROW,0,rates[i].time,rates[i].low);    // OBJ_ARROW 作成
         ObjectSetInteger(chart_id,name2,OBJPROP_ARROWCODE,InpSignArrowwCode2);  // 矢印コード
         ObjectSetInteger(chart_id,name2,OBJPROP_ANCHOR,ANCHOR_TOP);             // アンカーの種類
         ObjectSetInteger(chart_id,name2,OBJPROP_COLOR,InpSignColor);            // 矢印の色
         ObjectSetInteger(chart_id,name2,OBJPROP_WIDTH,InpSignWidth);            // 矢印のサイズ
      }
   }

   // 再描画
   ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| 画面下部のボタンの設定
//+------------------------------------------------------------------+
void underButton()
{
   string name = Prefix+"cb_Button_"; // Candle stick button

   color clr=clrBlack;        // 文字の色
   color back_clr=clrWhite;   // ボタンと境界線の色

   if(mode==2) // 検索モードのとき色変更
   {
      clr=clrWhite;     // 文字の色
      back_clr=clrNONE; // ボタンと境界線の色
   }

   string text; // 表示するテキスト

   for(int i=0; i<patternNow; i++)
   {
      string name1 = name + IntegerToString(i);

      // ボタンに表示するテキストの設定
      if(mode==0)
      {
         switch(pattern[i].status)
         {
            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 if(mode==1) text="P";
      else text=IntegerToString(i);
   
      ButtonCreate(pattern[i].x+15,30,20,20,name1,text,clr,back_clr);
   }

   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
//| ボタンを作成する      マウスクリックの優先度は 100
//+------------------------------------------------------------------+
void ButtonCreate(int x, int y, int x_button, int y_button, string name, string text, 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;
   }

   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,100);            // チャートのマウスクリックのイベントを受信するための優先順位を設定する

   //--- チャートを再描画
   ChartRedraw();
}
//+------------------------------------------------------------------+
// 水平線を描画
//+------------------------------------------------------------------+
void CreateLine(string name, 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)にする

   ChartRedraw(0);
}
//+------------------------------------------------------------------+
// パターンのあるところまで画面移動
//+------------------------------------------------------------------+
int chartMove(int num)
{
   int shift=num;

   // チャートの自動スクロールを無効
   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;
   time=iTime(Symbol(),PERIOD_CURRENT,shift);

   string text, text2;
   text= (string)num + "/"+ (string)signMax + "の時刻";
   text2= TimeToString(time);

   CreateLabel(Prefix+"Pattern_Time",text,CORNER_LEFT_UPPER, 70, 200, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   CreateLabel(Prefix+"Pattern_Time2",text2,CORNER_LEFT_UPPER, 70, 220, ANCHOR_CENTER, "Arial Black", 10, clrWhite);

   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_window,width);

   long height=0;
   ChartGetInteger(chart_id,CHART_HEIGHT_IN_PIXELS,sub_window,height); // サブウィンドウの高さ

   long height2=0;
   ChartGetInteger(chart_id,CHART_WINDOW_YDISTANCE,sub_window,height2); // メインチャートからサブウィンドウまでの高さ

   //--- スクリーンショットの保存 (保存先 terminal_directory\MQL5\Files\ )
   if(ChartScreenShot(chart_id,name,(int)width,(int)height+(int)height2,ALIGN_CENTER)) 
      printf("スクリーンショットを保存しました。file name = %s",name);

   //--- スクリーンショットの保存先を開く
   string dir=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files";
   ShellExecuteW(0,"open",dir,"","",1);

}
//+------------------------------------------------------------------+
// 通貨ペア・時間足の表示
//+------------------------------------------------------------------+
void info()
{
   // 通貨ペア
   CreateLabel(Prefix+"Symbol",_Symbol,CORNER_LEFT_UPPER, 70, 30, ANCHOR_CENTER, "Arial Black", 14, clrWhite);

   // タイムフレーム(時間軸)
   ENUM_TIMEFRAMES timeframe = _Period;
   string text_timeframe = EnumToString(timeframe);  // "PERIOD_M30" "PERIOD_H1" のような文字列を取得
   CreateLabel(Prefix+"TimeFrame",StringSubstr(text_timeframe, 7),CORNER_LEFT_UPPER, 70, 60, ANCHOR_CENTER, "Arial Black", 14, clrWhite);

   // 検索期間
   datetime time, time2;
   time=iTime(Symbol(),PERIOD_CURRENT,0);
   time2=iTime(Symbol(),PERIOD_CURRENT,candlesToCalculate);

   string text, text2;
   text= TimeToString(time);
   text2= TimeToString(time2);

   CreateLabel(Prefix+"Time3","検索期間",CORNER_LEFT_UPPER, 70, 100, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   CreateLabel(Prefix+"Time",text,CORNER_LEFT_UPPER, 70, 120, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
   CreateLabel(Prefix+"Time4","~",CORNER_LEFT_UPPER, 70, 140, ANCHOR_CENTER, "Arial Black", 10, clrWhite, 90); // ~を90度回転して表示
   CreateLabel(Prefix+"Time2",text2,CORNER_LEFT_UPPER, 70, 160, ANCHOR_CENTER, "Arial Black", 10, clrWhite);
}
//+------------------------------------------------------------------+
// ファイルの保存
//+------------------------------------------------------------------+
int csvFileWrite()
{
   // ファイル名の作成
   string fileName = csvName;
         
   // CSVファイルの作成
   ResetLastError();
   int handle=FileOpen(fileName,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, pattern[i].status, pattern[i].y_open, pattern[i].y_high, pattern[i].y_low, pattern[i].y_close);

      // ファイルを閉じる
      FileClose(handle);
      PrintFormat("%s を作成しました",fileName);
      return(1);
   }
   else
   {
      printf("ファイルの作成を失敗しました %s , エラーコード %d", fileName, GetLastError());
      return(-1);
   }

   return(0);
}
//+------------------------------------------------------------------+
// ファイルの読込
//+------------------------------------------------------------------+
int csvFileRead()
{
   // ファイル名の作成
   string fileName = csvName;
            
   ResetLastError();
   int handle=FileOpen(fileName,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列目のデータは取得せず移動のみ)
         pattern[i].status = (int)FileReadNumber(handle); // 陽線・陰線情報
         pattern[i].y_open = (int)FileReadNumber(handle); // open
         pattern[i].y_high = (int)FileReadNumber(handle); // high
         pattern[i].y_low  = (int)FileReadNumber(handle); // low
         pattern[i].y_close = (int)FileReadNumber(handle); // close
         i++;
      }
               
      //--- ファイルを閉じる
      FileClose(handle);
      return(1);
   }
   else
   {
      PrintFormat("ファイルの読込を失敗しました %s , エラーコード %d",fileName,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 -1;
}
//+------------------------------------------------------------------+
//| 構造体の初期設定
//+------------------------------------------------------------------+
void structReset(pattern_struct &structure[], int now)
{
   // xの200は画面右側にボタンを配置するため
   // yの50は画面下側にボタンを配置するため
   // .status     0=無し, 1=陽線, 2=陽線HL, 3=陽線Hのみ, 10=HL, 11=陰線, 12=陰線HL, 13=陰線Lのみ

   // 初期値を代入
   for(int i=0; i<patternMax; i++)
   {
      if(i<now) structure[i].status=1; // 使用する分のみ 1 を設定
      else structure[i].status=0;      // 使用しない分は 0
      
      structure[i].x=200+(i*40);    // x軸

      structure[i].y_open=50+30;    // y軸 open
      structure[i].y_high=50+75;    // y軸 high
      structure[i].y_low=50+15;     // y軸 low
      structure[i].y_close=50+60;   // y軸 close
   }
}
//+------------------------------------------------------------------+
//| この指標のチャートウィンドウの番号を返す(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);
}
//--------------------------------------------------------------------
// 文字を描画する関数
//--------------------------------------------------------------------
void CreateLabel(string name,       // オブジェクト名
                 string text,       // 表示するテキスト
                 ENUM_BASE_CORNER corner,        // チャートの四隅の指定
                 int xshift,        // OBJPROP_CORNERからの距離(横)
                 int yshift,        // OBJPROP_CORNERからの距離(縦)
                 int anchor,        // アンカーの位置
                 string font,       // フォントの種類
                 int fontSize,      // フォントのサイズ
                 color fontColor,   // フォントの色
                 double angle=0)    // 角度
{

    ObjectCreate(chart_id,name,OBJ_LABEL,sub_window,0,0);
    ObjectSetString( chart_id,name,OBJPROP_TEXT,text);
    ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);
    ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,xshift);
    ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,yshift);
    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);
    ObjectSetDouble(chart_id,name,OBJPROP_ANGLE,angle);
}
//+------------------------------------------------------------------+


それでは良い一日を!