チャート上に節目となるレートに水平線を描画する

この記事を共有

テストコード

//+------------------------------------------------------------------+
//|                                                  IND_RateSection |
//+------------------------------------------------------------------+
//|処理概要:チャート上に節目となるレートに水平線を描画する
//|          大節目/中節目/小節目の3段階で描画する
//|          円単位(USDJPY等) :1 / 0.5 / 0.1
//|          指数(JP225等)      :1000 / 500 / 100
//|          US500              :100 / 50 / 10
//+------------------------------------------------------------------+
//| 26/10/05    1.01    節目を間隔の倍数で丸めるよう修正(指数CFD等でキリ番にならない不具合)。
//|                     大節目/中節目/小節目の3段階描画に変更し、単位をシンボルから自動判定。
//|                     節目ごとに線の色・種類・太さを指定できるように変更。
//|                     中節目・小節目の表示/非表示を選択できるように変更。
//|                     右側スケールの数値表示(自動/表示/非表示)を選択できるように変更。
//|
//+------------------------------------------------------------------+

#property copyright "ryo m."
#property link      "http://ml/"
#property version   "1.01"
#property strict
#property indicator_chart_window

// プログラムの説明
#property description "チャート上に節目となるレートに水平線を描画する(大節目/中節目/小節目)"

#define        OBJ_OPTION_HEAD                "IRSO_"                           // レート表示オブジェクト用ヘッダ名
#define        DISP_HALF_NUM                 100                                // 基準レートから上下に描画する小節目の本数

enum e_profile{
    E_PROFILE_AUTO      = 0     // 自動(シンボルから判定)
,   E_PROFILE_FX        = 1     // 円単位(1 / 0.5 / 0.1)
,   E_PROFILE_INDEX     = 2     // 指数(1000 / 500 / 100)
,   E_PROFILE_US500     = 3     // US500(100 / 50 / 10)
};

enum e_style{
    E_STYLE_SOLID       = STYLE_SOLID       // 実線
,   E_STYLE_DOT         = STYLE_DOT         // 点線
,   E_STYLE_DASH        = STYLE_DASH        // 破線
,   E_STYLE_DASHDOT     = STYLE_DASHDOT     // 破線-点線
,   E_STYLE_DASHDOTDOT  = STYLE_DASHDOTDOT  // 破線-点線点線
};

enum e_width{
    E_WIDTH_1   = 1     // 1
,   E_WIDTH_2   = 2     // 2
,   E_WIDTH_3   = 3     // 3
,   E_WIDTH_4   = 4     // 4
,   E_WIDTH_5   = 5     // 5
};

enum e_label{
    E_LABEL_AUTO    = 0     // 自動(数値が重なる節目は非表示)
,   E_LABEL_SHOW    = 1     // 表示
,   E_LABEL_HIDE    = 2     // 非表示
};

enum e_back{
    E_DISP_FRONT    = (int)false        // 前面表示
,   E_DISP_BACK     = (int)true         // 背面表示
};

sinput    e_profile _Profile         = E_PROFILE_AUTO;                       // 節目の単位
sinput    color     _MajorLineColor  = clrYellow;                            // 大節目(1円/1000/100)の線の色
sinput    e_style   _MajorLineStyle  = E_STYLE_SOLID;                        // 大節目(1円/1000/100)の線の種類
sinput    e_width   _MajorLineWidth  = E_WIDTH_1;                            // 大節目(1円/1000/100)の線の太さ
sinput    bool      _MidLineShow     = true;                                 // 中節目(0.5円/500/50)を表示する
sinput    color     _MidLineColor    = clrLightSkyBlue;                      // 中節目(0.5円/500/50)の線の色
sinput    e_style   _MidLineStyle    = E_STYLE_DOT;                          // 中節目(0.5円/500/50)の線の種類
sinput    e_width   _MidLineWidth    = E_WIDTH_1;                            // 中節目(0.5円/500/50)の線の太さ
sinput    bool      _MinorLineShow   = false;                                // 小節目(0.1円/100/10)を表示する
sinput    color     _MinorLineColor  = clrDimGray;                           // 小節目(0.1円/100/10)の線の色
sinput    e_style   _MinorLineStyle  = E_STYLE_DOT;                          // 小節目(0.1円/100/10)の線の種類
sinput    e_width   _MinorLineWidth  = E_WIDTH_1;                            // 小節目(0.1円/100/10)の線の太さ
sinput    e_back    _SetLineBack     = E_DISP_FRONT;                         // 線の表示位置
sinput    e_label   _PriceLabel      = E_LABEL_AUTO;                         // 右側スケールの数値表示
sinput    int       _LabelMinGap     = 16;                                   // 自動時に数値を表示する最小間隔[px]

