cAlgo Tips & Sample

【cAlgo】含み損益状況をリアルタイムに取得する【Tips】

Positionの状態をリアルタイムで把握したい

保有中ポジションの情報はPositionsプロパティから取得できます。例えば全ポジションの総含み損益が知りたければ

private double GetTotalUnrealized() {
    double sum = 0;
    foreach(var pos in Positions){
        sum += pos.NetProfit;
    }
    return sum;
}

こんな風なメソッドを作って呼んであげればいいわけです。しかし、総含み損益なんて刻一刻と変わっていくものです。

そこで今回のテーマは、リアルタイムで総損益を使用するにはどのタイミングでこれを呼んで取得すればいいのか、ということです。

 

3つの方法

3つ方法を紹介しますが、手軽→正確(よりリアルタイム)の順で紹介してますので用途に合わせてお使いください。

 

1.OnTickやCalculateで取得する

当たり前の方法ですね。これであれば値動きがあるたびに損益計算がされるので、プログラム稼働中の通貨ペアのポジションだけであればこれでOKです。

protected override void Calculate() {
    var unrealized = GetTotalUnrealized();
    // 表示させる等、なんか処理
}

問題は他の通貨ペアのポジションの損益も正しく取得したい場合です。稼働中通貨ペアで値動きがない限り、他通貨ペアのポジション損益は更新されません

とはいえほとんどの通貨ペアでは数秒に1回くらいは更新されることになると思うので、おおざっぱでいいならこれで十分かもしれません。

 

2.TimerStartを仕掛けてOnTimerで取得する

たぶんそこそこちゃんとやりたいときの一番手軽な方法。cAlgoでのTimerはこんな感じで簡単に使えます。

protected override void Initialize() {
    var interval = new TimeSpan(0, 0, 0, 0, 30);
    Timer.Start(interval); // 30ms間隔でOnTimerを実行させる
}
protected override void OnTimer() {
    var unrealized = GetTotalUnrealized();
    // 表示させる等、なんか処理
}

これだけでTimer.Stopで止めるかプログラム自体を止めるまで、30ms間隔でOnTimer内の処理が実行されるようになります。

例では30ms間隔での実行にしてますが、やりたいことに合わせて変更してください。重たい処理をさせたいならもっと間隔あけた方がいいかもしれません。

逆にとにかく頻繁に処理を行わせたいならさらに短くしてもかまいません。ただしタイマーの精度は15ms程度です。これ以下の値を設定しても、約15ms間隔での実行になります。

 

3.各通貨ペアの値動きに合わせて取得する

ポジションの通貨ペアに値動きがあり次第、損益を更新する。これぞリアルタイムといった感じですね。30ms間隔で行うよりも処理に無駄がありません。ただ上記の方法に比べると少しだけ面倒です。

コピペする場合はファイル冒頭にこれを書き加えておいてください。

using System.Collections.Generic;
using System.Linq;

以下はメインのIndicatorサブクラス内のコードです。(cBotの場合はInitialize()をOnStart()に書き換えて)

private List<Symbol> _symbols;

protected override void Initialize() {
    _symbols = new List<Symbol>();

    // すべてのポジションのSymbolでTickイベントに処理を加える
    foreach (var p in Positions) TryAddSymbol(p.SymbolName);

    //新たなSymbolのPositionが増えたら_symbol追加
    Positions.Opened += args => TryAddSymbol(args.Position.SymbolName);

    //不要なSymbolを解放
    Positions.Closed += args => {
        var symbolName = args.Position.SymbolName;
        if (Positions.Select(pos => pos.SymbolName).Contains(symbolName)) return;
        var symbol = _symbols.Find(s => s.Name == symbolName);
        if (symbol != null) {
            symbol.Tick -= OnSymbolTick;
            _symbols.Remove(symbol);
        }
    };
            
}
//-----------------------------------------------------
// _symbolsになければ追加してTickイベントに処理を加える
private bool TryAddSymbol(string symbolName) {
    if (!_symbols.Select(s => s.Name).Contains(symbolName)) {
        var symbol = Symbols.GetSymbol(symbolName);
        if (symbol == null) throw new ArgumentException();
        symbol.Tick += OnSymbolTick;
        _symbols.Add(symbol);
        return true;
    } else return false;
}

//---------------------------
// リアルタイムで行いたい処理
private void OnSymbolTick(SymbolTickEventArgs args) {
    var unrealized = GetTotalUnrealized();
    // 表示させる等、なんか処理
}

コードがわかりにくかったら申し訳ありません。コメントに書いてある通りの処理をしてるんだな、と思っていただければいいです。

ポジションの各シンボルを取得して、それぞれのシンボルの値動き(Tick)イベントに合わせて総損益を更新しています。

Positionsに変更があったときの処理も忘れないでください。Openedで新しい通貨ペアのポジションが追加されたら新たなシンボルを取得します。Closedの処理はなくても動きますが、無駄なメモリ使うのは嫌なので、不要になったシンボルは解放してます。

もしかしたら、手動エントリーしたすべてのポジションの合計損益がいくら以上になったら即時決済する!みたいなcBot作るならこの方法がいいかもしれませんね。たかだか数十msの違いで結果が変わるかどうか知りませんが、少なくとも精神的には安心感あります。

 

なんかリアルタイム処理したいときにどうぞ

今回はポジションの損益を例に出しましたが、他にも相場状況に合わせてリアルタイム表示させたいとき、例えば一覧表形式でスプレッドを表示させたりだとか、通貨ペアごとにトレンド方向を一覧表示したりとか、なにかしらリアルタイムで行いたい処理がある場合はこれらの方法が使えると思います。

ご参考までに。

-cAlgo Tips & Sample

© 2021 cTrader's Life Powered by AFFINGER5