投資で実現!不労所得生活

MetaTrader/MQL: チャートの描画スタイルを設定する (ChartSetXxx)

更新:
作成:

チャートのプロパティを設定/取得する

あるチャートに設定されたプロパティ(描画スタイルなど)を変更/取得するには、次のような関数を使用します。

表示項目の OFF/ON 設定

チャートの表示項目を変更するには、ChartSetInteger 関数の第 2 引数 (prop_id) に以下のようなプロパティ ID を指定します。

プロパティ ID設定内容
CHART_MODECHART_BARS: バーチャート
CHART_CANDLES: ローソク足
CHART_LINE: 折れ線
CHART_SHOW_VOLUMESCHART_VOLUME_HIDE: ボリュームを表示しない
CHART_VOLUME_TICK: ボリュームとして Tick 数を表示する
CHART_VOLUME_REAL: ボリュームとして実際の取引量を表示する(サーバによって提供されていないことがある)
CHART_SHOW_GRIDtrue/false: グリッドを表示する/しない
CHART_SHOW_PERIOD_SEPtrue/false: 一定期間ごとの縦線を表示する/しない
CHART_SHOW_ASK_LINEtrue/false: 買値の水平線を表示する/しない
CHART_SHOW_BID_LINEtrue/false: 売値の水平線を表示する/しない
CHART_SHOW_DATE_SCALEtrue/false: 日時バー(横の軸)を表示する/しない
CHART_SHOW_PRICE_SCALEtrue/false: 価格バー(縦の軸)を表示する/しない
CHART_SHOW_OHLCtrue/false: 左上の Open/High/Low/Close 価格を表示する/しない(これを false にしても、通貨ペア名と時間足は表示されます)
CHART_SHOW_ONE_CLICKtrue/false: 左上のワンクリック注文パネルを表示する/しない
例: チャートのプロパティを変更する
/**
 * Setup the drawing style of the chart.
 *
 * @param chartId the target chart ID (0 means the current chart)
 */
void setupChart(long chartId = 0) {
    // ローソク足で表示
    ChartSetInteger(chartId, CHART_MODE, CHART_CANDLES);

    // 買値 (Ask) ラインを表示
    ChartSetInteger(chartId, CHART_SHOW_ASK_LINE, true);

    // 売値 (Bid) ラインを表示
    ChartSetInteger(chartId, CHART_SHOW_BID_LINE, true)

    ChartRedraw(chartId);
}

各種プロパティの変更が実際に画面上に反映されるのは、次のチャートの再描画のタイミングです(例えば、次の tick が発生したとき)。 直ちに設定を画面に反映させたい場合は、上記のように ChartRedraw 関数 を呼び出します。

表示項目の色の設定

チャートの各描画要素の色を設定する場合も、ChartSetInteger 関数を使用します。 第 2 引数 (prop_id) に次のようなプロパティ ID を指定することで、それぞれの項目の色を設定できます。

プロパティ ID設定内容
CHART_COLOR_BACKGROUND背景色
CHART_COLOR_FOREGROUND価格軸、時間軸、OHLC(Open/High/Low/Close) の色
CHART_COLOR_GRIDグリッド線の色
CHART_COLOR_VOLUMEボリュームの色
CHART_COLOR_CHART_UPローソク足の上昇バーのひげ、および、箱の枠の色
CHART_COLOR_CHART_DOWNローソク足の下降バーのひげ、および、箱の枠の色
CHART_COLOR_CHART_LINE折れ線チャートの線の色、ローソク足の十字線の色
CHART_COLOR_CANDLE_BULL上昇バーの内側の色
CHART_COLOR_CANDLE_BEAR下降バーの内側の色
CHART_COLOR_BID売値 (Bid) の水平線の色
CHART_COLOR_ASK買値 (Ask) の水平線の色
CHART_COLOR_LAST最新約定価格の水平線の色
CHART_COLOR_STOP_LEVEL決済価格(指値/逆指値)の水平線の色

色の指定は color 型(4 バイトの数値)で行いますが、様々な表現で指定することができます。

