こんな処理をするときは要注意
どれもときどき必要になる処理なんですが、ちょっと気を付けないと思ったように動作しない可能性があるため、注意が必要です。いずれもcTrader ver3.8で確認してます。
発注時にstopPipsを指定したい
× var stopPips = 20.123456;
ExecuteMarketOrderなど発注メソッドでstopPipsやtakeProfitPipsを指定する場合、これをそのまま渡してはいけません。stopやtakeProfitPipsは、必ず小数点以下を適切な桁数に丸めておく必要があります。なぜか値動きより細かい数値を指定すると発注エラーになる可能性があるのです。
もちろんこんなコードを直接書くことはないでしょうが、なんらかの計算をした結果stopPipsがこのような数値になるということは十分あり得ます。ではこれをどうやって丸め処理をすればいいでしょうか。
△ stopPips = Math.Round(stopPips, 1);
単純にFXのメジャー通貨ペア限定であればこれでOK。小数点以下一けたで丸めておけば間違いありません。現在はほとんどのブローカーで値動きは0.1Pips刻みですから。
ただ、インデックスや資源など別シンボルでも使うcBotの場合はこうはいきません。値動きが常に0.1Pipsとは限らないのです。
ではこの小数点以下の1の部分はどう決めればいいのでしょうか。0にしておけば発注自体は通るでしょうが、それでは細かなstopの設定ができなくなってしまいます。Symbolに応じて桁数を変えてあげる必要があります。
〇 stopPips = Math.Round(stopPips, Symbol.Digit + Math.Log10(Symbol.PipSize));
FX以外でも使う可能性があるcBotでは、こっちの方が間違いありません。
stopPipsは0.1Pips単位の値動きがあるなら小数点以下1桁に、0.01Pips単位で値動きがあるなら小数点以下2桁に丸める必要があります。
つまり(シンボルのtickSizeの小数点以下桁数ーpipSizeの小数点以下桁数)に丸める必要があるということです。tickSizeの小数点以下桁数はSymbol.Digitで直接整数で取得できるため、このような形になります。
シンボルを限定しないで稼働させるcBotではこのような形での桁丸めにしておいた方がいいでしょう。
現在時刻を取得したい
△ Bars.OpenTimes.LastValue
今のローソク足の開始時間でいいならばこれでいいです。でもこれでは正確な現在時刻はわかりません。例えば、あと何分でローソク足が更新されるかなどはわかりません。
△ DataTime.Now
リアルな現在時刻が欲しいだけならこれでいいです。C#標準のDateTimeのNowプロパティを使います。TimeZoneの調整は忘れないようにしてください。
ただし、バックテスト上ではおそらく想定通りの動作にはなりません。実際はバックテスト進行中であれば、バックテストデータ上での現在時刻が欲しいはずです。
〇 Server.Time
バックテストデータ上の現在時刻が欲しい場合はこれを使います。わかってしまえば簡単なんですが、Serverプロパティの存在感が薄いので、ついBarsやChartのプロパティを探してしまうんですよね。(追記:そもそもRobotやIndicaterがTimeプロパティで持ってました。気づかなかった・・・)
基本的にはこれを使っておけば間違いありません。しかし1点だけ注意すべき点があります。
注意:ビジュアルモード上で表示させたインジケーターからは常にリアルな時刻が返る
cTraderでは、インジケーターをビジュアルモードのバックテスト上で表示させた場合はリアルな現在時刻を返してしまいます。(cBot内で参照追加してGetIndicatorで使う場合は問題ありません。)
ビジュアルモード上で表示させる目的でインジケーターを作ることなんてないかもしれませんが、cTranerのようにバックテストでトレード練習をすることを考慮するなら意が必要です。
注意
IsBacktestingはfalseを返しますし、MarketData.GetBarsメソッドも現在までの価格を一気に返します。(プロパティのBarsはちゃんとバックテスト上の日時になります。)
ビジュアルモードバックテストをトレード練習に使う際はこの仕様は頭に入れておいた方がよさそうです。例えばマルチタイムフレーム系のインジケーター等は作り方次第では価格を先読みして表示してしまう可能性があります。
ビジュアルモード上でトレード練習というのはもともと特殊な使い方ですからね。普通にバックテストするだけであれば問題ないので、このような仕様なんでしょう。
チャート上に最新のBarが表示されてるか知りたい
× bool isNew = (Chart.LastVisibleBarIndex == Bars.Count-1);
普通に考えればこれでいいはずです。チャート上に見えてるバーの最後のインデックスが、最新のインデックスと同じかどうか確認しています。実際、リアルタイム環境ではこれで問題ありません。
しかしバックテスト上ではChartのLastVisibleBarIndexにバグがあるようで、まともに機能しません。
△ bool isNew = (Chart.MaxVisibleBars > Chart.LastVisibleBarIndex - Chart.FirstVisibleBarIndex+1);
完全な解決策はないのですが、私はこれで判定するようにしてます。チャート右側ぎりぎりに最新データが表示されていた場合は判定を誤りますが、普通は最新データを表示してる場合、右側に余白があるため問題になりません。
cTraderのバージョンアップに期待
個人的にはいずれもcTrader側で対応してもらいたいところです。
発注時のPips桁合わせくらい内部でやってくれてもいいでしょうよ。
特殊な使い方とはいえビジュアルモードで表示させたインジケーターもバックテスト扱いしてあげて欲しいです。
LastVisibleBarIndexに関しては、普通にバグですよね。早く治してもらえることを期待してます。
バージョンアップでこの記事が意味なくなることを願っています。