EA(自動売買)の精度を上げる方法とは?取引する曜日を制限して検証
第1回~第5回で朝スキャのEAを作成し、第6回~第10回ではナンピンや複利などの機能を実装して、精度がどのように変化するのかを検証しました。
しかし、EAの運用を考えると、実際は作って終わりではありません。
EAを運用するには、さらに精度を上げる、パラメータを精査する必要があります。
そこで第11回からは、「作成したEAの精度を上げる」ことをテーマとしていきます。
なおEAは第9回でナンピンを実装したものをひな形にします。
曜日の重要性
今回採用しているロジックの「朝スキャ」は、主なロジックとしては時間による値動きの特徴をとらえるというものでした。
実は、曜日ごとに値動きの特徴があることが知られています。
MT5ではバックテスト時に、以下の画像のような曜日ごとの損益が自動で表示されます。
MT5の開発元であるメタクオーツ社も、曜日ごとに精度を調査することが有効だと認識し、推奨しているというわけです。
(残念ながらMT4にはこの機能はありません)。
特に土日を挟む月曜日と、週末の金曜日は、特徴が表れやすい傾向にあります。
そこで今回は、曜日ごとにバックテストを実施し、どのように結果が変わるのかを確認していきましょう。
仕様
まずは第9回で作成したナンピンEAの仕様をまとめます。
エントリー
時間が日本時間早朝かつRSIが売られすぎラインを下回ったら、買いエントリー
時間が日本時間早朝かつRSIが買われすぎラインを上回ったら、売りエントリー
パラメータで指定したpipsの損害がでたらナンピンエントリー
決済
利確価格と損切り価格による決済
その他
著作権を「OANDA」に設定
スリッページ、スプレッドによってエントリーを制限する
ポジションは同時に1つのみ保有するようにする
マジックナンバーとロット数を変更できるようにする
以上です。
こちらに曜日制限の機能を追加していきましょう。
Aを作成する
前回までの内容は割愛し、今回追加する機能のみ紹介します。
フィールド
input int MAGICMA = 23498721; // マジックナンバー
input double Lots =0.01; // 1ロット十万通貨単位
input int Slippage = 4; // エントリー見送りスリッページ
input double MaxSpread = 5; // エントリー見送りスプレッド
input double TakeProfit = 10.0; // 利益確定幅(pips)
input double LossCut = 20.0; // 損切確定幅(pips)
input int RSIPeriod=6; // 期間
input ENUM_APPLIED_PRICE RSIAppliedPrice = PRICE_CLOSE; // 適用価格
input int UpLine = 85; // 上の線
input int DownLine = 25; // 下の線
input int TradeTime = 0; // トレードを行う時間
input int NanpinWidth = 5; //ナンピンの幅(pips)
//曜日設定
input int TradeDayOfWeek = 1; // トレード曜日(1:月曜、2火曜、3:水曜、4:木曜、5:金曜)
第9回のEAのパラメータに、曜日設定用のパラメータを追加しました。
MQL4の曜日を取得する関数TimeDayOfWeekは、月曜日を1、火曜日を2、水曜日を3、木曜日を4、金曜日を5としますので、コメントにメモとして残しています。
デフォルトの設定では「1」となっており、月曜日しかエントリーしません。
OnTick関数
void OnTick()
{
dSpread = (Ask - Bid) / (Point * 10);
if(CalculateCurrentOrders()==0 && dSpread < MaxSpread && TimeDayOfWeek(Time[0]) == TradeDayOfWeek) CheckForOpen();
if(CalculateCurrentOrders()==1 && dSpread < MaxSpread) CheckForNanpin();
CheckForClose();
}
CheckForOpen関数を呼び出す条件に「TimeDayOfWeek(Time[0]) == TradeDayOfWeek」という式を追加しています。
つまり、「現在の曜日がパラメータで指定した曜日の時」のみエントリーを行うというわけです。
最適化
ではMT4の最適化機能を使って、曜日ごとのトレードの結果がどのように変化するのかを確認していきましょう。
基本的な設定は以下の通りです。
- 通貨ペア:GBPUSD
- 時間足:5分足
- 期間:2018年1月1日~2023年1月1日の5年間
- スプレッド:15固定
まずは、バックテスターの最適化チェックボックスをONにします。
続いて、バックテスターのパラメータ設定画面から、曜日を1~5まで変化させるようにします。
この状態でスタートボタンを押すと、以下のような結果になりました。
TradeDayOfWeekが1、つまり月曜日にエントリーを行った時が最も精度が高く、金曜日にエントリーを行った場合が最も精度が低くなるという結果です。
月曜日と金曜日では、両極端な結果となりました。
ではこの結果を受けて、金曜日はエントリーをしないように書き換えましょう。
書き換え前:TimeDayOfWeek(Time[0]) == TradeDayOfWeek
書き換え後:TimeDayOfWeek(Time[0]) != TradeDayOfWeek
この状態でパラメータのTradeDayOfWeekを5にセットします。
過剰最適化(オーバーフィッティング)に注意
時間や曜日を切り分けることで精度が上がるならば、さらに分刻みや3の倍数の日などに分類したくなるかもしれません。
しかし、やりすぎると過剰最適化になってしまう可能性があります。
過剰最適化とは、過去のデータばかりに適合して、未来のデータに対応できなくなってしまうことです。
例えば、バックテスト上では「〇時23分にエントリーすると勝率が高い」となっていても、実はたまたまで、実際にはまったく勝てないといったことが起こり得ます。
バックテスト
金曜日にエントリーを行った場合と、行わない場合のバックテスト結果を比較してみましょう。
金曜日エントリーあり
金曜日エントリーなし
最適化を行ったので分かっていたことですが、金曜日にエントリーを行わない方がより良い精度となっています。
しかし当然ながら取引回数が減少しています。
EAの精度を上げる作業で難しいことの1つが、「取引回数と精度」のバランスです。
条件を厳しくして精度を上げると取引回数が少なくなり、逆に取引回数を上げようとすると精度が落ちるというトレードオフの関係にあります。
EAを開発するうえで、これらのバランスをとることが非常に重要です。
注意点
今回のバックテストは、スプレッドを固定で行っています。
日本時間早朝の相場が緩やかになる時間帯はスプレッドが広がりやすいという特徴があります。
実運用を行うにはスプレッド制限をかけるなど、十分に注意しましょう。
また、マーチンゲールは自己資金を一瞬で失ってしまうリスクがあります。
プログラム全文
#property copyright "Copyright(C) 2023, OANDA"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
input int MAGICMA = 23498721; // マジックナンバー
input double Lots =0.01; // 1ロット十万通貨単位
input int Slippage = 4; // エントリー見送りスリッページ
input double MaxSpread = 5; // エントリー見送りスプレッド
input double TakeProfit = 10.0; // 利益確定幅(pips)
input double LossCut = 20.0; // 損切確定幅(pips)
input int RSIPeriod=6; // 期間
input ENUM_APPLIED_PRICE RSIAppliedPrice = PRICE_CLOSE; // 適用価格
input int UpLine = 85; // 上の線
input int DownLine = 25; // 下の線
input int TradeTime = 0; // トレードを行う時間
input int NanpinWidth = 5; //ナンピンの幅(pips)
//曜日設定
input int TradeDayOfWeek = 1; // トレード曜日(1:月曜、2火曜、3:水曜、4:木曜、5:金曜)
double dSpread;
int OnInit()
{
return(INIT_SUCCEEDED);
}
void OnTick()
{
dSpread = (Ask - Bid) / (Point * 10);
if(CalculateCurrentOrders()==0 && dSpread < MaxSpread && TimeDayOfWeek(Time[0]) != TradeDayOfWeek) CheckForOpen();
if(CalculateCurrentOrders()==1 && dSpread < MaxSpread) CheckForNanpin();
CheckForClose();
}
void CheckForOpen()
{
int res;
double RSI = iRSI(Symbol(), 0, RSIPeriod, RSIAppliedPrice, 1);
if(TradeTime == TimeHour(Time[1]))
{
if(RSI < DownLine)
{
res=OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, 0, 0,"", MAGICMA, 0, Red);
}
if(RSI > UpLine)
{
res=OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, 0, 0, "", MAGICMA, 0, Blue);
}
}
}
void CheckForNanpin()
{
int res;
double buyProfitPips = 0;
double SellProfitPips = 0;
for( int i=0; i=0; i-- ){
if( OrderSelect(i, SELECT_BY_POS) == true ){
if( OrderType() == OP_BUY && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol() ){
res = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage * 10,Green);
}
}
}
}
if(TakeProfit <= SellProfitPips || LossCut <= SellProfitPips * -1){
for( int i=OrdersTotal()-1; i>=0; i-- ){
if( OrderSelect(i, SELECT_BY_POS) == true ){
if( OrderType() == OP_SELL && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol() ){
res = OrderClose(OrderTicket(),OrderLots(),Ask,Slippage * 10,Green);
}
}
}
}
}
int CalculateCurrentOrders()
{
int positions = 0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)
{
positions++;
}
}
return positions;
}
EA(自動売買)を学びたい方へオススメコンテンツ
OANDAではEA(自動売買)を稼働するプラットフォームMT4/MT5の基本的な使い方について、画像や動画付きで詳しく解説しています。MT4/MT5のインストールからEAの設定方法までを詳しく解説しているので、初心者の方でもスムーズにEA運用を始めることが可能です。またOANDAの口座をお持ちであれば、独自開発したオリジナルインジケーターを無料で利用することもできます。EA運用をお考えであれば、ぜひ口座開設をご検討ください。
本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。