/p/dzcoybn/img-001.png

上記のチャートの配色は、次のようなコードを実行することによって設定することができます。 スクリプトからチャート設定を行うと、一部の設定だけを変更することができるため、使いようによってはテンプレートによる配色変更を行うよりも便利です。

void setupColors(long chartId = 0) {
    ChartSetInteger(chartId, CHART_COLOR_BACKGROUND, clrBlack);
    ChartSetInteger(chartId, CHART_COLOR_FOREGROUND, clrLightGray);
    ChartSetInteger(chartId, CHART_COLOR_GRID, clrGray);
    ChartSetInteger(chartId, CHART_COLOR_VOLUME, clrLimeGreen);
    ChartSetInteger(chartId, CHART_COLOR_CHART_UP, clrDeepPink);
    ChartSetInteger(chartId, CHART_COLOR_CHART_DOWN, clrDodgerBlue);
    ChartSetInteger(chartId, CHART_COLOR_CHART_LINE, clrOrange);
    ChartSetInteger(chartId, CHART_COLOR_CANDLE_BULL, clrDeepPink);
    ChartSetInteger(chartId, CHART_COLOR_CANDLE_BEAR, clrDodgerBlue);
    ChartSetInteger(chartId, CHART_COLOR_BID, clrDodgerBlue);
    ChartSetInteger(chartId, CHART_COLOR_ASK, clrOrangeRed);
}

オブジェクト指向の CChart クラスを使用する

CChart クラスを使用すると、ChartSetInteger のようなプロパティセット関数を使用する代わりに、オブジェクトのメソッドを呼び出すことよって、スマートな記述を行うことができます(なぜか CHART_SHOW_ONE_CLICK に相当するメソッドだけは見つからない・・・)。

下記のスクリプトの setupChart 関数は、CChart オブジェクトを受け取って、描画スタイルの設定を行っています。

Scripts/SetupChart.mq4
#include <Charts\Chart.mqh>

/**
 * Setup the drawing style of the chart.
 *
 * @param chart the chart object to be set up
 */
void setupChart(CChart& chart) {
    // Show-hide settings
    chart.Mode(CHART_CANDLES);
    chart.ShowOHLC(true);
    chart.ShowLineBid(true);
    chart.ShowLineAsk(true);
    chart.ShowGrid(true);
    chart.ShowPeriodSep(true);
    chart.ShowVolumes(CHART_VOLUME_TICK);
    chart.ShowDateScale(true);
    chart.ShowPriceScale(true);
    chart.Scale(3);

    // Color settings
    chart.ColorBackground(clrBlack);
    chart.ColorForeground(clrLightGray);
    chart.ColorGrid(clrGray);
    chart.ColorVolumes(clrLimeGreen);
    chart.ColorBarUp(clrDeepPink);
    chart.ColorBarDown(clrDodgerBlue);
    chart.ColorChartLine(clrYellow);
    chart.ColorCandleBull(clrDeepPink);
    chart.ColorCandleBear(clrDodgerBlue);
    chart.ColorLineBid(clrDodgerBlue);
    chart.ColorLineAsk(clrOrangeRed);
}

void OnStart() {
    CChart c;
    c.Attach(0);  // 0 means the current chart.
    setupChart(c);
    c.Redraw();
    c.Detach();  // Without detaching, the chart will be closed.
}

CChart オブジェクトを既存のチャートに関連付けるには、Attach メソッドを使用します。 上記の例では、0 を渡すことによって、アクティブなチャートに関連付けています。 CChart クラスは、デストラクタ内で関連付けられたチャートを閉じようとするので、スクリプトが終了したときにチャートが閉じられないようにするために、Detach メソッドを読んで関連付けを解除しておかなければいけません。

関連記事

MetaTrader/MQL: 描画オブジェクトの基本 (ObjectCreate)

更新:
作成:

描画オブジェクトの作成 (ObjectCreate)

MetaTrader のチャート上に何らかの図形を描画するには、ObjectCreate 関数日本語)を使って、描画オブジェクトを生成します。

