今回はシグナルアローのインジケータを作成します。
簡単に言うとサインですね。
いつも通りに今回も他カスタムインジケータをベースにして新しいカスタムインジケータを作成します。
それでは
以前作成した移動平均線+エンベロープのカスタムインジケータのソースコードのTestMAEnvLine.mq4をコピペして、
ファイル名をTestArrowFractal.mq4に変更しましょう。
インジケータの描画タイプをアローシンボルにする
今回のインジケータは今までのような線では無く、矢印等のシンボルを表示させるので、インジケータの描画タイプをアローシンボルに変更する必要があります。
インジケータプロパティ設定に
indicator_typeNの設定を追加して、描画タイプを
DRAW_ARROWに設定します。
アローシンボルは小さいと目視で識別し難いので、ついでに
indicator_widthNの設定を3に変更します。
コンパイルして動作確認してみましょう。
ラインがシンボルに変わりました。
アローシンボルを変更する
次はアローシンボルを任意のシンボルに変更します。
任意のシンボルに変更するには
SetIndexArrow()関数を使って、
Wingdingsフォントか
アローコード定数のシンボルーコードを設定します。
OnInit()関数内にソースコードを追加します。
SetIndexLabel()の設定は今回邪魔なのでコメントアウトしました。
SetIndexArrow()で設定している217と218という数値は
Wingdingsフォントのコードです。
コンパイルして動作確認してみましょう。
シンボルが指定したものに変わりました。
トレンドの転換点を算出する
トレンドの転換点を算出して、転換点にのみシンボル表示するようにします。
トレンドの転換点は
iFractals()関数を使って機械的に算出します。
あくまで機械的に転換点を算出しているので、信頼性は高く有りませんが、相場観が養われていない相場初心者の人はこのインジケータを参考にしてチャートを眺めていると何か掴めるかもしれません。
基本的にテクニカル分析は日足で使われる事を前提で作成されている(と思います)ので、
日足未満の時間軸でテクニカル分析を行っても混乱の元にしかなりません(管理人の独断と偏見です。これに対して異議は受け付けませんw)。
VWAPと長いスパンのMAは日足未満の時間軸でも使えますが・・・
OnCalculate()関数内のforループ内の処理を
iFractals()関数に置き換えます。
転換点が表示されるようになりました。
転換点以外は表示されていませんが、これは
iFractals()関数が転換点と判断しなかった場合に0を返す為です。
実際には範囲外の価格0の部分にシンボルが並んでいます。
チャートスケールを引き伸ばすと・・・
見えない部分なので気にしなくてもいいのですが、
見えない部分も手抜きをしたくないエンジニア精神がある人は修正しましょう。
単純に
iFractals()の結果が0以下だった場合は、インジケータバッファに値を設定しないようにします。
ソースコード:
if ( get_lower > 0 ) {
_IndBuffer1[icount] = get_lower;
}
if ( get_upper > 0 ) {
_IndBuffer2[icount] = get_upper;
}
普段は見えない部分ですがスッキリしました。
シンボル表示位置をピクセル単位で調整する
これも細かい部分なのですが、
四本値とシンボルが被ってしまっています。
転換点の高値と安値位置にシンボルを配置している為、オフセットさせなかった場合必ず被ってしまう事になります。
単純に10pipsくらいオフセットさせても良いのですが、南アフリカランドドルみたいに極端にボラティリティの無い通貨ペアとポンドドルみたいに極端にボラティリティのある通貨ペアでは、
同じ10pipsのオフセットでもかなり変ってしまいます。
なのでオフセットは価格レートでは無く、ピクセル単位で行います。
正確にはピクセル単位のオフセットした価格レートを算出します。
それではオフセットする関数を自作しましょう。
処理内容は単純に
ChartTimePriceToXY()関数で価格値をY座標に変換し、
そのY座標にPixel単位のオフセット値を加えて、
オフセットしたY座標を
ChartXYToTimePrice()関数で価格値に変換するだけです。
ソースコード:
double GetOffsetRate(
double in_rate,
int in_offset_pixel
)
{
double ret = in_rate;
double move_rate;
datetime dummy_time;
int bese_axis_x;
int bese_axis_y;
int get_window_no;
int disp_pixel;
bool get_bool;
get_bool = ChartTimePriceToXY(
0,
0,
Time[0],
in_rate,
bese_axis_x,
bese_axis_y
);
if ( get_bool == true ) {
disp_pixel = bese_axis_y + in_offset_pixel;
get_bool = ChartXYToTimePrice(
0,
bese_axis_x,
disp_pixel,
get_window_no,
dummy_time,
move_rate
);
if ( get_bool == true ) {
ret = move_rate;
}
}
return ret;
}
ピクセル単位でオフセットする関数が出来た所で、インジケータバッファに設定する前の値を変換しましょう。
ソースコード:
if ( get_lower > 0 ) {
get_lower = GetOffsetRate(get_lower, 10);
_IndBuffer1[icount] = get_lower;
}
if ( get_upper > 0 ) {
get_upper = GetOffsetRate(get_upper, -10);
_IndBuffer2[icount] = get_upper;
}
いい感じでオフセットされました。
まぁ細かい部分なので、こういう微調整はインジケータが完成した後の仕上げの時に行って下さい。
最後にインプットパラメータも必要無いので削除します。
フラクタル用に常時算出バーを変更する
iFractals()関数はトレンド転換を判定する為に、終値が確定したバーを2本必要とします。
つまり何が言いたいかというと、トレンド転換と判断した時に3本目のバーにシンボルが表示されるという事です。
今のインジケータの作りでは直近2本しか常時更新していないので、新しいバーが生成された時にフラクタルが正しく表示されない事になります。
なので常時更新を直近2本から3本に変更する必要があります。
ソースコード:
#define IND_MIN_INDEX 3
このインジケータは本当に大切な事を色々と教えてくれます。
四本値の大切さ、四本値は終値が確定(または確定する直前)してから利用価値が生まれる事、
テクニカル分析は日足以上の時間軸でのみ意味を成す事等々・・・
本来であれば四本値と日足で基本的な事を理解して需給が読めるようになってから、あくまでおまけとしてテクニカル分析を使うべきなのですが、
多くの人が何故かテクニカル分析に執着して四本値と時間軸に関しては無関心です。テクニカル分析をまるで魔法のツールのように崇拝する傾向があります。
(管理人の独断と偏見と妄想です。これに対して異議は受け付けませんw)
完成したサンプルソースコード
最後に出来上がったソースコードをまとめると、
ソースコード:
#property copyright "yuki"
#property link "https://yukifx.web.fc2.com/"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrWhite
#property indicator_width1 3
#property indicator_type1 DRAW_ARROW
#property indicator_color2 clrWhite
#property indicator_width2 3
#property indicator_type2 DRAW_ARROW
#define IND_MIN_INDEX 3
double _IndBuffer1[];
double _IndBuffer2[];
int OnInit()
{
SetIndexBuffer( 0, _IndBuffer1 );
SetIndexBuffer( 1, _IndBuffer2 );
SetIndexArrow( 0 , 218 );
SetIndexArrow( 1 , 217 );
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 end_index = Bars - prev_calculated;
if ( end_index <= IND_MIN_INDEX ) {
end_index = IND_MIN_INDEX;
}
if ( Bars <= IND_MIN_INDEX ) {
return 0;
}
for( int icount = 0 ; icount < end_index ; icount++ ) {
double get_lower = iFractals(
Symbol(),
Period(),
MODE_LOWER,
icount
);
double get_upper = iFractals(
Symbol(),
Period(),
MODE_UPPER,
icount
);
if ( get_lower > 0 ) {
get_lower = GetOffsetRate(get_lower, 10);
_IndBuffer1[icount] = get_lower;
}
if ( get_upper > 0 ) {
get_upper = GetOffsetRate(get_upper, -10);
_IndBuffer2[icount] = get_upper;
}
}
return( rates_total );
}
double GetOffsetRate(
double in_rate,
int in_offset_pixel
)
{
double ret = in_rate;
double move_rate;
datetime dummy_time;
int bese_axis_x;
int bese_axis_y;
int get_window_no;
int disp_pixel;
bool get_bool;
get_bool = ChartTimePriceToXY(
0,
0,
Time[0],
in_rate,
bese_axis_x,
bese_axis_y
);
if ( get_bool == true ) {
disp_pixel = bese_axis_y + in_offset_pixel;
get_bool = ChartXYToTimePrice(
0,
bese_axis_x,
disp_pixel,
get_window_no,
dummy_time,
move_rate
);
if ( get_bool == true ) {
ret = move_rate;
}
}
return ret;
}