恥は/dev/nullへ by 初心者

プログラミング素人がのろのろと学んだことをつづっています♪

延長されない水平線を描画するボタン

MT4の水平線ボタンを使用して水平線を作成した場合、横方向に延長されて(チャートの端から端まで)描画されます。しかし、延長して描画したくない場合もあります。

そこで、トレンドラインを水平線代わりに使用することにしました。トレンドラインなら、ラインを「延長して描画することも、延長しないで描画することも」できるからです。

 しかし、マウス操作でトレンドラインをきっちり水平にしようとしても多少ブレてしまうことがあります。そこで、水平なトレンドラインを描画するボタンを作成しました。

 (作成といっても、このブログにアップされている「MT4用水平線描画ボタン」を少し改造しただけですが^^;。)

  

スクリーンショット

f:id:philojuan:20210224153438p:plain

 

使い方

(1)画面上部に設置されている FlatTLボタンをクリックします。
(2)チャート上の2つの地点をクリックします。

以上の操作で水平なトレンドラインが描画されます。

トレンドラインの描画位置(高さ・Y軸位置)は、最初にクリックした地点の高さとなります。一方、トレンドラインの幅(長さ)は、1回目のクリック地点と2回目のクリック地点の間となります。

 

備考

以下のコードでは、OBJPROP_SELECTEDtrueになっているので、ラインが作成された時点で「選択可能」状態になります。

 

コード

//------------------------------------------------------------------
//
// FileName: FlatTrendLineButton.mq4
//
// Feature : This indicator sets a button to draw a HORIZONTAL trend line.
//
// Usage   : After clicking the button, click two separate points on the chart.
//           
//------------------------------------------------------------------
#property copyright "Copyright 2021. PHILOJUAN"
#property link      "https://uhoho.hatenablog.jp/"
#property strict
#property indicator_chart_window

enum OnOff {OFF, ON};                    // enumでOnOff型を定義

//--------------------------------------------------------------------
// グローバル変数 (パラメーター設定の対象とするもの)
//--------------------------------------------------------------------
input OnOff deleteAtDeInit = OFF;        // インディケーター除去時にトレンドラインを全て削除

// ボタンのパラメーター
input int buttonXdis1    = 390;          // ボタンの表示位置(X軸)
input int buttonYdis1    =   4;          // ボタンの表示位置(Y軸)
input color tlColor1 = clrGold;          // 水平トレンドラインの色
ENUM_LINE_STYLE tlStyle1 = STYLE_DASH;   // 線種はダッシュ型
int  tlWidth1  = 1;                      // 太さは1

//--------------------------------------------------------------------
// グローバル変数 (パラメーター設定の対象にしないもの)
//--------------------------------------------------------------------
// CHARTEVENT_CLICK()内の[UTSUWA] という部分で使用する変数
// 初期化しているがtlColor1等の値を代入するための器に過ぎない
color TLcolor = clrAqua;     // 色
int   TLstyle = STYLE_SOLID; // 線種
int   TLwidth = 1;           // 太さ

// クリックしたXY座標を時刻と価格に変換して格納するための変数
// (step == 2 と step == 3 で使う)
datetime time1 =  0;  // 初期化の仕方が不思議だが、ChartXYToTimePriceのヘルプのとおり
double price1 = 0.0;
datetime time2 =  0;
double price2 = 0.0;
int window = 0;       // 0 はメインチャートを指す(サブウィンドウではない)

// その他
int step        = 0;             // 処理のステップ管理に使う変数
int numTL       = 0;             // 作成したトレンドラインの数
string baseName = "uhoTreLine";  // オブジェクトのベース名
string objName  = "";            // オブジェクト名に使う変数
string clickedButton = "";       // クリックされたボタン名を格納する変数

