Python
virtufin-execution-devkit (PyPI, the virtufin feed) is the Python mirror of
Virtufin.Execution.DevKit: the same bridge from an executor to a WorkManager worker, for the
Python engine (text/x-python, application/x-python) and the Python local WorkManager
(virtufin.worker_devkit.local). It needs virtufin-worker-devkit 0.42.0 or later.
| Module | What |
|---|---|
virtufin.execution_devkit.executor |
Executor (one order in, one trade event out, hidden state), ExecutorWorkerBase |
virtufin.execution_devkit.orders |
the order.submitted payload: OrderSubmitted, decode, encode, limit_order, topic, subject, order_id_of (the order contract of Virtufin.Trading.Contracts) |
virtufin.execution_devkit.trade_events |
OrderAccepted, OrderFilled, OrderCanceled, OrderExpired, fill_id, to_output (TradeEventJson) |
An executor worker
from datetime import datetime, timezone
from virtufin.execution_devkit import Executor, ExecutorWorkerBase, OrderFilled
class FillAtLimit(Executor):
def execute(self, state, order):
if order.price is None:
raise ValueError("needs a limit price")
return state, OrderFilled(order.order_id, order.qty, order.price, None, datetime.now(timezone.utc))
class FillAtLimitWorker(ExecutorWorkerBase):
def __init__(self):
super().__init__("fillatlimit", FillAtLimit())
_worker = FillAtLimitWorker()
Start = _worker.Start # the activation's worker id scopes the derived ids
Process = _worker.process
Dispatch
Per input, in this order, as in C# (see Bridge):
- anything but
com.virtufin.trading.order.submittedis ignored; - the payload is decoded (
orders.decode: every field required exceptpriceandstrategy_id, amounts at 8 decimals half away from zero, the C# error texts) and the side checked; a malformed order is an error response and does not take its order id; - an order whose
order_idthis instance already took is skipped (the last 100 000); scenarioidis required;- the executor runs; its exception is an error response (
Internal error: <message>onwrk.<type>.error, or the order'sreplytopic) and the order id stays taken; - the trade event is published on
sc.<scenarioid>.trading.order.<event>with ce-subjectorder/<order_id>, the order's envelope (virtufin.worker_devkit.envelope.stamp) andeventtime; then the executor's state advances.
WorkerBase.process adds the redelivery rules: a repeated order event (same source and id)
never reaches handle, and every output gets an id derived from the worker id, the order event
and the output, so a fresh instance that executes a replayed order again republishes the same
event (with the same fill_id, trade_events.fill_id(order_id)).
Conformance
The C# SimulatedExecutor and the Python SimulatedExecutorPython (execution-workers) run the
same vectors, conformance/simulated-executor.v1.json there, so a Python executor rejects,
fills, carries and deduplicates exactly as a C# one: SimulatedExecutor, conformance vectors.
Tests
cd src/python && uv run --extra dev pytest -q