double  g_majorstep     = 0;        // 現在の大節目の間隔[価格]
int     g_labelflags    = -1;       // 現在の数値表示状態(bit0:大 bit1:中 bit2:小、-1:未描画)

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit() {

    EventSetTimer(60);
    DrawRateLine();

    return(INIT_SUCCEEDED);
}


//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    EventKillTimer();
    ObjectsDeleteAll( 0 , OBJ_OPTION_HEAD);
}


//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

    // 拡大縮小・スクロールで表示範囲が変わった場合、数値表示の要否を再判定
    if ( id != CHARTEVENT_CHART_CHANGE || _PriceLabel != E_LABEL_AUTO || g_majorstep <= 0 ) {
        return;
    }
    if ( GetLabelFlags( g_majorstep ) != g_labelflags ) {
        DrawRateLine();
    }
}


//+------------------------------------------------------------------+
//| 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[])
{

    bool        testbool;
    datetime    gettime[];
    int         cret;

//    testbool = IsTesting();
    testbool = MQLInfoInteger(MQL_TESTER);

    if ( testbool == true ) {
        Print("デバッグテスト");
        static  datetime lasttime;
                datetime temptime;

//        temptime    = iTime(NULL,Period(),0);
        cret        = CopyTime( Symbol(),Period(),0,1,gettime);
        if ( cret < 0 ) {
            return rates_total;
        }
        temptime        = gettime[0];


        if ( temptime != lasttime ) {                // 時間足が確定時にtrue
            lasttime = temptime;
        } else {
            return rates_total;
        }

        DrawRateLine();

    }

    return(rates_total);
}


#define        DRAWTIME    60    // 描画間隔[分]

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer() {

    static int    timer_count        = DRAWTIME;


    if ( timer_count >= DRAWTIME ) {
        DrawRateLine();
        timer_count = 0;
    } else if ( _PriceLabel == E_LABEL_AUTO && g_majorstep > 0 && GetLabelFlags( g_majorstep ) != g_labelflags ) {
        DrawRateLine();     // 初期化直後など表示範囲が未確定だった場合の再判定
    }

    timer_count++;

}


//+------------------------------------------------------------------+
//| 関数名    :DrawRateLine
//| 概要    :前日終値を基準に、小節目間隔で上下に水平線を描画する
//| 備考    :大節目=小節目の10倍、中節目=小節目の5倍の位置
//| ―――――――――――――――――――――――――――――――――
//| 戻り値    :無し
//| 引数    :無し
//+------------------------------------------------------------------+
void DrawRateLine( void ) {

    double    nowrate;
    double    majorstep;
    double    minorstep;
    double    disprate;
    long      baseindex;
    long      lineindex;
    int       icount;
    color     linecolor;
    int       linestyle;
    int       linewidth;
    bool      showlabel;
    int       labelflags;
    int       objtype;
    datetime  lefttime;
    string    objname;

    int       cret;
    double    getrate[];

    cret        = CopyClose( Symbol(),PERIOD_D1,1,1,getrate);    // 前日日足終値取得
    if ( cret < 0 ) {
        printf("日足データ取得エラー");
        return;
    }
    nowrate        = getrate[0];
//    nowrate        = iClose(Symbol(),PERIOD_D1,1);

    majorstep   = GetMajorStep( nowrate );
    minorstep   = majorstep / 10.0;
    labelflags  = GetLabelFlags( majorstep );

    // 数値非表示の線(トレンドライン)の始点は最古の足
    lefttime    = iTime( Symbol() , Period() , Bars( Symbol() , Period() ) - 1 );

    // 小節目の倍数に丸めた基準位置(Digitsに依存させない)
    baseindex   = (long)MathRound( nowrate / minorstep );

    for ( icount = -DISP_HALF_NUM ; icount <= DISP_HALF_NUM ; icount++ ) {
        lineindex   = baseindex + icount;
        disprate    = NormalizeDouble( (double)lineindex * minorstep , Digits() );
        if ( disprate <= 0 ) {
            continue;
        }

        if ( lineindex % 10 == 0 ) {            // 大節目
            linecolor   = _MajorLineColor;
            linestyle   = _MajorLineStyle;
            linewidth   = _MajorLineWidth;
            showlabel   = ( ( labelflags & 1 ) != 0 );
        } else if ( lineindex % 5 == 0 ) {     // 中節目
            if ( !_MidLineShow ) {
                continue;
            }
            linecolor   = _MidLineColor;
            linestyle   = _MidLineStyle;
            linewidth   = _MidLineWidth;
            showlabel   = ( ( labelflags & 2 ) != 0 );
        } else {                                // 小節目
            if ( !_MinorLineShow ) {
                continue;
            }
            linecolor   = _MinorLineColor;
            linestyle   = _MinorLineStyle;
            linewidth   = _MinorLineWidth;
            showlabel   = ( ( labelflags & 4 ) != 0 );
        }

        objname = StringFormat( "%s %s" , OBJ_OPTION_HEAD , DoubleToString( disprate , Digits() ));

        // 数値表示あり:水平線(右側スケールに数値が出る)
        // 数値表示なし:右方向に延長した水平なトレンドライン(スケールに数値が出ない)
        objtype = showlabel ? OBJ_HLINE : OBJ_TREND;
        if ( ObjectFind(0,objname) >= 0 && ObjectGetInteger(0,objname,OBJPROP_TYPE) != objtype ) {
            ObjectDelete( 0 , objname );
        }

        if (ObjectFind(0,objname) == -1) {
            if ( showlabel ) {
                ObjectCreate(    0,objname, OBJ_HLINE, 0 , 0 , disprate );
            } else {
                ObjectCreate(    0,objname, OBJ_TREND, 0 , lefttime , disprate , lefttime + PeriodSeconds() , disprate );
                ObjectSetInteger(0,objname, OBJPROP_RAY_RIGHT, true);
            }
            ObjectSetInteger(    0,objname, OBJPROP_COLOR, linecolor);
            ObjectSetInteger(    0,objname, OBJPROP_STYLE, linestyle);
            ObjectSetInteger(    0,objname, OBJPROP_WIDTH, linewidth);
            ObjectSetInteger(    0,objname, OBJPROP_BACK,  _SetLineBack);
            ObjectSetInteger(    0,objname, OBJPROP_SELECTABLE,false);
            ObjectSetInteger(    0,objname, OBJPROP_SELECTED,false);
        }
    }

    g_majorstep     = majorstep;
    g_labelflags    = labelflags;
    ChartRedraw( 0 );
}