//+------------------------------------------------------------------
//| Custom indicator initialization function
//+------------------------------------------------------------------
int OnInit()
{
    MakeButton("TLbutton01", buttonXdis1, buttonYdis1, tlColor1, "FlatTL");

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

//+------------------------------------------------------------------+
//| インジケーター除去時の処理
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // オブジェクト名の先頭を使用してまとめて消去
    ObjectsDeleteAll(0, "TLbutton0");
// 今後、TLbutton01、 TLbutton02・・・と複数のボタンを設置する予定なので
// ObjectsDeleteAllを使用。 if(deleteAtDeInit) ObjectsDeleteAll(0, baseName); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // オブジェクトクリック時 if(id == CHARTEVENT_OBJECT_CLICK) { if(sparam == "TLbutton01") { if(!step) step = 1; TLcolor = tlColor1; TLstyle = tlStyle1; TLwidth = tlWidth1; clickedButton = sparam; } } // マウスクリック時 if(id == CHARTEVENT_CLICK) { // 1回目のクリック時(ボタンをクリックした時) if(step == 1) step = 2; // このstep == 1 の段階が無いと、ボタンをクリックしたのと同時に // 次の処理が実行されてしまう。 // 2回目のクリック時(1つ目の地点をクリックした時) else if(step == 2) { // クリックしたXY座標を取得 int x1 = (int)lparam; int y1 = (int)dparam; // 上述の2行については ChartXYToTimePrice関数のヘルプに同様の例文がある // https://docs.mql4.com/chart_operations/chartxytotimeprice // クリックした地点の座標を時間と価格に変換してtime1とprice1に代入 if(!ChartXYToTimePrice(0, x1, y1, window, time1, price1)) { Print("ChartXYToTimePrice error ", GetLastError()); // エラーメッセージを表示 } step = 3; } // 3回目のクリック時(2つ目の地点をクリックした時) else if(step == 3) { // クリックしたXY座標を取得 int x2 = (int)lparam; int y2 = (int)dparam; // クリックした地点の座標を時間と価格に変換してtime2とprice2に代入 if(!ChartXYToTimePrice(0, x2, y2, window, time2, price2)) { Print("ChartXYToTimePrice error ", GetLastError()); } // オブジェクト名の最後に番号を付ける objName = baseName + IntegerToString(numTL); // 名前の例 // 最初のオブジェクト uhoTreLine0 // 2番目のオブジェクト uhoTreLine1 // 3番目のオブジェクト uhoTreLine2 // 既に同じ名前のオブジェクトがあった場合への対応
            while(ObjectFind(0, objName) >= 0) {
                numTL++;
                objName = baseName + IntegerToString(numTL);
            }
           // 説明 // 既にuhoTreLine0 というオブジェクトがあった場合は // uhoTreLine1というオブジェクトを作る // [UTSUWA] // クリック位置に水平なトレンドラインを描画(1度しか登場しないので、自作関数にはせず) ObjectCreate( 0, objName, OBJ_TREND, 0, time1, price1, time2, price1); // 水平にするためにprice1を2回使用 ObjectSetInteger(0, objName, OBJPROP_COLOR, TLcolor); ObjectSetInteger(0, objName, OBJPROP_STYLE, TLstyle); ObjectSetInteger(0, objName, OBJPROP_WIDTH, TLwidth); ObjectSetInteger(0, objName, OBJPROP_BACK, false); ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, true); ObjectSetInteger(0, objName, OBJPROP_SELECTED, true); // ライン作成後、選択状態にする ObjectSetInteger(0, objName, OBJPROP_HIDDEN, false); ObjectSetInteger(0, objName, OBJPROP_ZORDER, 0); ObjectSetInteger(0, objName, OBJPROP_RAY_RIGHT, false); // ラインを延長しない step = 0; ObjectSet(clickedButton, OBJPROP_STATE, false); } // else if(step == 3) ここまで } } void MakeButton(string buttonName, // オブジェクト名 int xDis, // X座標 int yDis, // Y座標 color bgColor, // ボタンの背景色 string text // ボタンに表示するテキスト ) { ObjectCreate( 0, buttonName, OBJ_BUTTON , 0, 0, 0); ObjectSetInteger(0, buttonName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, buttonName, OBJPROP_XDISTANCE, xDis); ObjectSetInteger(0, buttonName, OBJPROP_YDISTANCE, yDis); ObjectSetInteger(0, buttonName, OBJPROP_XSIZE, 40); ObjectSetInteger(0, buttonName, OBJPROP_YSIZE, 18); ObjectSetInteger(0, buttonName, OBJPROP_COLOR, clrBlack); // ボタン内の文字の色 ObjectSetInteger(0, buttonName, OBJPROP_BGCOLOR, bgColor); ObjectSetInteger(0, buttonName, OBJPROP_BORDER_COLOR, clrGray); ObjectSetInteger(0, buttonName, OBJPROP_BORDER_TYPE, BORDER_RAISED); ObjectSetInteger(0, buttonName, OBJPROP_BACK, false); ObjectSetInteger(0, buttonName, OBJPROP_STATE, false); ObjectSetInteger(0, buttonName, OBJPROP_HIDDEN, true); ObjectSetInteger(0, buttonName, OBJPROP_ZORDER, 1); ObjectSetInteger(0, buttonName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, buttonName, OBJPROP_SELECTED, false); ObjectSetInteger(0, buttonName, OBJPROP_FONTSIZE, 7); ObjectSetString( 0, buttonName, OBJPROP_FONT, "HackGen"); ObjectSetString( 0, buttonName, OBJPROP_TEXT, text); }