2015年4月27日月曜日

相場は重力に縛られるのか?S/Rオシレータを作ってみた。

インジケータ作ってみたシリーズが思いのほか好評なため、もう一個作ったやつを公開します。

その前に、前回のレンジ・エクスパンション・インデックス(REI)を作ってみた。の記事を修正しています。私の解釈が間違っていた部分がありました。ソースコードは修正していません。

WSRO1.PNG

今回はS/R オシレータです。これまた、ぱっとMT4用のコードが見つからなかった為、自作してしまいました。

こちらはネットにウィドナー博士の英語論文が落ちてましたので、それを参考にしています。

とはいっても英語なんてこれっぽちもできません。Google先生に頼んでニュアンスで理解したところによると、「どんな勢い良くリンゴを放り投げても引力という抵抗を受けていつかは落ちる。それと同じで相場も勢いをつけて移動しても反対方向に落ちてくるからそのタイミングをとらえましょう。」という考え方のようです。
・・・・その意味でいくと重力圏を抜けて宇宙に飛び出してニュー○イプ化してしまった感のあるApple株みたいなこともあるので、そうなの?と思わないでもないですが、とりあえず作ってみました。

S/R オシレータは「Support and resistance oscillator」の略です。サポートラインとレジスタンスラインに対する位置を推進力、引力にとらえて算出するようです。上昇基調の時の考え方としては

サポートラインを上回る→推進力がある。
レジスタンスラインを上回る→引力を受ける。
推進力と引力が釣り合う→落ちてくるタイミング

という事みたいです。


今回は計算式にちょっと自信がありません。間違ってたら遠慮なく教えてください^^;;
//------------------------------------------------------------------
// ウィドナー博士のサポートレジスタンス オシレーター
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict

#include <Arrays/ArrayDouble.mqh>

#property indicator_separate_window
#property indicator_minimum    0
#property indicator_maximum    100

//バッファーを指定する。
#property indicator_buffers 2

//プロット数を指定する。
#property indicator_plots   2

//サポートオシレータ情報
#property indicator_label1  "Support"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//レジスタンスオシレータ
#property indicator_label2  "Resistance"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//入力パラメータ 期間
input int Period = 6;

//入力パラメータ HL期間(奇数)
input int HLPeriod = 9;

//インジケーター バッファ
double wsoBuffer[];
double wroBuffer[];

//S1-Sn
CArrayDouble supports;
//R1-Rn
CArrayDouble resistances;

//------------------------------------------------------------------
//初期化
int OnInit()
{
if( HLPeriod % 2 == 0 || HLPeriod < 5) return (INIT_PARAMETERS_INCORRECT);
if( Period < 3 ) return (INIT_PARAMETERS_INCORRECT);

//インジケーターバッファを初期化する。
SetIndexBuffer(0,wsoBuffer);
SetIndexBuffer(1,wroBuffer);

SetIndexDrawBegin(0, HLPeriod + 1);
SetIndexDrawBegin(1, HLPeriod + 1);


supports.Clear();
supports.Resize(Period);
resistances.Clear();
resistances.Resize(Period);

string short_name = "WSRO( " + IntegerToString(Period)+" , "+  IntegerToString(HLPeriod) + " )";
IndicatorShortName(short_name);


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[])            //スプレット
{
// 最終計算時間
static datetime lastCalculate = 0;

//元となる値を計算する。
for( int i = (rates_total - prev_calculated - 1); i>=0 ; i-- )
{
if( i >=  rates_total - Period - 2 )
{
wsoBuffer[i] = 0 ;
wroBuffer[i] = 0 ;
continue;
}

// 同一時間足の値は再計算不要
if( lastCalculate != time[i] )
{
lastCalculate = time[i];
int centerIndex =  i + 1 + (HLPeriod - 1) / 2;

//サポート
//if Low( four days back ) = Min(lows of previous nine days) then SL=Low(four days back)
if( iLowest(NULL, PERIOD_CURRENT, MODE_LOW, HLPeriod, i + 1) == centerIndex )
{
// 新しいサポートが構築された場合、Period数保持する。
if( supports.Total() >= Period )
{
supports.Delete(supports.Total() - 1);
}
supports.Insert(iLow(NULL, PERIOD_CURRENT, centerIndex), 0);
}

//レジスタンス
//if High( four days back ) = Max(high of previous nine days) then RL=High(four days back)
if( iHighest(NULL, PERIOD_CURRENT, MODE_HIGH, HLPeriod, i + 1) == centerIndex )
{
// 新しいレジスタンスが構築された場合、Period数保持する。
if( resistances.Total() >= Period )
{
resistances.Delete(resistances.Total() - 1);
}
resistances.Insert(iHigh(NULL, PERIOD_CURRENT, centerIndex), 0);
}
}

//つまりHLPeriodの期間内の中央値-1が高値・安値だった場合サポート・レジストラインとして登録する。
//ここで単純に価格で比較すると、最新の値が行ったり来たりすると
//過去のサポート・レジスタンスが次々更新される症状が発生してしまう。

//wsoの計算 1 - ((int)S1/C + (int)S2/C +(int)S3/C +(int)S4/C +(int)S5/C +(int)S6/C) / 6
if( supports.Total() == Period )
{
double wso = 0 ;
for( int j = 0 ; j < supports.Total(); j++ )
{
wso += (int) (supports.At(j) / close[i]);
}
wsoBuffer[i] = (1 - wso / supports.Total()) * 100;
}
else
{
wsoBuffer[i] = 0;
}

if( resistances.Total() == Period )
{
//wroの計算 1 - ((int)R1/C + (int)R2/C +(int)R3/C +(int)R4/C +(int)R5/C +(int)R6/C) / 6
double wro = 0 ;
for( int j = 0 ; j < resistances.Total(); j++ )
{
wro += (int) ( resistances.At(j) / close[i]);
}
wroBuffer[i] = (1 - wro / resistances.Total()) * 100;
}
else
{
wroBuffer[i] = 0;
}
}

return(rates_total - 1);
}


