cTraderでEA作成 ~単純論理で利益は出るのか~EA検証編

前回の記事にてcTraderを用いたEAの最適化・バックテストの方法は理解頂けたと思います。

ただ前回の状態では検証した所でマイナスで終わってましたので、実際に利益が出る様に考察・修正していこうと思います。

インジケータの画面出力

cTraderではバックテスト中の挙動を確認する事が出来ます。
方法としては、バックテスト実行前に「 ビジュアルモード 」にチェックを入れるだけです。
チェックを入れ、バックテストを実行する事で、画面上のグラフが経過と共に流れていき、発注・決済が表示されます。

ただそれだけだとどの様なロジックで発注・決済がされて行くのか直感的に解からないので、
今回のロジックで利用するBBを画面上に表示させたいと思います。
方法としては、普段cTraderにて設定するのと同一方法となるので割愛します。

パラメータの確認

前回最適化にて導き出されたパラメータは下記となっていると思います。
【 決済・発注用BB 】
・ Periods :15
・ Standard Dev :3

【 ロスカット用BB 】
・ Periods :15
・ Standard Dev :1.9

上記パラメータの最適化結果で取引総数が 5 回しかなかったと思います。
理由としては、
そもそもマイナスで全て終わっているので回数が少ない方が損失も少ないだろう
って形となっています。

そんな消極的な判断だとあまりにもお粗末なので
今回は取引数が多い下記パラメータで検証していこうと思います。
【 決済・発注用BB 】
・ Periods :198
・ Standard Dev :1.6

【 ロスカット用BB 】
・ Periods :58
・ Standard Dev :2.3

取引総数:847回

パラメータ考察 パラメータは適正か?

今回利用するパラメータをGUI上に表示してみました。

画像1

色としては、
赤: 発注・決済用BB
緑: ロスカット用BB

となっています。

パット見て解かる様に赤BBの中に緑BBが入ってたりしてます。
今回のEAの仕様として、赤BBに反発し逆方向を超過したら決済するという仕様です。
で反発してなくても良い様みどりBBでロスカットを設定する仕様としたいのですが、これだと想定通りなのにロスカットされる事態が発生します。
ロスカットがロスカットとして上手く機能してないので
機能させる様にするには
・  反発する時は緑BBを赤BBより外へ配置する
・ 赤BBが緑BBより中に入っている時は発注をしない
・ 赤BBをそもそもロスカットの値としない。

っていう所なのかなと思います。

反発する時は緑BBを赤BBより外へ配置する

そもそもBBとしてそれは正しいのか、
BBというのは
 
その価格の平均値よりσNの範囲に何%の割合で収まる


というものです。
なのでロスカット値としてBBの範囲を広げた所でロスカット値に近づくにつれ反発する割合は高くなります。

という事は ロスカット値をBBで定義するアプローチ は間違いであるとなります。

またBBの値を超過する動きというのは定義を覆す程の勢いがある動きともいえます。

今回アプローチ方法が間違っているのがわかりましたので、取引規則を変更します。

考察結果により取引規則を変更

現状下記取引規則によりEAを作成しています。
【 既存取引規則 】
発注

・足の終わり値がBBのtop/bottomの値を一度超過し再度BBの範囲内に戻ってきた時、反対方向のBBのtop/bottomへ向け発注する。

決済
・ポジションの利確方向のBBの値を一度超過し再度BBの範囲内に戻ってきた時

損切
・足の終わり値がロスカット用BBを超過した時

上記を下記の様に変更します。
【 修正後取引規則 】
発注

・足の終値が赤BBの値を超過した時超過した方向へ発注

決済
・足の終値が緑BBの値を超過した時

損切
・BBの平均値へ接触した時

大幅な改修となりましたが、上記規則に変更する事で
BBを超過する勢いがある流れに乗るEAを作成します。
修正御のEAは「 SimpleTrade2 」とします。

EAの修正

今回修正した内容は下記となります。

OnTick
【 修正前 】

        protected override void OnTick()
       {
           // ロスカット判定
           // 買いポジションのロスカット判定 
           if ((BB_A.Main.LastValue - Bid) >= 0)
           {
               Close(TradeType.Buy);
           }

           // 売り判定
           // 売りポジションのロスカット判定 
           if ((BB_A.Main.LastValue - Ask) <= 0)
           {
               Close(TradeType.Sell);
           }

           // テスト用 疑似ロスカット
           if (Account.MarginLevel < 100)
           {
               Close(TradeType.Buy);
               Close(TradeType.Sell);
           }

       }

【 修正後 】

        protected override void OnTick()
       {
           // テスト用 疑似ロスカット
           if (Account.MarginLevel < 100)
           {
               Close(TradeType.Buy);
               Close(TradeType.Sell);
           }


       }

