
MT5でBTCUSDの買い下がりEAを作って検証してみた ①
なんとなく暇だったので、グリッドトレードについて考えてみました。
グリッドトレードとは、決められた値幅で指値を置き、損切はせず利益が出たら決済するトレードのこと。例えば、100pipsごとに買い下がりながら平均建値を下げ、利益が出るまで保有みたいな感じ。
正確には、ある価格以上では売り、ある価格以下では買いのような指値をばらまく感じらしいですが、とりあえず簡単に考えるためにロングだけで検証してみました。
同じような手法は多数ありますが、違いは次の4つです。
① 指値価格の値幅(pips)
② 指値ごとのLot枚数
③ エントリーロジック
④ 決済ロジック
これらの違いを考えながらどんな結果が得られるのか検証してみました。
検証環境
FXGTのstandard口座(MT5)
BTCUSD
2021年1月1日~2022年10月9日
1時間足(モデル:1分足OHLC)
証拠金10000ドル
とりあえずFXGTのMT5で検証して、ええ感じならBinanceあたりをpythonで検証しようと思います。
pro口座だと2022年1月から3月の過去データが欠落しており、検証できない期間が生じたので、standard口座にて検証しました。
ロングするだけのグリッドトレード
まず手始めにロングするだけのグリッドトレードを作成してみました。
EA開始と同時に0.01Lotで成行ロング
100ドルずつ1000ドル下まで0.01Lotでロング指値
全ポジションの利益額合計が10ドルを超えると決済
1に戻る
/*
GridTrade
LongOnly
*/
#include <Trade\Trade.mqh>
int BarCounts=0;
input double Lots = 0.01;
input int num = 10;
input int haba = 100;
input double rieki = 10;
int OnInit()
{
return(INIT_SUCCEEDED);
}
void CheckForOpen()
{
CTrade trade;
if(AccountInfoDouble(ACCOUNT_PROFIT)>=rieki)
{
for(int i=PositionsTotal()-1; i>=0; i--)
{
trade.PositionClose(_Symbol,3);
}
for(int k=OrdersTotal()-1; k>=0; k--)
{
trade.OrderDelete(OrderGetTicket(k));
}
}
if(PositionsTotal()==0)
{
trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,Lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0);
for(int i=1; i<=num; i++)
{
trade.OrderOpen(_Symbol,ORDER_TYPE_BUY_LIMIT,Lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK)-haba*i,SymbolInfoDouble(_Symbol,SYMBOL_ASK)-haba*i,0,0);
}
}
Print(OrdersTotal());
}
void OnTick()
{
if(Bars(_Symbol,_Period)!=BarCounts)
{
CheckForOpen();
BarCounts = Bars(_Symbol,_Period);
}
}

2021年4月から8月、2022年1月からの下落相場では決済ができないために長期の含み損期間となっています。

資金が拘束され、利益が生まれない無駄な時間が生じてしまいます。
解決方法
買い下がり幅を広げる
買い下がり回数を増やす
買い下がりLotの枚数を可変にする(ナンピンやマーチン)
エントリーロジックを変更する
利確のロジックを変更する

買い下がり幅を500ドルに変更しましたが、2022年の下落では決済できずにずっと含み損状態です。

買い下がり回数を20回に増やしましたが、2022年の下落では決済ができていません。
可変Lotに変更
上記の指値部分をLots*MathPow(2,i)に変更することで、Lotを倍々にしていけるマーチンポジションを作成できます。
trade.OrderOpen(_Symbol,ORDER_TYPE_BUY_LIMIT,Lots*MathPow(2,i),SymbolInfoDouble(_Symbol,SYMBOL_ASK)-haba*i,SymbolInfoDouble(_Symbol,SYMBOL_ASK)-haba*i,0,0);

速攻でゼロカットされてます。
Lotを倍々ではなく1.1倍や1.2倍などで作成できるように変更してみました。

まだまだダメですね。
ちなみにパラメータを最適化かけるとこんな感じ。あくまで最適化ですからね。。。



10000ドル開始で、2年で3359106ドルだそうです。。。ふーん。。。
値幅設定を%に変えてみる
100ドル刻みで値幅設定していましたが、次の3つのパターンで検証してみました。
100ドル→120ドル→144ドルみたいに1.2倍ずつ離していくパターン
1%など、現在値の割合で固定
割合で固定しながら、1.2倍など離していくパターン
まず1つ目のパターンですが、指値を作成する際に、最後の価格をlastPなどの変数で保存し、変動幅を減算することで作成することができます。
if(PositionsTotal()==0)
{
trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,Lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0);
lastP = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
for(int i=1; i<=num; i++)
{
trade.OrderOpen(_Symbol,ORDER_TYPE_BUY_LIMIT,MathRound(Lots*MathPow(hiritsu,i)*100)/100,lastP-haba*MathPow(haba_hiritsu,i),lastP-haba*MathPow(haba_hiritsu,i),0,0);
lastP -= haba*MathPow(haba_hiritsu,i);
}
}
2つ目のパターンは、指値を比率に変えるだけ。
// habaをdouble型に変更
input double haba = 0.01;
// SymbolInfoDouble(_Symbol,SYMBOL_ASK)*haba*i に変更
trade.OrderOpen(_Symbol,ORDER_TYPE_BUY_LIMIT,MathRound(Lots*MathPow(hiritsu,i)*100)/100,SymbolInfoDouble(_Symbol,SYMBOL_ASK)*(1-haba*i),SymbolInfoDouble(_Symbol,SYMBOL_ASK)*(1-haba*i),0,0);
3つ目、上記の二つを足した形。
if(PositionsTotal()==0)
{
trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,Lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0);
lastP = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
for(int i=1; i<=num; i++)
{
trade.OrderOpen(_Symbol,ORDER_TYPE_BUY_LIMIT,MathRound(Lots*MathPow(hiritsu,i)*100)/100,lastP-SymbolInfoDouble(_Symbol,SYMBOL_ASK)*haba*MathPow(haba_hiritsu,i),lastP-SymbolInfoDouble(_Symbol,SYMBOL_ASK)*haba*MathPow(haba_hiritsu,i),0,0);
lastP -= SymbolInfoDouble(_Symbol,SYMBOL_ASK)*haba*MathPow(haba_hiritsu,i);
}
}
結論から言うと、指値幅のロジックを変えても大きな変化はなかったです。どれを使っても同じような結果になりました。
最適化すれば、どれも同じようなパラメータで同じような結果になります。
買い下がりの値幅やLotを変更するより、エントリーと利確のロジックを考えた方がよさそうです。
パターン③の最適化結果



ドローダウンとか見たら、最初の固定の方が良さそう。。。
眠なってきたから今日はここまで、エントリーと決済のロジック考える部分は次回書きます。