複数チャートの通貨ペア同期ツールを作ってみました(ソース公開)

 

MT5で複数チャートを並べて使っていると、 シンボルや時間足をいちいち合わせるのが面倒 だと感じることが多いと思います。

特に、 チャートをドッキングして細かく配置している時は、 上部の時間足バーが遠かったり隠れたりして操作しづらい ことがあります。

そこで、 複数チャートの通貨ペアと時間足を、 ボタン一発で切り替えられるツール を作ってみました。 ソースもそのまま公開します。

■ このツールでできること

  • 送信側のボタンで通貨ペアを一括切り替え → 複数チャートを同じ銘柄に揃えるのが簡単

  • 受信側のボタンで時間足を一発切り替え → ドッキング環境で特に便利(上のバーを探さなくていい)

  • チャートごとにIDを設定して役割を分けられる → 例:メイン足、監視足、補助足など

  • グローバル変数でチャート間を識別して同期 → MT5標準機能だけで動作(外部DLLなし)

  • ソースがシンプルなので改造しやすい



■ ソースコード(そのまま貼っています)

送信側
#property strict
#property indicator_chart_window
#property indicator_plots 0
input string byo = "_S5";
input int mado = 0;
// 画像のリスト
string symbols[] = {"USDJPY", "EURJPY", "AUDJPY", "EURUSD", "GBPUSD", "AUDUSD", "ETHUSD", "BTCUSD", "GOLD"};

//---------------------------------------------
// ボタン作成
//---------------------------------------------
void CreateButton(string name, int x, int y, string text)
{
   if(ObjectFind(0, name) == -1)
   {
      ObjectCreate(0, name, OBJ_BUTTON, mado, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, name, OBJPROP_XSIZE, 50);
      ObjectSetInteger(0, name, OBJPROP_YSIZE, 18);
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 7);
      ObjectSetString (0, name, OBJPROP_TEXT, text);
      
      ObjectSetInteger(0, name, OBJPROP_COLOR, clrWhite);
      ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clrDarkSlateGray);
      ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrSilver);
      ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   }
}

int OnInit()
{
   for(int i=0; i<ArraySize(symbols); i++)
   {
      CreateButton("btn_sym_" + symbols[i], 5, 15 + (i * 20), symbols[i]);
   }
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason) { ObjectsDeleteAll(0, "btn_sym_"); }

//---------------------------------------------
// メイン処理:自分を変え、他も変える
//---------------------------------------------
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id == CHARTEVENT_OBJECT_CLICK && StringFind(sparam, "btn_sym_") == 0)
   {
      // 1. 選択された銘柄名(例:USDJPY)を取得
      string baseName = StringSubstr(sparam, 8);
      
      // 2. 自分自身の切り替え(_S5を付加、M1固定)
      string myTarget = baseName + "_S" + byo;
      if(!ChartSetSymbolPeriod(0, myTarget, PERIOD_M1))
      {
         Print("エラー: ", myTarget, " が見つかりません。");
      }

      // 3. 他の目印付きチャート(Receiver)を探して同期
      long currChart = ChartFirst();
      while(currChart >= 0)
      {
         // 自分以外のチャートをチェック
         if(currChart != ChartID())
         {
            string flagName = "Receiver_" + IntegerToString(currChart);
            if(GlobalVariableCheck(flagName))
            {
               int targetID = (int)GlobalVariableGet(flagName);
               
               // IDに応じた銘柄名のルール
               // ID 1なら秒足(_S5)、それ以外(ID 2など)なら通常銘柄
               string suffix = (targetID == 1) ? byo : "";
               string syncSymbol = baseName + suffix;
               
               // ※時間足は、そのチャートの「今の設定」を維持したまま銘柄だけ変える
               ChartSetSymbolPeriod(currChart, syncSymbol, ChartPeriod(currChart));
            }
         }
         currChart = ChartNext(currChart);
      }

      ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
      ChartRedraw();
   }
}

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


受信側

#property strict
#property indicator_chart_window
#property indicator_plots 0

//--- 追加:目印用の設定 ---
input int MyID = 2; // このチャートのID(1:秒足用, 2:分足用など)

string timeFrames[] = {"M1", "M5", "M15", "M30", "H1"};

//---------------------------------------------
// ボタン作成(右上起点の座標系)
//---------------------------------------------
void CreateButton(string name, int x, int y, string text)
{
   if(ObjectFind(0, name) == -1)
   {
      ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, name, OBJPROP_XSIZE, 30);
      ObjectSetInteger(0, name, OBJPROP_YSIZE, 15);
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 8);
      ObjectSetString (0, name, OBJPROP_TEXT, text);
      
      ObjectSetInteger(0, name, OBJPROP_COLOR, clrWhite);
      ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clrDarkSlateGray);
      ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrSilver);
      ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   }
}

//---------------------------------------------
// 初期化
//---------------------------------------------
int OnInit()
{
   // --- 目印フラグをグローバル変数にセット ---
   string flagName = "Receiver_" + IntegerToString(ChartID());
   GlobalVariableSet(flagName, MyID);

   // ID表示用ラベル(確認用:不要なら消してもOK)
   ObjectCreate(0, "ID_Label", OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, "ID_Label", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
   ObjectSetInteger(0, "ID_Label", OBJPROP_XDISTANCE, 35);
   ObjectSetInteger(0, "ID_Label", OBJPROP_YDISTANCE, 0);
   ObjectSetInteger(0, "ID_Label", OBJPROP_FONTSIZE, 7);
   ObjectSetInteger(0, "ID_Label", OBJPROP_COLOR, clrGray);
   ObjectSetString(0, "ID_Label", OBJPROP_TEXT, "ID:" + IntegerToString(MyID));

   for(int i=0; i<ArraySize(timeFrames); i++)
   {
      CreateButton("btn_" + timeFrames[i], 35, 15 + (i * 15), timeFrames[i]);
   }
   return(INIT_SUCCEEDED);
}

//---------------------------------------------
// 終了処理
//---------------------------------------------
void OnDeinit(const int reason)
{
   string flagName = "Receiver_" + IntegerToString(ChartID());
   if(GlobalVariableCheck(flagName)) GlobalVariableDel(flagName);
   
   ObjectsDeleteAll(0, "btn_");
   ObjectDelete(0, "ID_Label");
}

//---------------------------------------------
// ボタンクリック処理
//---------------------------------------------
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      if(StringFind(sparam, "btn_") == 0)
      {
         string tfString = StringSubstr(sparam, 4); 
         ENUM_TIMEFRAMES newTF = StringToTimeframe(tfString);
         
         if(newTF != WRONG_VALUE)
         {
            ChartSetSymbolPeriod(0, _Symbol, newTF);
         }

         ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
         ChartRedraw();
      }
   }
}

// 時間足変換補助
ENUM_TIMEFRAMES StringToTimeframe(string tf)
{
   if(tf == "M1")  return PERIOD_M1;
   if(tf == "M5")  return PERIOD_M5;
   if(tf == "M15") return PERIOD_M15;
   if(tf == "M30") return PERIOD_M30;
   if(tf == "H1")  return PERIOD_H1;
   if(tf == "H4")  return PERIOD_H4;
   if(tf == "D1")  return PERIOD_D1;
   return WRONG_VALUE;
}

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

■ 最後に

こういう “複数チャートの同期ツール” は アイデアとして持っている人は多いと思いますが、 実際に形にして公開されている例はあまり見ない ので、 誰かの参考になればと思い公開しました。

もし改善案や追加機能のアイデアがあれば教えてください。