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.