Grid Free5の弱点克服?フィルターを追加してみた→Grid Free6
最近、Grid Free5をデモ口座でテスト稼働してみて、苦手な場面が少し見えてきたので、対策を考えてみました。
Grid Free5が苦手な場面は、長期のトレンドが転換するところです。↓
これは今テスト稼働している直近のAUDCADの日足チャートです。
買いポジションが8段まで入っています。
この中で、赤い縦の線を入れたあたりで買いエントリーが入らないようにしたい、というのが今回の目標です。
何種類かインジケーターを試してみて、RSIのフィルターが合いそうだったので、今回は日足のRSIでフィルターを追加してみました。
上の画像を見てみると、RSIが65以上のところで買いエントリーが入らないようにすると良さそうです。
なので、買いエントリーのフィルターに、「日足のRSIが65以下の場合」という条件を追加します。
同様に、売りエントリーは「日足のRSIが35以上の場合」という条件を追加します。↓
double rsi3 = iRSI(NULL, PERIOD_D1, 14, PRICE_CLOSE, 0);
rsi3 < 65
rsi3 > 35
こんな感じのパーツをトレンドフィルターの中に入れて、65のところをパラメーターで変更できるようにしてみます。
フィルター追加前のGrid Free5のトレンドフィルターはこの部分です。↓
bool is_up_trend()
{
double close = iClose(NULL,0,0);
double close100 = iClose(NULL,0,shift1);
double close200 = iClose(NULL,0,shift2);
double mom100 = close - close100;
double mom200 = close - close200;
//「momが0超え」なら上昇トレンド
if(0 < mom100 && 0 < mom200)
{
return true;
}
return false;
}
ここに、「日足のRSIが65以下の場合」という条件を追加するとこんな感じになります。↓
bool is_up_trend()
{
double close = iClose(NULL,0,0);
double close100 = iClose(NULL,0,shift1);
double close200 = iClose(NULL,0,shift2);
double mom100 = close - close100;
double mom200 = close - close200;
double rsi3 = iRSI(NULL, PERIOD_D1, 14, PRICE_CLOSE, 0);
//「momが0超え」なら上昇トレンド
if(0 < mom100 && 0 < mom200 && rsi3 < 65)
{
return true;
}
return false;
}
ここから、65の部分をパラメーターで変更できるように書き換えます。
今回はrsifilterhiという項目にしてみました。↓
if(0 < mom100 && 0 < mom200 && rsi3 < rsifilterhi)
そして、EAのソースコードの上の方に行って、パラメーター項目を追加します。↓
input int rsifilterhi =65;//日足RSIフィルター上限
同様に、売りエントリーの方にもフィルターを追加します。
これでGrid Free6の完成です。
出来上がったソースコードはこんな感じになりました。↓
#property copyright "けんじ2405"
#property link "https://note.com/just_pothos4327"
#property version "1.00"
#property strict
input int MagicNumber = 77701;//マジックナンバー
input double lots = 0.1;//ロット数
input int MaxSp = 45;//最大スプレッド
input int rikakuhaba = 150;//利確幅
input int nanpinhaba =300;//グリッド幅
input double lotbai = 1.5;//ロット倍率
input int entrystop = 9;//最大ポジション段数
input int rsikikan =14;//RSI計算期間
input int rsilow =28;//RSI下ライン(買い)
input int agehaba =2;//RSI下からの上げ幅(買い)
input int rsihigh =72;//RSI上ライン(売り)
input int sagehaba =2;//RSI上からの下げ幅(売り)
input int shift1 =100;//モメンタムフィルター1
input int shift2 =200;//モメンタムフィルター2
input int rsifilterhi =65;//日足RSIフィルター上限
input int rsifilterlow =35;//日足RSIフィルター下限
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTick()
{
//エントリー処理
if(is_buy() && is_up_trend() && posi_count(OP_BUY) == 0)
{
position_entry(OP_BUY);
}
if(is_sell() && is_down_trend() && posi_count(OP_SELL) == 0)
{
position_entry(OP_SELL);
}
//決済処理
if(posi_count(OP_BUY) > 0)
{
if(position_average_price(0) + rikakuhaba * _Point < Bid)
{
position_close(0);
}
}
if(posi_count(OP_SELL) > 0)
{
if(position_average_price(1) - rikakuhaba * _Point > Ask)
{
position_close(1);
}
}
//ナンピンマーチン
nanpin_martin_judge();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool is_buy()
{
double rsi = iRSI(NULL,0,rsikikan,0,1);
double rsi2 = iRSI(NULL,0,rsikikan,0,0);
if(rsi <= rsilow && rsi2 >= rsilow+agehaba)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool is_sell()
{
double rsi = iRSI(NULL,0,rsikikan,0,1);
double rsi2 = iRSI(NULL,0,rsikikan,0,0);
if(rsi >= rsihigh && rsi2 <= rsihigh-sagehaba)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool is_up_trend()
{
double close = iClose(NULL,0,0);
double close100 = iClose(NULL,0,shift1);
double close200 = iClose(NULL,0,shift2);
double mom100 = close - close100;
double mom200 = close - close200;
double rsi3 = iRSI(NULL, PERIOD_D1, 14, PRICE_CLOSE, 0);
//「momが0超え」なら上昇トレンド
if(0 < mom100 && 0 < mom200 && rsi3 < rsifilterhi)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool is_down_trend()
{
double close = iClose(NULL,0,0);
double close100 = iClose(NULL,0,shift1);
double close200 = iClose(NULL,0,shift2);
double mom100 = close - close100;
double mom200 = close - close200;
double rsi3 = iRSI(NULL, PERIOD_D1, 14, PRICE_CLOSE, 0);
//「momが0未満」なら下降トレンド
if(0 > mom100 && 0 > mom200 && rsi3 > rsifilterlow)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int posi_count(int side)
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() == side)
{
if(OrderSymbol()==Symbol())
{
if(OrderMagicNumber()==MagicNumber)
{
count++;
}
}
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void position_entry(int side)
{
double qty = lots;
if(side==0 && MarketInfo(Symbol(),MODE_SPREAD) < MaxSp)
{
bool res= OrderSend(NULL,side,qty,Ask,0,0,0,NULL,MagicNumber,0,clrGreen);
}
if(side==1 && MarketInfo(Symbol(),MODE_SPREAD) < MaxSp)
{
bool res= OrderSend(NULL,side,qty,Bid,0,0,0,NULL,MagicNumber,0,clrRed);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void position_entry_nanpin(int side,double bairitu)
{
double qty = lots;
if(side==0 && posi_count(OP_BUY) < entrystop && MarketInfo(Symbol(),MODE_SPREAD) < MaxSp)
{
bool res= OrderSend(NULL,side,qty * bairitu,Ask,0,0,0,NULL,MagicNumber,0,clrGreen);
}
if(side==1 && posi_count(OP_SELL) < entrystop && MarketInfo(Symbol(),MODE_SPREAD) < MaxSp)
{
bool res= OrderSend(NULL,side,qty * bairitu,Bid,0,0,0,NULL,MagicNumber,0,clrRed);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void position_close(int side)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() == side)
{
if(OrderSymbol()==Symbol())
{
if(OrderMagicNumber()==MagicNumber)
{
bool res= OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 0, clrBlue);
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double position_average_price(int side)
{
double lots_sum = 0;
double price_sum = 0;
double average_price = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() == side)
{
if(OrderSymbol()==Symbol())
{
if(OrderMagicNumber()==MagicNumber)
{
lots_sum += OrderLots();
price_sum += OrderOpenPrice() * OrderLots();
}
}
}
}
}
if(lots_sum && price_sum)
{
average_price = price_sum/lots_sum;
}
return average_price;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double position_entry_price(int side)
{
double entry_prices[50];
double entry_price=0;
ArrayInitialize(entry_prices,0.0);
if(side ==1)
{
ArrayInitialize(entry_prices,9999999.0);
}
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() == side)
{
if(OrderSymbol()==Symbol())
{
if(OrderMagicNumber()==MagicNumber)
{
entry_prices[i] = OrderOpenPrice();
}
}
}
}
}
if(side==0)
{
entry_price = entry_prices[ArrayMaximum(entry_prices,WHOLE_ARRAY,0)];
}
if(side==1)
{
entry_price = entry_prices[ArrayMinimum(entry_prices,WHOLE_ARRAY,0)];
}
return entry_price;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void nanpin_martin_judge()
{
if(posi_count(OP_BUY) > 0)
{
int position_num = posi_count(OP_BUY);
double entry_price = position_entry_price(OP_BUY);
double nanpin_price = entry_price - (nanpinhaba * _Point) * position_num;
double lots_bairitu = MathPow(lotbai,position_num);
if(nanpin_price > Ask)
{
position_entry_nanpin(OP_BUY,lots_bairitu);
}
}
if(posi_count(OP_SELL) > 0)
{
int position_num = posi_count(OP_SELL);
double entry_price = position_entry_price(OP_SELL);
double nanpin_price = entry_price + (nanpinhaba * _Point) * position_num;
double lots_bairitu = MathPow(lotbai,position_num);
if(nanpin_price < Bid)
{
position_entry_nanpin(OP_SELL,lots_bairitu);
}
}
}
//+------------------------------------------------------------------+
EAのファイルはこちら↓
フィルターの効果をたしかめるために、Grid Free5とGrid Free6でバックテストを比較してみます。
まずはGrid Free5のバックテスト結果↓
次はGrid Free6のバックテスト結果↓
プロフィットファクターやドローダウンを見てみると、フィルターの意味があるのかないのか、よくわからない結果になりました。
わかりやすく変わった所は、総取引数は減って、勝率は上がったというところです。
パラメーターを調整して最適化すればよくなりそうな感じはします。
あとは、他の通貨ペアでもバックテストしてみたいと思います。
グリッド・マーチンゲールのEAを複数の通貨ペアで同時稼働するなら、これくらいエントリーを絞った方が良いかなという感じもします。
今後は、他の通貨ペアでもバックテストするのと、通貨ペアごとのパラメーターの最適化をしてみたいと思います。
もしよければ記事のサポートをお願いします。
お金が稼げなくて困っています。
よろしくお願いいたします。