Skip to content

Strategy Author Guide

The full guide — implementing IDecide, subclassing StrategyWorkerBase, and wiring per-instance config — lives in the strategy devkit docs. This page covers only what's specific to deploying a strategy worker from this repo.

Structure

A C# strategy worker in this repo is a thin WorkerBase subclass that composes the devkit's StrategyWorkerBase with an IDecide:

public sealed class MyWorker : StrategyWorkerBase<MyState, RichMarketEvent, PortfolioState, TradeAction>
{
    public MyWorker() : base(
        new Uri("urn:virtufin:worker:myworker"),
        "myworker.response",
        new MyStrategy(),
        new PortfolioAlgebra())
    {
    }

    protected override OrderSubmission ToOrderSubmission(CloudEvent input, TradeAction action)
        => action switch
        {
            TradeAction.BuyOrder buy => new OrderSubmission(
                buy.OrderId ?? Guid.NewGuid(), buy.Symbol.Value, "buy",
                buy.LimitPrice is null ? "market" : "limit", buy.Quantity, buy.LimitPrice, "binance-spot"),
            TradeAction.SellOrder sell => new OrderSubmission(
                sell.OrderId ?? Guid.NewGuid(), sell.Symbol.Value, "sell",
                sell.LimitPrice is null ? "market" : "limit", sell.Quantity, sell.LimitPrice, "binance-spot"),
            _ => throw new ArgumentOutOfRangeException(nameof(action), action.GetType(),
                "MyStrategy only emits Buy/Sell orders."),
        };
}

The devkit packages are consumed via NuGet package references (Virtufin.Strategy.DevKit and friends), never project references — they live in the separate virtufin-strategy-devkit repo.

Deploy

Publish the worker package (CI), then CreateWorker with two explicit topics -- the scenario's market-data feed and its position feed (not a wildcard: the deployed Dapr pubsub component is Redis Streams, which has no wildcard subscription support):

{ "topics": ["act.exchange.binance.candle.closed", "sc.LIVE.position.snapshot"] }

Per-instance config (e.g. timewindowdays, and scenarioid -- required by the trading envelope) arrives as CloudEvent extension attributes; see the devkit docs for the extension-only config rules.