//+------------------------------------------------------------------+
//| 関数名    :GetLabelFlags
//| 概要    :節目ごとに右側スケールへ数値を表示するかを判定する
//| 備考    :自動時は、節目の間隔が画面上で _LabelMinGap[px] 以上の場合のみ表示
//|           (表示範囲が取得できない場合は非表示)
//| ―――――――――――――――――――――――――――――――――
//| 戻り値    :int       bit0:大節目 bit1:中節目 bit2:小節目
//| 引数    :double    大節目の間隔[価格]
//+------------------------------------------------------------------+
int GetLabelFlags( double in_majorstep ) {

    double    pricerange;
    double    pxperprice;
    int       flags = 0;

    if ( _PriceLabel == E_LABEL_SHOW ) {
        return 7;
    }
    if ( _PriceLabel == E_LABEL_HIDE ) {
        return 0;
    }

    pricerange  = ChartGetDouble( 0 , CHART_PRICE_MAX , 0 ) - ChartGetDouble( 0 , CHART_PRICE_MIN , 0 );
    if ( pricerange <= 0 ) {
        return 0;
    }
    pxperprice  = (double)ChartGetInteger( 0 , CHART_HEIGHT_IN_PIXELS , 0 ) / pricerange;

    if ( in_majorstep * pxperprice >= _LabelMinGap ) {
        flags |= 1;
    }
    if ( in_majorstep / 2.0 * pxperprice >= _LabelMinGap ) {
        flags |= 2;
    }
    if ( in_majorstep / 10.0 * pxperprice >= _LabelMinGap ) {
        flags |= 4;
    }
    return flags;
}

//+------------------------------------------------------------------+
//| 関数名    :GetMajorStep
//| 概要    :大節目の間隔を返す(円単位:1、指数:1000、US500:100)
//| 備考    :自動判定はシンボル名(US500/JP225)を優先し、
//|           それ以外はレートが1000以上なら指数とみなす
//| ―――――――――――――――――――――――――――――――――
//| 戻り値    :double    大節目の間隔[価格]
//| 引数    :double    基準レート
//+------------------------------------------------------------------+
double GetMajorStep( double in_rate ) {

    e_profile   profile = _Profile;
    string      symbolname;

    if ( profile == E_PROFILE_AUTO ) {
        symbolname = Symbol();
        StringToUpper( symbolname );

        if ( StringFind( symbolname , "US500" ) >= 0 ) {
            profile = E_PROFILE_US500;
        } else if ( StringFind( symbolname , "JP225" ) >= 0 ) {
            profile = E_PROFILE_INDEX;
        } else if ( in_rate >= 1000 ) {
            profile = E_PROFILE_INDEX;
        } else {
            profile = E_PROFILE_FX;
        }
    }

    if ( profile == E_PROFILE_INDEX ) {
        return 1000.0;
    }
    if ( profile == E_PROFILE_US500 ) {
        return 100.0;
    }
    return 1.0;
}
未分類
シェアする