Skip to content

LiveExecutor

Live order executor for the LIVE/act scenario (managed JIT, application/x-dotnet-dll), built on virtufin-execution-devkit. Routes orders to Binance's real Spot trading API.

⚠ Before deploying this against real capital

This worker has not been tested against Binance's real API or testnet. It was written from Binance's published REST API documentation with no network access available to verify signing or response parsing against the live service. Before pointing this at act:

  1. Set BINANCE_BASE_URL=https://testnet.binance.vision and run it against Binance's testnet with testnet API keys first.
  2. Independently verify BinanceSigning.Sign's output against a request you've manually signed and confirmed Binance accepts.
  3. Check whether the symbol(s) you intend to trade have unusual LOT_SIZE/PRICE_FILTER precision requirements (GET /api/v3/exchangeInfo) -- this worker sends quantities/prices as plain decimals without querying or rounding to a symbol's actual step size, so orders on some symbols may be rejected.
  4. Review error handling: a failed/rejected order currently throws, which WorkerBase.ProcessAsync's outer try/catch converts into an error response -- confirm that's the behavior you want for a production trading path.

Behaviour

Subscribes to sc.LIVE.trading.order.submitted -- a live executor only ever serves the reserved LIVE scenario (see the pubsub-topics spec's Topic Patterns requirement); routing real capital under anything but the reserved production scenario id would be a bug.

  • Buy/Sell orders route to POST /api/v3/order (market if no limit price, GTC limit otherwise). Other action types throw.
  • The response's fills[] are collapsed into one TradeEvent.FillReceived (quantity-weighted average price, summed commission). Partial fills across multiple Binance responses aren't handled -- this worker treats the first POST /api/v3/order response as final.

Configuration

Environment variables (process-level, not per-worker CreateWorkerRequest.config -- exchange credentials are the same class of secret VIRTUFIN_REGISTRY_TOKEN is, and per-worker config is stamped onto every triggering CloudEvent, which would leak credentials into the event stream):

Variable Required Meaning
BINANCE_API_KEY yes Binance API key.
BINANCE_API_SECRET yes Binance API secret.
BINANCE_BASE_URL no (default https://api.binance.com) Override for testnet or a proxy.

Deploy

cd LiveExecutor
python3 scripts/build_managed.py --csproj src/Virtufin.Worker.LiveExecutor/Virtufin.Worker.LiveExecutor.csproj
python3 scripts/publish.py --worker-nupkg /tmp/worker-out/Virtufin.Worker.LiveExecutor.nupkg
python3 scripts/create_worker.py --api-client-host localhost --api-client-port 5002

config/config.json's topics already defaults to sc.LIVE.trading.order.submitted. Make sure BINANCE_API_KEY/BINANCE_API_SECRET are set in the WorkManager process's own environment before creating this worker -- not something these scripts set for you. Go through the pre-deployment checklist above first.

Package

Virtufin.Worker.LiveExecutor on the private Gitea NuGet feed; CI publishes via .github/workflows/liveexecutor-nuget.yaml.