高レベルサブスクリプション

概要

Strategy クラスは、高レベルのマーケットデータ購読メソッドとして SubscribeCandlesSubscribeTicksSubscribeLevel1SubscribeOrderBook を提供します。これらのメソッドは ISubscriptionHandler<T> オブジェクトを返し、データハンドラーやインジケーターを便利な fluent スタイルでバインドできます。

Subscription オブジェクトを手動で作成して Subscribe() を呼び出す方法とは異なり、高レベルメソッドには次の特徴があります。

  • 適切なパラメーターでサブスクリプションを自動作成する
  • ハンドラーをバインドするための型付き ISubscriptionHandler<T> を提供する
  • Bind メソッドを介してインジケーターシステムと統合する
  • チャートへの自動描画をサポートする
  • サブスクリプションのライフサイクルを適切に管理する

サブスクリプションメソッド

SubscribeCandles

ローソク足を購読します。タイムフレームまたは DataType を受け取ります。

// タイムフレームで購読
ISubscriptionHandler<ICandleMessage> SubscribeCandles(
    TimeSpan tf,
    bool isFinishedOnly = true,
    Security security = default);

// DataType で購読 (すべてのローソク足タイプをサポート)
ISubscriptionHandler<ICandleMessage> SubscribeCandles(
    DataType dt,
    bool isFinishedOnly = true,
    Security security = default);

// 作成済みの Subscription オブジェクトで購読
ISubscriptionHandler<ICandleMessage> SubscribeCandles(Subscription subscription);

isFinishedOnly パラメーターはデフォルトで true です。この場合、ハンドラーは完成済みのローソク足のみを受け取ります。

SubscribeTicks

ティック約定を購読します。

ISubscriptionHandler<ITickTradeMessage> SubscribeTicks(Security security = null);
ISubscriptionHandler<ITickTradeMessage> SubscribeTicks(Subscription subscription);

SubscribeLevel1

Level1 データ (最良買気配/売気配価格、直近約定、その他のフィールド) を購読します。

ISubscriptionHandler<Level1ChangeMessage> SubscribeLevel1(Security security = null);
ISubscriptionHandler<Level1ChangeMessage> SubscribeLevel1(Subscription subscription);

SubscribeOrderBook

板情報を購読します。

ISubscriptionHandler<IOrderBookMessage> SubscribeOrderBook(Security security = null);
ISubscriptionHandler<IOrderBookMessage> SubscribeOrderBook(Subscription subscription);

security パラメーターを指定しない場合は、ストラテジーの Security が使用されます。

ISubscriptionHandler インターフェイス

ISubscriptionHandler<T> オブジェクトは、次のメソッドを提供します。

Start / Stop

サブスクリプションの開始と停止:

handler.Start();   // Subscribe を呼び出す
handler.Stop();    // UnSubscribe を呼び出す

Bind (インジケーターなし)

単純なデータハンドラーをバインドします。

handler.Bind(Action<T> callback);

Bind (インジケーターあり)

1 つ以上のインジケーターを持つハンドラーをバインドします。インジケーターは受信データを自動的に処理し、ハンドラーは計算済みの値を受け取ります。

// 1 つのインジケーター -- decimal 値
handler.Bind(IIndicator indicator, Action<T, decimal> callback);

// 2 つのインジケーター
handler.Bind(IIndicator ind1, IIndicator ind2, Action<T, decimal, decimal> callback);

// 最大 8 つのインジケーター
handler.Bind(ind1, ind2, ind3, ..., callback);

// インジケーターの配列
handler.Bind(IIndicator[] indicators, Action<T, decimal[]> callback);

Bind を使用したハンドラーは、すべてのインジケーターが空でない値を返した場合にのみ呼び出されます。

BindWithEmpty

Bind と似ていますが、インジケーターが空の値を返した場合でもハンドラーが呼び出されます。値は decimal? として表されます。

handler.BindWithEmpty(IIndicator indicator, Action<T, decimal?> callback);

BindEx

抽出された decimal ではなく、完全な IIndicatorValue オブジェクトへアクセスできます。

handler.BindEx(IIndicator indicator, Action<T, IIndicatorValue> callback, bool allowEmpty = false);

例: インジケーターを使用するストラテジー

public class SmaStrategy : Strategy
{
    private readonly StrategyParam<int> _shortPeriod;
    private readonly StrategyParam<int> _longPeriod;
    private readonly StrategyParam<DataType> _candleType;

    public int ShortPeriod
    {
        get => _shortPeriod.Value;
        set => _shortPeriod.Value = value;
    }

    public int LongPeriod
    {
        get => _longPeriod.Value;
        set => _longPeriod.Value = value;
    }

    public DataType CandleType
    {
        get => _candleType.Value;
        set => _candleType.Value = value;
    }

    public SmaStrategy()
    {
        _shortPeriod = Param(nameof(ShortPeriod), 10);
        _longPeriod = Param(nameof(LongPeriod), 20);
        _candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
    }

    protected override void OnStarted2(DateTime time)
    {
        base.OnStarted2(time);

        var shortSma = new SimpleMovingAverage { Length = ShortPeriod };
        var longSma = new SimpleMovingAverage { Length = LongPeriod };

        var subscription = SubscribeCandles(CandleType);

        // 2 つのインジケーターをバインド -- 両方のインジケーターが
        // 形成されたときにハンドラーが呼び出される
        subscription
            .Bind(shortSma, longSma, (candle, shortValue, longValue) =>
            {
                if (!IsFormedAndOnlineAndAllowTrading())
                    return;

                if (shortValue > longValue && Position <= 0)
                    BuyMarket(Volume + Math.Abs(Position));
                else if (shortValue < longValue && Position >= 0)
                    SellMarket(Volume + Math.Abs(Position));
            })
            .Start();

        // チャート設定
        var area = CreateChartArea();
        if (area != null)
        {
            DrawCandles(area, subscription);
            DrawIndicator(area, shortSma);
            DrawIndicator(area, longSma);
            DrawOwnTrades(area);
        }
    }
}

例: ティックサブスクリプション

protected override void OnStarted2(DateTime time)
{
    base.OnStarted2(time);

    SubscribeTicks()
        .Bind(tick =>
        {
            if (!IsFormedAndOnlineAndAllowTrading())
                return;

            this.AddInfoLog("ティック: 価格={0}, 数量={1}", tick.Price, tick.Volume);
        })
        .Start();
}

例: 板情報サブスクリプション

protected override void OnStarted2(DateTime time)
{
    base.OnStarted2(time);

    SubscribeOrderBook()
        .Bind(book =>
        {
            var bestBid = book.GetBestBid();
            var bestAsk = book.GetBestAsk();

            if (bestBid != null && bestAsk != null)
            {
                var spread = bestAsk.Price - bestBid.Price;
                this.AddInfoLog("Spread: {0}", spread);
            }
        })
        .Start();
}

手動でのサブスクリプション作成との違い

観点 手動サブスクリプション 高レベルメソッド
作成 new Subscription(DataType, Security) SubscribeCandles(tf)
データ処理 コネクターイベントへの購読 Bind(callback)
インジケーター 手動での indicator.Process() 呼び出し Bind(indicator, callback) により自動
インジケーター登録 Indicators への手動追加 Bind 時に自動
チャート描画 IChart との手動統合 DrawCandles, DrawIndicator

高レベルメソッドは、コード量を大幅に削減し、エラーの可能性を下げるため、ほとんどのストラテジーでの使用が推奨されます。