ObjectCreate 関数
bool ObjectCreate(
    long chart_id,     // チャート ID(0 ならカレントチャート)
    string name,       // オブジェクト名
    ENUM_OBJECT type,  // オブジェクトの種類
    int sub_window,    // サブウィンドウ番号(0 ならメインウィンドウ)
    datetime time1,    // 1 番目のアンカーポイントの時刻
    double price1,     // 1 番目のアンカーポイントの価格
    ...                // :
    datetime time30=0, // 30番目のアンカーポイントの時刻
    double price30=0   // 30番目のアンカーポイントの価格
);

chart_id / sub_window

chart_id 引数と sub_window 引数には、どのチャートの、どのウィンドウに描画オブジェクトを表示するかを指定します。 カレントチャートのメインウィンドウに表示するのであれば、両方とも 0 を指定しておけば OK です。

name

name 引数では、作成する描画オブジェクトに名前を付けます。 描画オブジェクトの各種プロパティを設定するときは、この名前で描画オブジェクトを指定することになります。 名前はチャート内(サブウィンドウを含む)で一意でなければいけません。 ただし、使用上 63 文字までしか使えないので、その範囲で他のインジケーターとできるだけ被らない名前を付ける必要があります。

簡単なテクニックとして、次のようなプレフィックスマクロを定義しておけば、

#define OBJ_PREFIX "MY_INDI_"

オブジェクト名が必要なところで次のように使えます。 文字列リテラルを並べると自動的に結合されるので、+ 演算子を使った文字列結合は必要ないことに注意してください。

string name1 = OBJ_PREFIX "LABEL_1";  //=> "MY_INDI_LABEL_1" になる
string name2 = OBJ_PREFIX "LABEL_2";  //=> "MY_INDI_LABEL_2" になる

type

type 引数では、どのような種類の描画オブジェクトを作成するかを指定します。 例えば、ラベルであれば OBJ_LABEL を指定し、水平線であれば OBJ_HLINE を指定します。

time1 / price1

time1 引数や price1 引数では、描画オブジェクトのアンカーポイントを指定します。 アンカーポイントとは、描画オブジェクトの表示位置を示す座標情報です。 描画オブジェクトの種類によって、アンカーポイントをいくつ指定しなければいけないかが決まっています(0 個以上)。 例えば、長方形オブジェクト (OBJ_RECTANGLE) やトレンドラインオブジェクト (OBJ_TREND) の場合は、2 つのアンカーポイント(time1price1time2price2)を指定する必要があります。

ラベルオブジェクト (OBJ_LABEL) のように、アンカーポイントをまったく使用しない描画オブジェクトもあります(ラベルの表示位置は OBJPROP_XDISTANCE などのプロパティで指定します)。 その場合でも、ObjectCreate 関数の使用上、1 つはアンカーポイントを指定しなければいけません。 ラベルオブジェクトを作成する場合は、time1 引数と price1 引数には、適当に 0 を指定しておけば OK です。

次のインジケーターでは、CreateObject 関数を使って、1 つの水平線オブジェクト (OBJ_HLINE) を作成しています。 水平線は 1 つのアンカーポイント(price1 のみ)を使用します。

Scripts/Test.mq5
#property strict
#property indicator_chart_window
#property indicator_plots 0

input double Price = 100;  // 水平線を引く価格

int OnInit() {
    ObjectCreate(0, "HLINE_1", OBJ_HLINE, 0, 0, Price);
    return INIT_SUCCEEDED;
}

int OnCalculate(const int rates_total, const int prev_calculated,
                const int begin, const double &price[]) {
    return rates_total;
}

描画オブジェクトの削除 (ObjectDelete, ObjectDeleteAll)

描画オブジェクトを 1 つずつ削除(ObjectDelete)

CreateObject で作成した描画オブジェクトは、ObjectDelete 関数日本語)を使って削除することができます。

ObjectDelete 関数
bool ObjectDelete(long chart_id, string name);

