2015年7月3日金曜日

[検証]使える!単純移動平均、単純移動平均の重要性

昨日の記事は大反響でした。前回から、もうちょっと単純移動平均について掘り下げてみたいと思います。

単純移動平均は遅れているため、シグナルとして使用すると判断が遅くなることを、前回の記事で検証しました。では単純移動平均は使わない方がよいのでしょうか?いいえ。単純移動平均には、その傾きによってトレンドを推測できるという重要な役割があります。ちょっとした数学を使って検証したいと思います。

移動平均といっても、さまざまな種類があります。
有名どころで、単純移動平均(SMA)、加重移動平均(WMA)、指数平滑移動平均(EMA)とありますよね?皆様どれを使っていますか?

単純移動平均以外の特徴は次の通りです。
・加重移動平均:少ない遅延で平滑化する。
・指数平滑移動平均:単純と加重の中間。

 単純移動平均と比較して、同じ遅延であれば加重/指数の方が滑らかだし、同じ滑らかさであれば加重/指数の方が遅延が少ないという事になります。移動平均を使う主目的の平滑化では、加重/指数を使う方が理に適っているということになります。

では単純移動平均はお役御免でしょうか?

いいえ。単純移動平均にはとても重要な役割があります。トレンド方向を判別することです。

分かりやすくするためにEXCELグラフで視覚化したいと思います。

■正弦波に対して移動平均をとる
単純移動平均正弦波.PNG

これは、正弦波形に対して波長と同じ長さの移動平均をとったグラフです。波形成分が打ち消されて移動平均は0となっています。このようにある波長と同じ期間の単純移動平均をとると波形成分による振幅を取り除くことができます。この特性を利用すると、小さい周期の値動きを排除してトレンドの方向をつかむ事ができそうです。

もう一個わかりやすい例として、一定値を加えて生成した正弦波に対して、移動平均をとった結果をしめします。
■線形増分を持つ正弦波に対して移動平均をとる
単純移動平均正弦波トレンド.PNG

正弦波波形成分が取り除かれてトレンドラインが表れている様子がよくわかります。
上記結果から、単純移動平均はチャートに存在する短期波長成分の揺らぎを排除してトレンドの方向を知るのに非常に重要なツールであることが示されています。

さて、ここで問題があります。単純移動平均を使用してトレンドを得る為には、取り除きたい波形成分の波長が必要です。ここで移動平均の期間としてよく使われる21という数字は数学的に正当性がある数字なのでしょうか?チャートの波長成分を分析するオシレータを使用した結果です。
■EURUSD 1時間足 主要波長解析
EURUSD波長解析.PNG

これを見ると21付近をうろうろしています。みんなが21を使うからかどうかはわかりませんが21という数字にはそれなりの数学的根拠がありそうです。

ということで、単純移動平均は遅延が大きいため売買シグナルを図るツールとしては使用が難しいですが、その傾きはトレンド方向を知る重要なツールであることが判りました。

なんとなくで移動平均を使っていると、その使用法に勘や経験に頼る事になりますが、このように数学的に説明すると利用シーンがはっきりするなぁと思っていますが皆さんどうですか?



2015年7月2日木曜日

[検証]移動平均は遅れてる!!!!!

某ラノベ風タイトルをつけてみましたが、ここでの遅れているは、古臭いという意味ではなく、価格に対して遅延しているという意味で使っています^^;

マイクさんという方が、FX-ONや自身のブログで素晴らしい記事をアップしています。ボリンジャーの都市伝説(1)

この中で、価格は移動平均に対して中心に滞在していない事が示されています。

この現象はなぜ発生するのでしょうか?
これは単純なグラフを描画すると直感的に理解できる現象です。

値変化に対して、5単純移動平均をとったグラフです。

■価格変化と移動平均の遅れについて
移動平均.PNG

青色の値に対してオレンジの移動平均が重なるのは値が変化してクロスする地点のみで後は基本的に遅れて追従していることが確認できるかと思います。

このように、移動平均と同じ時間の価格を比較すると遅延分のずれが発生します。結果、統計を取ると、中心値に対して遅延分だけずれた位置にピークが発生します。さらに遅延分だけ分布が両側に広がる為、マイクさんが解析してくれたような症状が発生します。

では、実データを使って遅延の影響を検証したいと思います。

21単純移動平均ボリンジャーバンドに対して、その時のクローズ値がどのシグマ内にいたのかをカウントした結果です。中心値に対して両脇にピークが来ています。またそれによって分布が広がっており、確率通りに収まっていない事が分かります。

■EURUSD 15分足 バンドカウント結果
0シフト分布.PNG

ボリンジャーバンドでよく使用される21単純移動平均の場合(21-1)/2=10の遅延が発生します。そのため統計値内にはいっているかどうかは10本先の移動平均に対して確認する必要があります。
次のグラフは、バンドを-10させた値と比較した場合のどのα内にいたのかをカウントした結果です。

