アンカーポイントの定数
アンカーポイントの定数は、オブジェクトやチャートのアンカーポイントを設定するときに使われます。
アンカーポイントとは、オブジェクトを表示するときに基準となる座標のことです。
主に、ObjectSetInteger関数で使われます。
簡単に関数の説明です。
- ObjectSetInteger関数:オブジェクトの状態を設定する
それぞれ、OBJPROP_ANCHORと、OBJPROP_CORNERの設定値として、アンカーポイントの定数が使われます。
アンカーポイントの定数(ENUM_ANCHOR_POINT)
| 定数 | 説明 |
| ANCHOR_LEFT_UPPER | 左上を基準 |
| ANCHOR_LEFT | 中央左を基準 |
| ANCHOR_LEFT_LOWER | 左下を基準 |
| ANCHOR_LOWER | 中央下を基準 |
| ANCHOR_RIGHT_LOWER | 右下を基準 |
| ANCHOR_RIGHT | 中央右を基準 |
| ANCHOR_RIGHT_UPPER | 右上を基準 |
| ANCHOR_UPPER | 中央上を基準 |
| ANCHOR_CENTER | 中央を基準 |
アンカーポイントの定数の使い方
主に、ObjectSetInteger関数で使用されます。
それぞれ、OBJPROP_ANCHORと、OBJPROP_CORNERの設定値として、アンカーポイントの定数が使われます。
上記の定数を入力しましょう。
すると、その定数に対応したアンカーポイントが設定されます。
例えば、以下のように使用します。
//ObjectSetInteger関数
//オブジェクトの左上を基準にする
bool objectSetInteger1 = ObjectSetInteger(ChartID(), "自動売買を作ろう!", OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
//チャートの左上を基準にする
bool objectSetInteger2 = ObjectSetInteger(ChartID(), "自動売買を作ろう!", OBJPROP_CORNER, ANCHOR_LEFT_UPPER);
返り値はbool型です。
成功すればture、失敗すればfalseが返ってきます。
実用的なプログラム例
ここからは、アンカーポイントの定数を使った実用的なプログラム例を紹介します。
例1:チャート右上にスプレッド表示ラベルを作成する
チャートの右上隅にリアルタイムのスプレッドを表示するインジケーターです。ANCHOR_RIGHT_UPPERを使って、ラベルを右上基準で配置しています。
//+------------------------------------------------------------------+
//| SpreadLabel.mq4 - チャート右上にスプレッドを表示するインジケーター
//+------------------------------------------------------------------+
#property indicator_chart_window
// ラベルのオブジェクト名
string labelName = "SpreadLabel";
//+------------------------------------------------------------------+
//| 初期化関数 |
//+------------------------------------------------------------------+
int OnInit()
{
// ラベルオブジェクトを作成する
ObjectCreate(ChartID(), labelName, OBJ_LABEL, 0, 0, 0);
// チャートの右上隅を基準コーナーに設定する
ObjectSetInteger(ChartID(), labelName, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
// オブジェクトのアンカーポイントを右上に設定する
// これにより、ラベルの右上が指定座標に一致する
ObjectSetInteger(ChartID(), labelName, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
// チャート右上隅からのX方向の距離(ピクセル)
ObjectSetInteger(ChartID(), labelName, OBJPROP_XDISTANCE, 10);
// チャート右上隅からのY方向の距離(ピクセル)
ObjectSetInteger(ChartID(), labelName, OBJPROP_YDISTANCE, 20);
// フォントサイズを設定する
ObjectSetInteger(ChartID(), labelName, OBJPROP_FONTSIZE, 14);
// 文字色を設定する(黄色)
ObjectSetInteger(ChartID(), labelName, OBJPROP_COLOR, clrYellow);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| ティックごとに呼ばれる関数 |
//+------------------------------------------------------------------+
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[])
{
// 現在のスプレッドを取得する(ポイント単位)
int currentSpread = (int)MarketInfo(Symbol(), MODE_SPREAD);
// ラベルのテキストにスプレッド値を表示する
ObjectSetString(ChartID(), labelName, OBJPROP_TEXT,
"Spread: " + IntegerToString(currentSpread) + " pts");
return(rates_total);
}
//+------------------------------------------------------------------+
//| 終了時にオブジェクトを削除する |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectDelete(ChartID(), labelName);
}
例2:チャート四隅に情報パネルを表示する
チャートの四隅それぞれにラベルを配置し、通貨ペア名・時間足・Bid価格・Ask価格を表示する例です。CORNER定数とANCHOR定数を組み合わせることで、各隅に正しく配置できます。
//+------------------------------------------------------------------+
//| FourCornerInfo.mq4 - チャート四隅に情報を表示するインジケーター
//+------------------------------------------------------------------+
#property indicator_chart_window
// 4つのラベル名を配列で管理する
string labels[4] = {"LabelLU", "LabelRU", "LabelLB", "LabelRB"};
//+------------------------------------------------------------------+
//| ラベルを1つ作成するヘルパー関数 |
//+------------------------------------------------------------------+
void CreateCornerLabel(string name,
ENUM_BASE_CORNER corner,
ENUM_ANCHOR_POINT anchor,
int xDist, int yDist, color clr)
{
// ラベルオブジェクトを作成する
ObjectCreate(ChartID(), name, OBJ_LABEL, 0, 0, 0);
// チャートのどの隅を基準にするかを設定する
ObjectSetInteger(ChartID(), name, OBJPROP_CORNER, corner);
// オブジェクトのアンカーポイントを設定する
ObjectSetInteger(ChartID(), name, OBJPROP_ANCHOR, anchor);
// X方向の距離(ピクセル)
ObjectSetInteger(ChartID(), name, OBJPROP_XDISTANCE, xDist);
// Y方向の距離(ピクセル)
ObjectSetInteger(ChartID(), name, OBJPROP_YDISTANCE, yDist);
// フォントサイズを設定する
ObjectSetInteger(ChartID(), name, OBJPROP_FONTSIZE, 12);
// 文字色を設定する
ObjectSetInteger(ChartID(), name, OBJPROP_COLOR, clr);
}
//+------------------------------------------------------------------+
//| 初期化関数 |
//+------------------------------------------------------------------+
int OnInit()
{
// 左上:通貨ペア名を表示(アンカーポイント=左上)
CreateCornerLabel(labels[0], CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER,
10, 20, clrWhite);
// 右上:時間足情報を表示(アンカーポイント=右上)
CreateCornerLabel(labels[1], CORNER_RIGHT_UPPER, ANCHOR_RIGHT_UPPER,
10, 20, clrAqua);
// 左下:Bid価格を表示(アンカーポイント=左下)
CreateCornerLabel(labels[2], CORNER_LEFT_LOWER, ANCHOR_LEFT_LOWER,
10, 10, clrLime);
// 右下:Ask価格を表示(アンカーポイント=右下)
CreateCornerLabel(labels[3], CORNER_RIGHT_LOWER, ANCHOR_RIGHT_LOWER,
10, 10, clrOrange);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| ティックごとに呼ばれる関数 |
//+------------------------------------------------------------------+
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[])
{
// 左上に通貨ペア名を表示する
ObjectSetString(ChartID(), labels[0], OBJPROP_TEXT, Symbol());
// 右上に現在の時間足を表示する
ObjectSetString(ChartID(), labels[1], OBJPROP_TEXT,
"TF: " + IntegerToString(Period()) + "min");
// 左下にBid価格を表示する
ObjectSetString(ChartID(), labels[2], OBJPROP_TEXT,
"Bid: " + DoubleToString(Bid, Digits));
// 右下にAsk価格を表示する
ObjectSetString(ChartID(), labels[3], OBJPROP_TEXT,
"Ask: " + DoubleToString(Ask, Digits));
return(rates_total);
}
//+------------------------------------------------------------------+
//| 終了時に全ラベルを削除する |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
for(int i = 0; i < 4; i++)
{
ObjectDelete(ChartID(), labels[i]);
}
}
例3:EAでエントリー時にチャート上に矢印マークを表示する
EAで売買が発生したとき、チャート上のエントリーポイントに矢印オブジェクトを配置する例です。OBJ_ARROW_UPやOBJ_ARROW_DOWNではANCHOR_TOPやANCHOR_BOTTOMを指定することで、矢印の先端がエントリー価格に正確に一致するよう調整できます。
//+------------------------------------------------------------------+
//| EntryArrowEA.mq4 - エントリー位置に矢印を表示するEA |
//+------------------------------------------------------------------+
#property strict
// 矢印の連番管理用カウンタ
int arrowCount = 0;
//+------------------------------------------------------------------+
//| 買いエントリー矢印を表示する関数 |
//+------------------------------------------------------------------+
void DrawBuyArrow(datetime entryTime, double entryPrice)
{
// ユニークなオブジェクト名を生成する
string objName = "BuyArrow_" + IntegerToString(arrowCount);
arrowCount++;
// 上向き矢印オブジェクトを作成する
ObjectCreate(ChartID(), objName, OBJ_ARROW_UP, 0, entryTime, entryPrice);
// アンカーポイントをTOP(上端)に設定する
// 矢印の先端(上端)がエントリー価格の位置に来る
ObjectSetInteger(ChartID(), objName, OBJPROP_ANCHOR, ANCHOR_TOP);
// 矢印の色を青に設定する(買いシグナル)
ObjectSetInteger(ChartID(), objName, OBJPROP_COLOR, clrDodgerBlue);
// 矢印の幅を設定する
ObjectSetInteger(ChartID(), objName, OBJPROP_WIDTH, 2);
}
//+------------------------------------------------------------------+
//| 売りエントリー矢印を表示する関数 |
//+------------------------------------------------------------------+
void DrawSellArrow(datetime entryTime, double entryPrice)
{
// ユニークなオブジェクト名を生成する
string objName = "SellArrow_" + IntegerToString(arrowCount);
arrowCount++;
// 下向き矢印オブジェクトを作成する
ObjectCreate(ChartID(), objName, OBJ_ARROW_DOWN, 0, entryTime, entryPrice);
// アンカーポイントをBOTTOM(下端)に設定する
// 矢印の先端(下端)がエントリー価格の位置に来る
ObjectSetInteger(ChartID(), objName, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
// 矢印の色を赤に設定する(売りシグナル)
ObjectSetInteger(ChartID(), objName, OBJPROP_COLOR, clrRed);
// 矢印の幅を設定する
ObjectSetInteger(ChartID(), objName, OBJPROP_WIDTH, 2);
}
//+------------------------------------------------------------------+
//| ティックごとに呼ばれる関数 |
//+------------------------------------------------------------------+
void OnTick()
{
// 移動平均のゴールデンクロス・デッドクロスで売買判定する例
double maFast0 = iMA(Symbol(), 0, 5, 0, MODE_SMA, PRICE_CLOSE, 0);
double maFast1 = iMA(Symbol(), 0, 5, 0, MODE_SMA, PRICE_CLOSE, 1);
double maSlow0 = iMA(Symbol(), 0, 20, 0, MODE_SMA, PRICE_CLOSE, 0);
double maSlow1 = iMA(Symbol(), 0, 20, 0, MODE_SMA, PRICE_CLOSE, 1);
// 現在ポジションがない場合のみエントリーする
if(OrdersTotal() == 0)
{
// ゴールデンクロス:短期MAが長期MAを上抜け → 買い
if(maFast1 <= maSlow1 && maFast0 > maSlow0)
{
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "BuyEntry", 0, 0, clrBlue);
if(ticket > 0)
{
// 買いエントリー矢印をチャートに描画する
DrawBuyArrow(TimeCurrent(), Ask);
}
}
// デッドクロス:短期MAが長期MAを下抜け → 売り
if(maFast1 >= maSlow1 && maFast0 < maSlow0)
{
int ticket = OrderSend(Symbol(), OP_SELL, 0.1, Bid, 3, 0, 0, "SellEntry", 0, 0, clrRed);
if(ticket > 0)
{
// 売りエントリー矢印をチャートに描画する
DrawSellArrow(TimeCurrent(), Bid);
}
}
}
}
//+------------------------------------------------------------------+
//| 終了時に全矢印オブジェクトを削除する |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// "BuyArrow_"で始まるオブジェクトを全削除する
ObjectsDeleteAll(ChartID(), "BuyArrow_");
// "SellArrow_"で始まるオブジェクトを全削除する
ObjectsDeleteAll(ChartID(), "SellArrow_");
}
OBJ_ARROW_UPにANCHOR_TOPを設定すると矢印の先端がローソク足の安値側に正確に接し、OBJ_ARROW_DOWNにANCHOR_BOTTOMを設定すると矢印の先端が高値側に正確に接します。アンカーポイントを適切に設定しないと、矢印がずれて表示されてしまうので注意しましょう。
例4:チャート左下に取引状況ダッシュボードを表示する
EAに組み込んで使える、取引状況をリアルタイム表示するダッシュボードの例です。チャート左下にANCHOR_LEFT_LOWERを使って複数行のラベルを整列配置し、保有ポジション数・含み損益・口座残高を表示します。
//+------------------------------------------------------------------+
//| TradeDashboard.mq4 - 取引状況ダッシュボードを表示するEA |
//+------------------------------------------------------------------+
#property strict
// ダッシュボードのラベル名を定義する
string dashLabels[4] = {"DashTitle", "DashPositions", "DashProfit", "DashBalance"};
// ラベル1行あたりの高さ(ピクセル)
int lineHeight = 22;
//+------------------------------------------------------------------+
//| ダッシュボード用ラベルを1行作成する関数 |
//+------------------------------------------------------------------+
void CreateDashLabel(string name, int lineIndex, color clr)
{
// ラベルオブジェクトを作成する
ObjectCreate(ChartID(), name, OBJ_LABEL, 0, 0, 0);
// チャートの左下隅を基準にする
ObjectSetInteger(ChartID(), name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
// アンカーポイントを左下に設定する
// これにより、テキストの左下端が指定座標に一致する
ObjectSetInteger(ChartID(), name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
// X方向の距離を設定する(左端から15ピクセル)
ObjectSetInteger(ChartID(), name, OBJPROP_XDISTANCE, 15);
// Y方向の距離を設定する(下から行番号に応じて上へずらす)
// lineIndex=0が一番下、数字が大きいほど上に配置される
ObjectSetInteger(ChartID(), name, OBJPROP_YDISTANCE, 15 + lineIndex * lineHeight);
// フォントサイズを設定する
ObjectSetInteger(ChartID(), name, OBJPROP_FONTSIZE, 11);
// フォントを等幅フォントに設定する(数値が揃って見やすくなる)
ObjectSetString(ChartID(), name, OBJPROP_FONT, "Courier New");
// 文字色を設定する
ObjectSetInteger(ChartID(), name, OBJPROP_COLOR, clr);
}
//+------------------------------------------------------------------+
//| 保有ポジションの合計損益を計算する関数 |
//+------------------------------------------------------------------+
double CalcTotalProfit()
{
double totalProfit = 0.0;
// 全オーダーをループして含み損益を合計する
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// 現在の通貨ペアのポジションのみ集計する
if(OrderSymbol() == Symbol())
{
totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
}
}
}
return totalProfit;
}
//+------------------------------------------------------------------+
//| 現在の通貨ペアの保有ポジション数を取得する関数 |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol())
{
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| 初期化関数 |
//+------------------------------------------------------------------+
int OnInit()
{
// ダッシュボードの各行を作成する(下から順に配置)
// 行0(一番下):口座残高
CreateDashLabel(dashLabels[3], 0, clrGold);
// 行1:含み損益
CreateDashLabel(dashLabels[2], 1, clrWhite);
// 行2:保有ポジション数
CreateDashLabel(dashLabels[1], 2, clrWhite);
// 行3(一番上):タイトル
CreateDashLabel(dashLabels[0], 3, clrYellow);
// タイトル行のテキストを設定する(固定文字列)
ObjectSetString(ChartID(), dashLabels[0], OBJPROP_TEXT, "== Trade Dashboard ==");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| ティックごとに呼ばれる関数 |
//+------------------------------------------------------------------+
void OnTick()
{
// 保有ポジション数を更新表示する
int posCount = CountPositions();
ObjectSetString(ChartID(), dashLabels[1], OBJPROP_TEXT,
"Positions : " + IntegerToString(posCount));
// 含み損益を計算して更新表示する
double profit = CalcTotalProfit();
ObjectSetString(ChartID(), dashLabels[2], OBJPROP_TEXT,
"Profit : " + DoubleToString(profit, 2) + " " + AccountCurrency());
// 含み損益がプラスなら緑、マイナスなら赤に色を変える
if(profit >= 0)
ObjectSetInteger(ChartID(), dashLabels[2], OBJPROP_COLOR, clrLime);
else
ObjectSetInteger(ChartID(), dashLabels[2], OBJPROP_COLOR, clrRed);
// 口座残高を更新表示する
ObjectSetString(ChartID(), dashLabels[3], OBJPROP_TEXT,
"Balance : " + DoubleToString(AccountBalance(), 2) + " " + AccountCurrency());
}
//+------------------------------------------------------------------+
//| 終了時にダッシュボードのオブジェクトを全削除する |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
for(int i = 0; i < 4; i++)
{
ObjectDelete(ChartID(), dashLabels[i]);
}
}
ANCHOR_LEFT_LOWERを指定することで、チャート左下から上方向に向かって各行が自然に並びます。もしアンカーポイントをANCHOR_LEFT_UPPERにしてしまうと、テキストの上端が基準になるため、行の重なりや位置のずれが起こります。複数行を並べるときは、アンカーポイントの方向と配置の方向を揃えることが大切です。
例5:チャート中央にトレードシグナルのテキストを表示する
チャートの中央にANCHOR_CENTERを使って大きなシグナルテキスト(「BUY」「SELL」「WAIT」)を表示するインジケーターの例です。ANCHOR_CENTERを使うことで、テキストの長さに関係なく常にチャートの真ん中に表示されます。
//+------------------------------------------------------------------+
//| CenterSignal.mq4 - チャート中央にシグナルを表示するインジケーター |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property strict
// シグナル表示用のラベル名
string signalLabel = "CenterSignalLabel";
//+------------------------------------------------------------------+
//| 初期化関数 |
//+------------------------------------------------------------------+
int OnInit()
{
// ラベルオブジェクトを作成する
ObjectCreate(ChartID(), signalLabel, OBJ_LABEL, 0, 0, 0);
// チャートの左上隅を基準コーナーに設定する
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER);
// アンカーポイントを中央に設定する
// テキストの中心が指定座標に一致するようになる
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_ANCHOR, ANCHOR_CENTER);
// チャートの幅と高さの中央にラベルを配置する
// ChartGetInteger関数でチャートの幅・高さをピクセルで取得する
int chartWidth = (int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS);
int chartHeight = (int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS);
// X方向の距離をチャート幅の半分に設定する
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_XDISTANCE, chartWidth / 2);
// Y方向の距離をチャート高さの半分に設定する
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_YDISTANCE, chartHeight / 2);
// フォントサイズを大きく設定する(目立つように)
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_FONTSIZE, 32);
// 初期テキストを設定する
ObjectSetString(ChartID(), signalLabel, OBJPROP_TEXT, "WAIT");
// 初期色をグレーに設定する
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_COLOR, clrGray);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| ティックごとに呼ばれる関数 |
//+------------------------------------------------------------------+
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[])
{
// チャートサイズが変わった場合に備えて、毎回中央座標を再計算する
int chartWidth = (int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS);
int chartHeight = (int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS);
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_XDISTANCE, chartWidth / 2);
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_YDISTANCE, chartHeight / 2);
// 移動平均を使ったシンプルなシグナル判定
double maFast = iMA(Symbol(), 0, 10, 0, MODE_SMA, PRICE_CLOSE, 0);
double maSlow = iMA(Symbol(), 0, 50, 0, MODE_SMA, PRICE_CLOSE, 0);
// 短期MAが長期MAより上 → 買いシグナル
if(maFast > maSlow)
{
ObjectSetString(ChartID(), signalLabel, OBJPROP_TEXT, "BUY");
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_COLOR, clrDodgerBlue);
}
// 短期MAが長期MAより下 → 売りシグナル
else if(maFast < maSlow)
{
ObjectSetString(ChartID(), signalLabel, OBJPROP_TEXT, "SELL");
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_COLOR, clrRed);
}
// ほぼ同じ → 待機
else
{
ObjectSetString(ChartID(), signalLabel, OBJPROP_TEXT, "WAIT");
ObjectSetInteger(ChartID(), signalLabel, OBJPROP_COLOR, clrGray);
}
return(rates_total);
}
//+------------------------------------------------------------------+
//| 終了時にオブジェクトを削除する |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectDelete(ChartID(), signalLabel);
}
ANCHOR_CENTERを使うことで、テキストが「BUY」「SELL」「WAIT」と変化しても、常にチャートの中央に表示されます。もしANCHOR_LEFT_UPPERを使った場合、テキストの左上端が中央座標に来るため、文字列の長さによって見た目の位置がずれてしまいます。中央配置にはANCHOR_CENTERが最適です。