インジケーターの OnDeinit 関数内で呼び出すようにしておけば、インジケーターをチャートからデタッチしたときに、自動的に描画オブジェクトを削除できます。

Indicators/Test.mq5(抜粋)
input double Price = 105;  // 水平線をひく価格
#define OBJ_PREFIX "MY_INDI_"

int OnInit() {
    ObjectCreate(0, OBJ_PREFIX "HLINE_1", OBJ_HLINE, 0, 0, Price);
    return INIT_SUCCEEDED;
}

void OnDeinit(const int reason) {
    ObjectDelete(0, OBJ_PREFIX "HLINE_1");
    ObjectFind(0, OBJ_PREFIX "HLINE_1");  // 確実に反映させる
}

注意点としては、ObjectDelete 関数は非同期で実行されるため、OnDeinit 関数で単独で呼び出しても処理が即座に反映されないことがあるということです(市場がクローズしているときなど)。 この問題を解決するには、ObjectDelete 関数の後ろで、ObjectFind 関数など同期実行される関数を呼び出しておきます。

描画オブジェクトをまとめて削除 (ObjectsDeleteAll)

ObjectDeleteAll 関数日本語)を使うと、指定したチャート内の描画オブジェクトをまとめて削除することができます。

ObjectDeleteAll 関数
int ObjectsDeleteAll(
    long chart_id,      // チャート識別子
    int sub_window=-1,  // ウィンドウ番号
    int type=-1         // オブジェクトの型
);

int ObjectsDeleteAll(
    long chart_id,        // チャート識別子
    const string prefix,  // オブジェクト名のプレフィックス
    int sub_window=-1,    // ウィンドウ番号
    int object_type=-1    // オブジェクトの型
);

2 つ目のバージョンでは、指定したプレフィックスを名前に持つ描画オブジェクトだけをまとめて削除することができます。 これを使えば、インジケーターが自分で追加したオブジェクトだけをまとめて削除することができます。

次のインジケーターは、チャートへのアタッチ時に 3 つの水平線を生成し、デタッチ時に自分が作成した水平線をすべて削除します。

Indicators/Test.mq5
#property strict
#property indicator_chart_window
#property indicator_plots 0

input double Price = 105;  // 水平線をひく価格

// 描画オブジェクトのプレフィックス
#define OBJ_PREFIX "MY_INDI_"

int OnInit() {
    // 同じプレフィックスで描画オブジェクトを生成する
    ObjectCreate(0, OBJ_PREFIX "HLINE_UPPER", OBJ_HLINE, 0, 0, Price - 0.5);
    ObjectCreate(0, OBJ_PREFIX "HLINE_MIDDLE", OBJ_HLINE, 0, 0, Price);
    ObjectCreate(0, OBJ_PREFIX "HLINE_LOWER", OBJ_HLINE, 0, 0, Price + 0.5);

    return INIT_SUCCEEDED;
}

void OnDeinit(const int reason) {
    // 同じプレフィックスを持つ描画オブジェクトをすべて削除する
    ObjectsDeleteAll(0, OBJ_PREFIX);
}

int OnCalculate(const int rates_total, const int prev_calculated,
                const int begin, const double &price[]) {
    return rates_total;
}

描画オブジェクトの設定 (ObjectSetXxx)

ObjectCreate 関数によって描画オブジェクトを作成したら、あとは次のような関数を使って各種プロパティを設定していきます。

次のサンプルスクリプトでは、ラベルオブジェクト作成し、上記の関数を使ってフォントサイズや表示位置の設定を行っています。

Indicators/Test.mq5(ラベルを右下に表示)
#property strict
#property indicator_chart_window
#property indicator_plots 0

// 描画オブジェクトのプレフィックス
#define OBJ_PREFIX "MY_INDI_"

