Skip to main content

mts1b-oms-algos — public API surface

Each algorithm is an async generator that yields child orders.

The contract

from typing import AsyncIterator
from mts1b_foundation.orders import Order

async def execute(parent: Order, *, params: dict) -> AsyncIterator[Order]:
"""Execute parent order via this algorithm. Yields child orders."""

Algorithms own slice sizing + timing + child order types. OMS owns state, idempotency, broker routing per child.

Algorithms

VWAP

from mts1b_oms_algos.vwap import execute

async for child in execute(parent_order, params={
"horizon_minutes": 30,
"volume_profile": "intraday_estimated", # or "uniform"
"max_participation": 0.10, # cap at 10% of bar volume
"child_order_type": "limit", # or "marketable_limit"
}):
await oms.submit(child)

TWAP

from mts1b_oms_algos.twap import execute

async for child in execute(parent_order, params={
"horizon_minutes": 30,
"n_slices": 30,
"jitter_pct": 0.2, # ±20% jitter on slice timing
"child_order_type": "limit",
}):
await oms.submit(child)

POV — Participation of Volume

from mts1b_oms_algos.pov import execute

async for child in execute(parent_order, params={
"target_participation": 0.15,
"max_horizon_minutes": 120,
"volume_lookback_minutes": 5,
}):
await oms.submit(child)

Iceberg

from mts1b_oms_algos.iceberg import execute

async for child in execute(parent_order, params={
"display_qty": Decimal("100"),
"refill_threshold": Decimal("50"),
"limit_price": Decimal("180.50"),
}):
await oms.submit(child)

Almgren-Chriss

from mts1b_oms_algos.almgren_chriss import execute

async for child in execute(parent_order, params={
"horizon_minutes": 30,
"risk_aversion": 1.0,
"volatility": 0.18, # annualized vol
"permanent_impact": 0.1, # bps per unit of parent size
"temporary_impact": 5.0, # bps per unit of slice size
}):
await oms.submit(child)

Implementation Shortfall (IS)

from mts1b_oms_algos.is_ import execute

async for child in execute(parent_order, params={
"arrival_price": Decimal("180.50"),
"risk_aversion": 1.0,
"max_horizon_minutes": 60,
"urgency": "medium", # low | medium | high
}):
await oms.submit(child)

When to use which

ScenarioAlgorithm
Standard rebalance, moderate sizevwap
Schedule-driven, want predictable timingtwap
Liquidity-driven, fraction-of-flowpov
Hide block sizeiceberg
Optimal impact-vs-timing tradeoffalmgren_chriss
Urgent — beat arrival priceis_
Tiny order (under threshold)None — direct submit to broker

Algorithm dispatch by name

from mts1b_oms_algos import ALGO_REGISTRY

algo = ALGO_REGISTRY["vwap"]
async for child in algo(parent_order, params={"horizon_minutes": 30}):
await oms.submit(child)

Risk

Child orders go through the full OMS pipeline — same risk gates as any order. The algorithm only decides the slice schedule; OMS still:

  • Dedupes via idempotency_key
  • Calls riskengine.CheckOrder per child
  • Routes to the broker

A faulty algorithm cannot bypass risk; worst case it generates too many child orders → riskengine rejects the excess.

Child idempotency keys

Each child gets a key derived from the parent + slice index:

child_key = f"{parent.idempotency_key}-slice-{i:03d}"

This makes the algorithm replay-safe across crashes.

TCA hooks (Wave 2)

Post-trade, each algorithm can emit metrics to compare actual vs benchmark:

async for child in execute(parent_order, params={..., "emit_tca": True}):
...

# Published to mts.v1.oms.algos.tca:
# {algo: "vwap", parent_id: ..., avg_fill_price: ..., vwap_benchmark: ...,
# slippage_bps: ..., timing_cost_bps: ...}

See also