■EURUSD 15分足 -10シフト バンドカウント結果
10シフト分布.PNG

見比べると違いが分かるかと思います。
なお、確率的には10本先の移動平均対して、1σ以内の確率は78%、2σは98%、3σは99.9%と正規分布と比較してもかなり移動平均に沿って価格が動いている事が分かります。

動いた結果に基づいた移動平均に対して比較しているため当たり前と思われるかもしれませんが、ここではちょうど単純移動平均の遅延分だけを加えるときっちり正規分布の形になるという事が重要です。

このように移動平均は遅れているという事を念頭に入れると、できるだけ遅延なく対応できるのか?という事に考えが移ると思います。統計結果から移動平均は強力なツールであることが示されていますが、遅延したままではばらつきが大きい事も判ります。そのため移動平均だけではなく、移動平均に対して遅延を消す予測値を付加する必要性があり、ここがいろんなインジケータの見せ所でもあります。

以前紹介した移動平均にモメンタムを加えるというゼロラグEMAもその一つです。

(2015.07.03) 追記
そんな、移動平均の遅れに由来する誤差を消す!予測移動平均ボリンジャーバンドを発売開始!詳しくは「MT4インジケータ 予測移動平均ボリンジャーバンド」で!

カウントするプログラムもアップしておきます。
バンド内の値をカウントするスクリプト
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict

void OnStart()
{
int counter[];
ArrayResize(counter, 40);
ArrayFill(counter, 0, 40, 0);

string symbol = "EURUSD";

int i = 10;

int period = 21;
int dilay = (period - 1) / 2;

while( !IsStopped() )
{
double close = iClose( symbol, PERIOD_M15, i);
if( close <= 0 ) break ;

double center = iMA(symbol, PERIOD_M15, period, -dilay, MODE_SMA, PRICE_CLOSE, i);

double beforeHigh = 0;
double beforeLow = 0;
double currentHigh = center ;
double currentLow = center;
for( int index = 0 ; index < 20; index++)
{
double d = 0.2 * (index + 1);
beforeHigh = currentHigh;
beforeLow = currentLow;
currentHigh = iBands( symbol, PERIOD_M15, period, d, -dilay, PRICE_CLOSE, MODE_UPPER, i);
currentLow = iBands( symbol, PERIOD_M15, period, d, -dilay, PRICE_CLOSE, MODE_LOWER, i);

if( beforeHigh <= close && close < currentHigh)
{
counter[ 20 + index ] ++;
break;
}

if( currentLow <= close && close < beforeLow)
{
counter[ 19 - index ] ++;
break;
}
}
i++;
}

int handle = FileOpen("bandCounter.csv", FILE_CSV|FILE_WRITE, ',', CP_ACP);

for( i = 0; i < ArraySize(counter); i++ )
{
FileWrite(handle, counter[i]);
}
FileClose(handle);
}


2015年7月1日水曜日

価格変動における、周波数・位相解析は効果があるのか? 検証中・・。

sinwave.PNG

 チャートは時間と価格の二次元で表現されます。そしてそれは波をうっています。そのため周波数成分が発生します。波の引き具合を過去の周波数成分から未来を予測することは可能なのでしょうか?
 あれこれ解析を行いながら確認しています。

 示した図は、周波数位相の変化をチャート化したものです。

 赤い線が位相変化、黄色い線がそれを45度分先行させた値です。単純に取引した感じだと、五分五分です。トレンドが消えている時はある程度きれいな波形が出ています。トレンドが出ていると波形が崩れます。
 クロスしたときには、そのあと相場の流れが変わる事が見受けられる為、先行指標として位相の転換というのは効果がありそうです。モメンタムのように価格帯をベースにしていない為、上昇トレンドの際いつまでも逆シグナルを出し続けることもありません。

 ただしレンジ相場の周期の短い間隔の際は、シグナルと同時に逆方向に動くか動いた後に出ることもあります。多分同じことを考えて先行して取引している人がいるんだろうなーと想像していますが、さてどうでしょうか?


2015年6月30日火曜日

MT4インジケータ 移動平均の遅れをなくす? ゼロラグEMA

zema.PNG

移動平均の最大の問題は、移動平均が表している値は遅延しているということです。見た目単純にわかりやすく説明するのに、1,2,3と線形で増えていく値の5単純移動平均をExcelでグラフにしてみました。
移動平均の遅れ.PNG
元の値に対して遅れて移動平均が遅れて追従していく様子が分かるかと思います。

このように移動平均を元に判別すると、相場に参加する判断が遅くなる問題があり移動平均がシグナルを出す頃には、すでに手遅れになっているという事も多々発生します。