int OnInit() {
    // ラベルを作成する
    string name = OBJ_PREFIX "LABEL_1";
    ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);

    // 表示するテキスト、色、フォントサイズを設定
    ObjectSetString(0, name, OBJPROP_TEXT, "Hello");
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrYellow);
    ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 20);

    // ラベルはチャートの右下に表示する
    ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
    ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 10);

    // 直ちに画面に反映させる
    ChartRedraw();
    return INIT_SUCCEEDED;
}

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

int OnCalculate(const int rates_total, const int prev_calculated,
                const int begin, const double &price[]) {
    return rates_total;
}

関連記事

MetaTrader/MQL: 価格情報を取得する (SymbolInfoTick, CopyRates)

更新:
作成:

あるシンボル(銘柄)の価格情報を取得する方法はいろいろ用意されています。

  • SymbolInfoTick … 最新のティック情報を取得する
  • CopyRates … 各バーの四本値を取得する
  • SymbolInfoDouble/Integer … 最新の価格情報を個別に取得する(SymbolInfoTick の方を使えば OK)

似たような関数があって混乱するかもしれませんが、ティック情報(Bid/Ask などの値動き)を取得する手段と、各バーの情報(OHLC 四本値情報)を取得する手段の 2 種類が用意されていると考えると理解しやすいです。

SymbolInfoTick … 最新のティック情報を取得する

SymbolInfoTick 関数日本語)を使用すると、指定したシンボルの最後の値動き(ティック)における Bid/Ask 値やボリュームの情報を取得することができます。

bool SymbolInfoTick(string symbol, MqlTick& tick);

得られる情報の MqlTick 構造体日本語) は次のようになっています。

MqlTick 構造体
struct MqlTick {
    datetime time;      // 価格更新時間(datetime 値)
    double bid;         // Bid 価格(売値)
    double ask;         // Ask 価格(買値)
    double last;        // 取引価格(注: ターミナル起動直後は 0.0 になる)
    ulong volume;       // 取引ボリューム
    long time_msc;      // 取引時間時間(ミリ秒)
    uint flags;         // 変化理由(TICK_FLAG_BID など)
    double volume_real; // より正確な取引ボリューム(取得できれば)
};

この構造体は、あくまで 1 ティックの情報だけを含むため、ローソク足のような四本値 (OHLC) 情報は含まれていないことに注意してください。

次のスクリプトを実行すると、カレントチャートのシンボルにおける最新価格情報を出力します。

Scripts/Test.mq5
void OnStart() {
    MqlTick tick;
    if (!SymbolInfoTick(_Symbol, tick)) {
        Print("Error SymbolInfoTick: ", GetLastError());
        return;
    }

    Print("time=", tick.time, ", ask=", tick.ask,
        ", bid=", tick.bid, ", volume=", tick.volume);
}

EA(エキスパートアドバイザー)であれば、OnTick 関数の中で SymbolInfoTick を呼び出せば、ティックが発生するごとに最新の価格を取得できます。

Experts/Test.mq5
void OnTick() {
    // 同上
}
☝️ MT4 の Ask/Bid 変数 MT4 環境では AskBid といった組み込み変数でカレントシンボルの現在価格を参照できました。 MT5 にはこのような組み込み変数は用意されていないので、SymbolInfoTick 関数などを使って価格情報を取得する必要があります。

CopyRates … 各バーの四本値 (OHLC) を取得する

CopyRates 関数日本語)を使うと、各バーの四本値 (OHLC) 情報を取得することができます。 CopyRates 関数にはいくつかのバリエーションがあり、取得するデータの位置を、ポジション(start_pos = 0 は最新のバー)で指定するか、時刻(datetime 値)で指定するかによって使い分けます。

CopyRates 関数
int CopyRates(
        string symbol_name, ENUM_TIMEFRAMES timeframe,
        int start_pos, int count, MqlRates rates_array[]);
int CopyRates(
        string symbol_name, ENUM_TIMEFRAMES timeframe,
        datetime start_time, int count, MqlRates rates_array[]);
int CopyRates(
        string symbol_name, ENUM_TIMEFRAMES timeframe,
        datetime start_time, datetime stop_time, MqlRates rates_array[]);

取得結果は次のような MqlRates 構造体日本語)の配列です。

