C# Examples
C# examples demonstrate connectivity to all three Virtufin services.
Client package
| Package | What it is |
|---|---|
Virtufin.Api.Client |
The API gateway client: State, pub/sub, and every gateway service (workmanager, websocketmanager, ...) through dynamic dispatch |
Virtufin.*.DevKit |
The worker devkits (Worker, Behavior, MarketData, Indicator, Strategy, Execution) the notebooks and dotnet/workers/ build on |
The notebooks get all of them from the one Virtufin.Examples.Notebooks package (below). In a project of your own,
dotnet add package Virtufin.Api.Client from the Virtufin feed (Installation).
Verso notebooks
Most C# examples are Verso notebooks in
dotnet/: the devkits end to end (market data, indicator, strategy, executor), the published engines chained
into a pipeline, the live platform pipelines, and tours of Virtufin.Core/Base. The
README lists them all and covers installing Verso and the registry
credentials. Run one headlessly with verso run <notebook> from dotnet/.
Every notebook loads exactly one package:
#!nuget Virtufin.Examples.Notebooks *
Virtufin.Examples.Notebooks is a dependencies-only package
(dotnet/notebook-packages/).
It lists every package the notebooks use, with its whole dependency closure, at one
consistent set of the latest versions. Verso resolves each #!nuget line on its own and
can load two versions of the same assembly from two lines (CS1503/CS0508/CS1705), so
don't add #!nuget lines next to it. To use another package, add it to the BOM's
Directory.Packages.props. CI publishes a new BOM version when its closure changes.
Central Package Management
The example worker projects in dotnet/workers/ pin their versions in
dotnet/workers/Directory.Packages.props (kept current by Renovate):
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<PackageVersion Include="Virtufin.Indicator.DevKit" Version="..." />
Key Patterns
// The context: a name in ~/.config/virtufin/api/contexts.toml, set at the top of the notebook.
const string ContextName = "demo";
// host, port, tls and apiKey come from the context's entry (platform.cs resolves them).
var api = new ApiClient(context.Host, context.Port, context.Tls, context.ApiKey);
dynamic gateway = api; // gateway services resolve at the call site
// WebSocketManager through the gateway
var connected = await gateway.websocketmanager.Connect(new Dictionary<string, object?>
{
["url"] = "wss://stream.binance.com:9443/ws/btcusdt@kline_1m", // Binance's symbol for BTC_USDT
["auto_reconnect"] = true,
});
await gateway.websocketmanager.StartPublish(new Dictionary<string, object?>
{
// act.exchange.binance.candle.update, from the naming library (names.cs in examples/dotnet)
["id"] = connected["id"]!.ToString(), ["topic"] = NotebookNames.CandleUpdateTopic(),
});
// State: a service the gateway registers ("statestore" on demo and local)
await api.SaveStateAsync("statestore", "x.notebook.my-key", "{\"hello\":\"virtufin\"}");
var (value, etag) = await api.GetStateAsync("statestore", "x.notebook.my-key");
dotnet/platform.cs wraps this for the notebooks: Platform.ConnectAsync(ContextName) resolves the context,
deploys workers and connections, and CleanupAsync removes everything the notebook created.