動作としては、
過去9本のうち4本目が最安値だった場合、サポートラインとします。
同様に過去9本のうち4本目が最高値だった場合、レジスタンスラインとします。
サポート・レジスタンスともに新しく更新されるまで過去6個分保持します。
上記6個と現在価格の位置をカウントして超えている割合を%表示したものがS/Rオシレータとなります。
��たぶん・・・汗)

WSRO2.PNG

水色のラインがサポートラインに対する現在価格の位置、赤色のラインがレジスタンスに対する現在価格の位置となります。両方のラインが100になった場合売り、0になった場合は買いというシグナルです。
添付画像で行くと赤丸で囲った部分が0になっていますが、そのあと反転していることが読み取れます。

チャートとS/Rオシレータを眺めていて、思った事ですが、やはりこのオシレータ価格が一方方向に動き続けると0/100に張り付きます。特に相場が凪いでいた状態から動き出すとあっという間に0/100に達して相場が波打つまで、そのままとなります。俗にいう力をためている状態というのは認識できていなさそうです。

ただし、一度100/0に張り付いた後、それが離れるタイミングでは確かに相場が逆に動き出すことも多そうです。ですので、もし、このオシレータを参考にする場合、100/0に達した後、それが崩れるタイミングを見てエントリーというのがよさそうと感じました。

ソースコード的な部分では、今回CArrayDoubleを使用しています。
これは、MT4についてきている浮動小数点配列クラスで、Include/Arraysフォルダに含まれています。
中身を見ると、doubleの配列に対して、AddやInsertなどデータ操作系が行えるようになっており、配列操作を簡単化できます。簡単によく使うメンバ関数を紹介します。

bool CArrayDouble::Resize(const int size)
引数で指定したサイズ分まで配列を確保します。
元のサイズより小さい場合は値が削除されます。
この値は、要素数の最大値となります。(実際には16個分を最低値として16の倍数で確保します)

bool CArrayDouble::Add(const double element)
配列に要素を追加します。Resizeで指定した値まで追加可能です。

bool CArrayDouble::Insert(const double element,const int pos)
posで指定した位置に要素を挿入します。Resizeで指定した値まで追加可能です。

bool CArrayDouble::Delete(const int index)
indexで指定した位置の要素を削除します。

double CArrayDouble::At(const int index) const
indexで指定した位置の要素を取得します。

int CArray:Total(void) const
現在の要素数を取得します。
Resizeで指定した値は最大値で、実際に値の入っている要素数はTotalで取得します。
CArrayDouble はCArrayを継承していますので、CArrayのメンバであるTotalが使用可能です。

��しかし、みなさんMT4のインジケータで定番の奴が見つからない時どうしてるんでしょうか??
��英語版のサイトをうろつくと見つかることもあるのですが、コードが古い為動かなかったりします・・。
��まぁこーやって作っていくと考え方の勉強になるため、とても役には立っているのですが・・。