MqlRates 構造体
struct MqlRates {
    datetime time;     // 期間開始時間
    double open;       // 始値
    double high;       // 期間中の最高値
    double low;        // 期間中の最安値
    double close;      // 終値
    long tick_volume;  // ティックボリューム
    int spread;        // スプレッド
    long real_volume;  // 取引高
};

スプレッドの情報も取得できるのが面白いですね。

次のスクリプトでは、最新のバーから 3 本分の四本値 (OHLC) 情報を取得しています。 データ格納先の配列を ArraySetAsSeries 関数日本語)でシリーズ化(時系列化)すると、配列の先頭要素が最新のバーの情報を表すようになります(デフォルトでは、配列の先頭要素は一番過去のバー情報)。

Scripts/Test.mq5
void OnStart() {
    MqlRates rates[];
    ArraySetAsSeries(rates, true);  // 先頭要素を最新バーとする
    int copied = CopyRates(_Symbol, PERIOD_CURRENT, 0, 3, rates);
    for (int i = 0; i < copied; i++) {
        Print(i, ": time=", rates[i].time,
            ", O=", rates[i].open, ", H=", rates[i].high,
            ", L=", rates[i].low, ", C=", rates[i].close,
            ", tick_volume=", rates[i].tick_volume, ", spread=", rates[i].spread);
    }
}
実行結果
0: time=2021.02.12 19:00:00, O=1.07397, H=1.07435, L=1.0736, C=1.07428, tick_volume=4880, spread=11
1: time=2021.02.12 20:00:00, O=1.0743, H=1.07461, L=1.07408, C=1.07448, tick_volume=3688, spread=11
2: time=2021.02.12 21:00:00, O=1.07447, H=1.07452, L=1.07412, C=1.07445, tick_volume=3043, spread=11

上記のように、CopyRates 関数を使うと各バーの四本値 (OHLC) 情報を MqlRates の形でまとめて取得できますが、始値 (Open) や終値 (Close) だけが欲しい場合は、代わりに以下のような関数を使って取得することができます。

例: 最新の 3 本の終値を取得する
void OnStart() {
    double closes[];
    ArraySetAsSeries(closes, true);
    int copied = CopyClose(_Symbol, PERIOD_CURRENT, 0, 3, closes);
    for (int i = 0; i < copied; i++) {
        Print(i, ": ", closes[i]);
    }
    // 配列の内容は次のように出力しても OK
    // ArrayPrint(closes);
}

SymbolInfoDouble/Integer … 最新の価格情報を個別に取得する

SymbolInfoDouble 関数日本語)などの数値プロパティ取得用の関数を使うと、あるシンボルの Ask/Bid 値などを個別に取得することができます。

Scripts/Test.mq5
void OnStart() {
    datetime time = (datetime) SymbolInfoInteger(_Symbol, SYMBOL_TIME);
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    long volume = SymbolInfoInteger(_Symbol, SYMBOL_VOLUME);
    Print("time=", time, ", ask=", ask, ", bid=", bid, ", volume=", volume);
}

SymbolInfoTick 関数で最新のティック情報 (MqlTick) を一度に取得するのと同じかと思うかもしれませんが、まさに同じ値が取得できます(^^;

SymbolTickInfo と SymbolInfoDouble のどちらで Bid/Ask 値を取得すべきか?

結論から言うと、SymbolTickInfo 関数の方を使えばよさそう です。

Bid/Ask 値を取得するのであれば、どちらの関数でも同じ値が取得できるので、違いはコードの可読性と、実行時のパフォーマンスだけです。 可読性はどちらもそんなに変わらないので、パフォーマンスを調べて速い方を使うのがよさそうです。 予想では、取得できる情報量の少ない SymbolInfoDouble の方が速いと思いましたが、プロファイリングを取ってみると、わずかに SymbolTickInfo 関数の方が速そうです。

/p/uhv9mx9/img-001.png

関連記事

メニュー

投資で実現!不労所得生活
サイトマップまくへのメッセージ