OnBar
【 修正前 】

        protected override void OnBar()
       {
           // 決済判定
           // 買い判定
           if ((Flag_Top) && ((BB_A.Top.LastValue - Bars.ClosePrices.LastValue) <= 0))
           {
               Close(TradeType.Buy);
           }

           // 売り判定
           if ((Flag_bottom) && ((BB_A.Bottom.LastValue - Bars.ClosePrices.LastValue) >= 0))
           {
               Close(TradeType.Sell);
           }


           // 発注判定
           //売り判定
           if ((Flag_Top) && ((BB_A.Top.LastValue - Bars.ClosePrices.LastValue) <= 0))
           {
               Open(TradeType.Sell);
           }

           //買い判定
           if ((Flag_bottom) && ((BB_A.Bottom.LastValue - Bars.ClosePrices.LastValue) >= 0))
           {
               Open(TradeType.Buy);
           }


           // BBの値から超過しているかの判定
           Flag_Top = ((BB_A.Top.LastValue - Bars.ClosePrices.LastValue) > 0);
           Flag_bottom = ((BB_A.Bottom.LastValue - Bars.ClosePrices.LastValue) < 0);


       }

【 修正後 】

        protected override void OnBar()
       {
           // 決済判定
           // 買い判定
           if ((BB_L.Top.LastValue - Bars.ClosePrices.LastValue) <= 0)
           {
               Close(TradeType.Buy);
           }

           // 売り判定
           if ((BB_L.Bottom.LastValue - Bars.ClosePrices.LastValue) >= 0)
           {
               Close(TradeType.Sell);
           }

           // 発注判定
           //買い判定
           if ((BB_A.Top.LastValue - Bars.ClosePrices.LastValue) < 0)
           {
               Open(TradeType.Buy);
           }

           // 売り判定
           if ((BB_A.Bottom.LastValue - Bars.ClosePrices.LastValue) > 0 )
           {
               Open(TradeType.Sell);
           }
       }

今回の改修で赤BBの超過有無をフラグとして持つ必要は無くなったので削除しました。

最適化再実施

大幅な改修となったため、再度最適化を実施しパラメータを求めたいと思います。
取得した結果は下記となります。

画像2

結果最適化された値としては下記となります。

【 決済・発注用BB 】
・ Periods :180
・ Standard Dev :1.9

【 ロスカット用BB 】
・ Periods :18
・ Standard Dev :2.5

取引総数:5108回

今回は取引回数も申し分なく、また利益として733.72$発生したので
この値を利用したいと思います。

バックテストの実行

では前回と同様のパラメータでテストを実施します。

結果は、、、

画像3

1月1日開始で1月2日には証拠金が尽きてしまいました、、w

バックテスト結果の検証

結果を見てみると

画像4

キャプチャに表示されているロスカットされたポジションは売りにて入っています。

すべてポジションを張ったのち想定通り値は下がっているのに決済タイミングである緑BBに接触せずその後反転しロスカットされています。

なので 緑BBのパラメータを下記の様に変更し再度バックテストを実施してみました。

【 ロスカット用BB 】
・ Periods :40
・ Standard Dev :2.4

画像5

結果としては、同じく証拠金が尽きてしまいましたが今度は2月6日迄取引できてました。

取引を見ると、決済ポイントである緑BBを超過した後もポジションを持とうとしています。

なので、発注判定に試しに
・ 決済処理後は赤BBの範囲内に入る迄発注はしない

という規則を入れて見ます。

EA修正 決済直後の取引停止

修正したEAは下記となります。
OnTick
【 修正前 】

        protected override void OnTick()
       {
           // テスト用 疑似ロスカット
           if (Account.MarginLevel < 100)
           {
               Close(TradeType.Buy);
               Close(TradeType.Sell);
           }
       }

【 修正後 】

        protected override void OnTick()
       {
           // ロスカット判定
           // 買いポジションのロスカット判定 
           if ((BB_A.Main.LastValue - Bid) >= 0)
           {
               Close(TradeType.Buy);
           }
           // 売り判定
           // 売りポジションのロスカット判定 
           if ((BB_A.Main.LastValue - Ask) <= 0)
           {
               Close(TradeType.Sell);
           }
           // 決済判定
           // 買い判定
           if ((BB_L.Top.LastValue - Bid) <= 0)
           {
               Close(TradeType.Buy);
           }
           // 売り判定
           if ((BB_L.Bottom.LastValue - Ask) >= 0)
           {
               Close(TradeType.Sell);
           }
           // テスト用 疑似ロスカット
           if (Account.MarginLevel < 100)
           {
               Close(TradeType.Buy);
               Close(TradeType.Sell);
           }
       }

OnBar
【 修正前 】

        protected override void OnBar()
       {
           // 決済判定
           // 買い判定
           if ((BB_L.Top.LastValue - Bars.ClosePrices.LastValue) <= 0)
           {
               Close(TradeType.Buy);
           }
           // 売り判定
           if ((BB_L.Bottom.LastValue - Bars.ClosePrices.LastValue) >= 0)
           {
               Close(TradeType.Sell);
           }
           // 発注判定
           //買い判定
           if ((BB_A.Top.LastValue - Bars.ClosePrices.LastValue) < 0)
           {
               Open(TradeType.Buy);
           }
           // 売り判定
           if ((BB_A.Bottom.LastValue - Bars.ClosePrices.LastValue) > 0 )
           {
               Open(TradeType.Sell);
           }
       }

