過剰最適化を避けることはEA開発者にとって非常に重要です。
最適化を繰り返し完成したEAの成績が出ない。
これは誰もが経験をすることだと思います。
大きな原因の一つは取引数が少ないことです
1つのロジックで数百程度の取引数は必要です。
この条件をクリアをしている人が多いと思いますが、
逆に取引を減らすときにもある程度の取引数が必要です。
例えば、フィルターを付けて成績が良くなったとします。
そのフィルターで取引数が20減りました。
しかし20しか減ってないのでしたらこれは再現性の乏しい過剰最適化です。
フィルターを付けるときにも100程度の取引に影響があるものを使いましょう。
しかしどうしても取引数が足りない時があります。
そんな時の最適化方法を紹介します。
サンプルコード
単純なロジックとコードを利用して、最適化をします。
ドル円で仲値9:55を越えたらショートエントリー 12:00にクローズします。
仲値前のロジックは有名でしたが仲値後の発見は私と自負しております!
さてコードです。
1年の何日目かを返すDayOfYaer()から曜日DayOfWeek()を引いた数
この数が66~303の間は夏時間です!
前準備 過剰な利益の削除 重要
バックテスト「結果」タブの「損益」を利益の大きい順に並べます。
一回の取引で41,200円の利益が出ています。
これは他のものに比べて極端に大きい数字で再現性があると考えられません
21,060や15,430も同様です。
基準として損益順に並べ替えをして前の取引と1割以上離れている物を「過剰な利益」としています。
この他にも基準はトップ10%削除や3σなど色々やり方があります。
今回の削除対象は上から以下のようになりました。
2016.6.24(ブレクジット)
2016.11.09(トランプ勝利)
2020.3.9(コロナ)
2008.3.17(サブプライム)
2020.3.12(コロナ)
2008.10.24(リーマン)
2005.12.14
2020.3.20(コロナ)
この日にはエントリーしないようにします。
{
if(Year()==2016&&Month()== 6&&Day()==24)return;
if(Year()==2016&&Month()==11&&Day()== 9)return;
if(Year()==2020&&Month()== 3&&Day()== 9)return;
if(Year()==2008&&Month()== 3&&Day()==17)return;
if(Year()==2020&&Month()== 3&&Day()==12)return;
if(Year()==2008&&Month()==10&&Day()==24)return;
if(Year()==2005&&Month()==12&&Day()==14)return;
if(Year()==2020&&Month()== 3&&Day()==20)return;
int d,H=Hour(),D=DayOfYear()-DayOfWeek();
if(66<=D&&D<=303)H--;
if(H>=5&&OrderSelect(0,0))d=OrderClose(OrderTicket(),0.1,Ask,0);
if(H==2&&Minute()==55)d=OrderSend("",OP_SELL,0.1,Bid,0,0,0);
}
同様にワーストも削る場合もありますがリスクは残しておきます。
期待利得 184.77->154.30
この8取引の影響の大きさがうかがえます。
一部抜粋試験
仲値は曜日や日の影響を受けやすく、インジケーターの影響は受けにくい極めて特殊なロジックです。
何日が適していて何日が除外するべき日なのかを調べます。
2005年から1日の取引数は150日以下です。
過剰最適化になりやすい数のため様々に分けて検証をします。
ウォークフォワードをするともっとも重要な直近を最適化に入れられないため、
同じ期間を分けて検討します。
分け方は偶数、奇数月というような期間も曜日も同じようになりやすい形です。
①すべて
②偶数月
③奇数月
④偶数年
⑤奇数年
⑥DayOfYear()偶数
⑦DayOfYear()奇数
※DayOfYear()は一年の何日目かを返します。
先程の「過剰な利益」は除外したままです。
void OnTick()
{
if(DAY!=Day())return;
//if(Month()%2!=0)return;//偶数月
//if(Month()%2==0)return;//奇数月
//if(Year()%2!=0)return;//偶数年
//if(Year()%2==0)return;//奇数年
//if(DayOfYear()%2!=0)return;//偶数通し日
//if(DayOfYear()%2==0)return;//奇数通し日
if(Year()==2016&&Month()== 6&&Day()==24)return;
if(Year()==2016&&Month()==11&&Day()== 9)return;
if(Year()==2020&&Month()== 3&&Day()== 9)return;
if(Year()==2008&&Month()== 3&&Day()==17)return;
if(Year()==2020&&Month()== 3&&Day()==12)return;
if(Year()==2008&&Month()==10&&Day()==24)return;
if(Year()==2005&&Month()==12&&Day()==14)return;
if(Year()==2020&&Month()== 3&&Day()==20)return;
int d,H=Hour(),D=DayOfYear()-DayOfWeek();
if(66<=D&&D<=303)H--;
if(H>=5&&OrderSelect(0,0))d=OrderClose(OrderTicket(),0.1,Ask,0);
if(H==2&&Minute()==55)d=OrderSend("",OP_SELL,0.1,Bid,0,0,0);
}
損益とDDを並べました。
右端の合計は最低利益、最大DDです。
最大DDは上位50%を色づけました。DD20,000が境界です
①最低損益 マイナスの削除
1-4,6,7,9-11,18,22,24,26-28,31日は削除対象です。
10と27日は「すべて」の損益が25,000以上ありDDも20,000以下のため残してもいいと思います。
残したのは5、8、10、12、13、14、15、16、17、19、20、21、23、25、27、29、30日です。
18日はなぜか成績が悪い仲値後の特異日です!
最適化後の結果「過剰な利益」を削除したものと比較します。
左「最適化前」→右「最適化後」
純益 678,090 → 691,690
PF 1.30→1.64
取引数 4,404 →2,445
DD 40,450 → 31,870
期待利得 153.97→282.90
勝率 54.56% → 57.75%
平均勝ち 1210.15 → 1257.70
平均敗け -1114.39 → -1049.55
リカバリファクタ 1.3 → 1.64
Stagnation 845 → 482 ※DD発生から最高値更新までの最大日数
すべての項目で改善が見られています。
何よりもチャートの歪さがなくなりました。
取引数が少ないEAでも条件をうまくすることで、
過剰最適化をさけ確実に最適化ができます。
最後にこのコードを個人利用はしていただいて問題ありませんが、販売はしないでください。
コードを公開していますが、著作権は放棄していません。
そして、使う場合もこのままではなくもう少し調整することをおすすめします。
0 件のコメント:
コメントを投稿