17.EAを修正する
EAに限らず、プログラミングに修正はつきものです。
もともとちゃんとしたロジックがあって、それをEA化している場合にはロジック自体の修正というのはあまり無いのかもしれません。
前々回作成したものはそもそもロジックが適当ですので、ロジック自体に少し手を入れていきます。
まず現在のロジックを再度確認します。
- 稼働させる通貨ペア・タイムフレームは不問とする
- 200SMAが上昇しているか下降しているか調べる
– 200SMAの現在値と1つ前のバー時点での値を比較し、値が大きくなっていれば上昇、逆なら下降とする(完全に同値だった場合、これ以降の処理は行わない) - 20SMAが200SMAの上下どちらに位置しているか調べる
- 200SMAが上向きかつ20SMAが200SMAより上に位置する時、バーが20SMAを下から上に抜けたらロングエントリーする
逆の場合にショートエントリーする - 期間20のボリンジャーバンド±2σラインを使い、エントリーと逆方向のラインにタッチしたら決済する
バックテストによるトレード結果を見て、ボリンジャーバンドがスクイーズしているようなレンジ期間では、ひたすら損切りになっている事が気になりました。
また、レートが伸びる場合にはエントリーし直すことにはなりますが、±2σで決済することが勿体ないと感じる場面も見られました。
これを受け、決済条件を200SMAタッチに変更します。
エントリー位置と200SMAまでの値幅がかなり開いているケースが考えられるため、ストップロスを設定し、最大損失をPipsで制限することにします。
(とりあえず、20pipsにします。)
また、スクイーズ箇所ではなるべくエントリーしてほしくないので、簡易的にボリンジャーバンドの上下ラインの内側に200SMAが存在する場合は、エントリーしないことにします。
上記変更を加えると以下のようなコードになります(OnTick内のみ記載)。
void OnTick() { if(OrdersTotal() == 0) { //ポジションを持っていない時は、ここに処理が入る double sma200 = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での200SMA double sma200_prev = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 1); //1本前のバー時点での200SMA double sma20 = iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での20SMA double sma20_prev = iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1); //1本前のバー時点での20SMA double bb_upper = iBands(Symbol(), Period(), 20, 2.0, 0, PRICE_CLOSE, MODE_UPPER, 0); //ボリンジャーバンド+2σ double bb_lower = iBands(Symbol(), Period(), 20, 2.0, 0, PRICE_CLOSE, MODE_LOWER, 0); //ボリンジャーバンド-2σ if(sma200 > sma200_prev) { //200SMAが上昇なら、ここに処理が入る if(sma20 > sma200) { //20SMAが200SMAより上に位置するなら、ここに処理が入る if(Open[1] < sma20_prev && Close[1] >= sma20_prev && Bid > sma20) { //バーが20SMAを上抜けたら、ここに処理が入る if(bb_lower > sma200) { //200SMAがボリンジャーバンドの外側(下)にある場合のみエントリー OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, Bid-200*Point(), 0, NULL, 12345); //買い注文・損切り20pips・マジックナンバー12345 } } } } else if(sma200 < sma200_prev) { //200SMAが下降なら、ここに処理が入る if(sma20 < sma200) { //20SMAが200SMAより下に位置するなら、ここに処理が入る if(Open[1] > sma20_prev && Close[1] <= sma20_prev && Bid < sma20) { //バーが20SMAを下抜けたら、ここに処理が入る if(bb_upper < sma200) { //200SMAがボリンジャーバンドの外側(上)にある場合のみエントリー OrderSend(Symbol(), OP_SELL, 0.1, Bid, 3, Bid-200*Point(), 0, NULL, 12345); //売り注文・損切り20pips・マジックナンバー12345 } } } } else { //200SMAが水平移動しているなら、ここに処理が入る } } else { //ポジションを持っている時は、ここに処理が入る double sma200 = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での200SMA for(int i=OrdersTotal()-1; i>=0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderMagicNumber() == 12345) { //このEAによるポジションがあればここに処理が入る if(OrderType() == OP_BUY && Bid <= sma200) { //200SMAタッチで決済 OrderClose(OrderTicket(), OrderLots(), Bid, 3); } else if(OrderType() == OP_SELL && Bid >= sma200) { //200SMAタッチで決済 OrderClose(OrderTicket(), OrderLots(), Ask, 3); } } } } } }
上記をコンパイルし、前回と同期間でバックテストすると、以下のようになりました。
勝率はさらに下がりましたが、残高はトントンになっています。
細かなエントリーが減ったためと考えられますが、総取引数が半分以下になっているので、テスト期間を2021/06/01~2022/05/31まで広げ、再度テストを実行します。
総取引回数はほぼ同じになりましたが、結果はトントンのままでした。
この期間ではトントンというだけで、もっと長い期間でテストすればほぼ右肩下がりにはなると思います。
実際のところロジックの変更は、より良いものになっているのかどうかが分からない事が多いです。
根気よく検証作業を繰り返して、より良いEAを目指したいところです。
今回加えた変更の中に、損切りを-20pipsにするというものがありました。
テストを5分足で行ったので問題無さそうでしたが、これが1時間足になれば損切りが近すぎることになります。
時間足を変更するために毎度ソースコードを書き換えてコンパイルするのはバカバカしいので、普通こういったデータは外部入力できるようにします。
次回は、EA稼働時にpipsやロットなどを外部入力できるように変更します。