【 修正後 】

        protected override void OnBar()
       {
           // BBの範囲に収まっているか判定
           // 買い判定
           if ((BB_A.Top.LastValue - Bars.ClosePrices.LastValue) >= 0)
           {
               Flag_Top = true;
           }
           // 売り判定
           if ((BB_A.Bottom.LastValue - Bars.ClosePrices.LastValue) <= 0)
           {
               Flag_bottom = true;
           }

           // 発注判定
           //買い判定
           if (((BB_A.Top.LastValue - Bars.ClosePrices.LastValue) < 0) && ((BB_L.Top.LastValue - Bars.ClosePrices.LastValue) > 0) && Flag_Top)
           {
               Open(TradeType.Buy);
           }
           // 売り判定
           if (((BB_A.Bottom.LastValue - Bars.ClosePrices.LastValue) > 0) && ((BB_L.Bottom.LastValue - Bars.ClosePrices.LastValue) < 0) && Flag_bottom)
           {
               Open(TradeType.Sell);
           }
       }

Close
【 修正前 】

        private void Close(TradeType t)
       {
           foreach (Position p in Positions.FindAll(BotName, SymbleName, t))
           {
               ClosePosition(p);
           }
       }

【 修正後 】

        private void Close(TradeType t)
       {
           if (t == TradeType.Buy)
           {
               Flag_Top = false;
           }
           else
           {
               Flag_bottom = false;
           }

           foreach (Position p in Positions.FindAll(BotName, SymbleName, t))
           {
               ClosePosition(p);
           }
       }

修正内容としては
・グラフが描写される毎に
 終値が赤BB内に入っていれば正となる変数を定義

・発注時に 追加した変数が正である判定を追加
・決済時に 追加した変数をfalseへ設定。

これで再度バックテストを実行しようと思います。

画像6

結果としては、3月31日に資金の底尽いてしまいました。
ただ、取引総数4579回の内2/3以上の2718回勝利しています。
損切するタイミングを考慮すれば勝てる様になるかもしれません。

なので今度は、ロスカットタイミングに緑BBの平均値に接触する事を追加してみようと思います。

EA修正 ロスカット規則追加

修正したEAは下記となります。
OnTick
【 修正前 】

        protected override void OnTick()
       {
           // ロスカット判定
           // 買いポジションのロスカット判定 
           if ((BB_A.Main.LastValue - Bid) >= 0)
           {
               Close(TradeType.Buy);
           }
           // 売り判定
           // 売りポジションのロスカット判定 
           if ((BB_A.Main.LastValue - Ask) <= 0)
           {
               Close(TradeType.Sell);
           }
           // 決済判定
           // 買い判定
           if ((BB_L.Top.LastValue - Bid) <= 0)
           {
               Close(TradeType.Buy);
           }
           // 売り判定
           if ((BB_L.Bottom.LastValue - Ask) >= 0)
           {
               Close(TradeType.Sell);
           }
           // テスト用 疑似ロスカット
           if (Account.MarginLevel < 100)
           {
               Close(TradeType.Buy);
               Close(TradeType.Sell);
           }
       }

【 修正後 】

protected override void OnTick()
       {
           // ロスカット判定
           // 買いポジションのロスカット判定 
           if (((BB_A.Main.LastValue - Bid) >= 0) || ((BB_L.Main.LastValue - Bid) >=0))
           {
               Close(TradeType.Buy);
           }
           // 売り判定
           // 売りポジションのロスカット判定 
           if (((BB_A.Main.LastValue - Ask) <= 0) || ((BB_L.Main.LastValue - Ask) <= 0))
           {
               Close(TradeType.Sell);
           }
           // 決済判定
           // 買い判定
           if ((BB_L.Top.LastValue - Bid) <= 0)
           {
               Close(TradeType.Buy);
           }
           // 売り判定
           if ((BB_L.Bottom.LastValue - Ask) >= 0)
           {
               Close(TradeType.Sell);
           }
           // テスト用 疑似ロスカット
           if (Account.MarginLevel < 100)
           {
               Close(TradeType.Buy);
               Close(TradeType.Sell);
           }
       }

ではバックテストを実施します。
結果は、、2日増えて 4月2日に資金が尽きる様になりました、、、
全然だめですね、、
では、取引の勝利数はいくつになったか確認してみると
4500回取引の内 1712回の勝利となりました。。。
やはりロスカット迄の距離を狭めると損失する機会が増えたみたいです。
ただ損失の機会が増えてるのに資金が尽きるのが遅くなったのは、ロスカット1回の額が少なくなったからだと思います。

ただ、これはあくまで延命しているだけみたいなので利益出るEAでは無いですね、、、

今回は長くなってしまったのでここ迄として、次回は一旦今までの検証・改修内容を纏めてみたいと思います。






この記事が気に入ったらサポートをしてみませんか?