テストコード
//+------------------------------------------------------------------+
//| 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;
}