この移動平均の問題に対して、推定値を加えることで遅延をけし、なおかつ平滑化効果を得ようというのがゼロラグEMAです。
ページトップのチャートは、黄色が7EMA、赤が7ZEMAとなっています。

ロケット工学投資法を参考に、推定値として3バー先のモメンタムを加えています。

//------------------------------------------------------------------
// ZEMA
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_chart_window

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

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

#property indicator_label1  "ZEMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrIndianRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

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

// 入力パラメータ 期間
extern int Period = 7;

// 推定値期間
extern int MomentamPeriod = 3;

// ゲイン要素
extern double Gain = 0.5;

// 対象価格
extern ENUM_APPLIED_PRICE MaPrice = PRICE_MEDIAN;

// バッファー
double zemaBuffer[];

// 平滑平均定数
double alfa = 0 ;

//------------------------------------------------------------------
//初期化
int OnInit()
{
//インジケーターバッファを初期化する。
SetIndexBuffer(0,zemaBuffer);
SetIndexDrawBegin(0, Period);

string short_name = "ZEMA( " + IntegerToString(Period)+" , "+  IntegerToString(MomentamPeriod) + " )";
IndicatorShortName(short_name);

// 2 / (Period + 1)だと0になる。int演算で切り捨てが発生する。
alfa =  2.0 / (Period + 1);

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[])            //スプレット
{
//元となる値を計算する。
for( int i = (rates_total - prev_calculated - 1); i >= 0 && !IsStopped(); i-- )
{
if( i > (rates_total - Period) ) continue;

// 最初の一個は単純平均
if( i == (rates_total - Period) )
{
double sum = 0;
for( int j = i; j < rates_total; j++ )
{
sum += GetPrice(open[j], close[j], high[j], low[j], MaPrice);
}
zemaBuffer[i] = sum / Period;
continue;
}

//ZEMA = alfa * ( price[0] + Gain * (price[0] - price[MomentamPeriod]) + (1-alfa) * zema[1]

double price0 = GetPrice(open[i], close[i], high[i], low[i], MaPrice);
double priceM = GetPrice(open[i + MomentamPeriod], close[i + MomentamPeriod], high[i + MomentamPeriod], low[i + MomentamPeriod], MaPrice);

zemaBuffer[i] = alfa * (price0 + Gain * (price0 - priceM) ) + (1 - alfa) * zemaBuffer[i + 1];
}

return(rates_total -1);
}

//------------------------------------------------------------------
// 価格を計算する。
// return 対象価格
double GetPrice(
double open,   // オープン値
double close,  // クローズ値
double high,   // 高値
double low,    // 安値
ENUM_APPLIED_PRICE maPrice    //取得価格
)
{
double price = 0;

switch( maPrice )
{
case PRICE_CLOSE:
price = close;
break;
case PRICE_OPEN:
price = open;
break;
case PRICE_HIGH:
price = high;
break;
case PRICE_LOW:
price = low;
break;
case PRICE_MEDIAN:
price = (high + low) / 2;
break;
case PRICE_TYPICAL:
price = (high + low + close) / 3;
break;
case PRICE_WEIGHTED:
price = (high + low + close + close) / 4;
break;
}
return price;
}


2015年6月29日月曜日

Gewinn2 バージョンアップのお知らせと雑談

Gewinn2をバージョンアップしました。

修正点は次の通りです。

・FOMCフィルタを公開しました。バックテスト的には無効にしたほうが成績が良い為、デフォルトでは無効にしています。
・だましの多い時間帯にポジションを取らないフィルタを追加しました。
 日本時間の昼休み、アメリカ時間終了間際のだましの動きに対応するために時間フィルタを導入しました。
・50pipsを超える含み益が発生した場合、リミット値を移動させる処理を追加しました。

今後も改善点を見つけてバージョンアップしていきますので、よろしくお願いします。

また、リアルマネーによるフォワードテストも開始しました。
OANDA Japanのプロ口座にて両建て可能状態で
みんなのMT4にて公開しています。

さて、大概の予想を裏切りギリシャ問題が決裂しましたね。先週末の時点でも投資家予想にて、何らかの合意にたどり着く予想が60%近くあったので、半分以上の人にとって意外な結果だったようです。
朝からユーロが大幅安となっています。Gewinn2では朝方はポジションを取らない為、眺めているだけとなっていますが、このままヨーロッパ時間になったら、どう動くのかさっぱり分からなくなりました。このまま大きく下がる場合はポジションを持ちませんが、いったん反発する場合はポジションを取りに行くロジックとなっています。さてどうなるでしょうか?

Money Box-100.jpg
逆コツコツドカン型EA Gewinn2 販売中
初期導入者様向け先着10名様に9800円でご提供します!
不明な点、動作が分からない点ありましたら、ご質問ください!