Skip to main content

YU15-eod-risk-extract architecture

The end-of-day risk extract turns the completion of the overnight P&L batch into one immutable, byte-reproducible portfolio fixture. eod.pnl.done triggers the producer; a sequenced risk-extract marker through the consensus log names a sequence N; every member renders the identical position cut at N and the leader publishes it over NATS; the producer joins that cut with the published closing-price version and the counterparty reference data, sends a second marker to witness that nothing traded during the build, and writes one write-once object announced on risk.extract.ready. Positions come from the replicated state machine, never from the asynchronous SQL read model; state at a consensus sequence is a consistent cut by construction, which is what makes the consumer's VaR mathematically valid.

  • Inherits architectural baseline from: YU14-listed-equity-options
  • Generated from: system/architecture.model.json
  • Canonical flows: architecture.md

Architecture Diagram​

Node Catalog​

NodeKindLabelNotes
eod_chainserviceYU06 EOD batch chaintrade-processor publishes the immutable closing-price version; position-service marks against exactly that version and emits eod.pnl.done. Inherited unchanged; this state adds a subscriber, not a step.
pnl_donequeueeod.pnl.done (JetStream)The only trigger. Chosen over eod.prices.ready because it fires after P&L exists, so the consumer's reconciliation target is already written. Durable consumer, so a failed extract is redelivered rather than lost.
producerserviceRisk-extract producerRiskExtractMain: same image as the node and gateway, different main. Opens a fresh cluster session per batch, offers the marker, receives the cut, joins marks and reference data, writes the object, announces it.
consensusserviceAeron Cluster consensus (leader + followers)Inherited: one totally-ordered committed log applied identically by every member. The marker is ordinary ingress; it occupies a sequence and mutates nothing.
markerserviceSequenced extract marker (SBE template 8)Carries only the stamp: request id, session date, closing-price version. On apply, every member advances appliedSeq, renders the cut, and records its SHA-256. Routed by template id ahead of the order-flow branch, so the hot path is untouched.
engine_statestoreReplicated positions + last trade prices + multipliersThe engine's PositionBook (quantity, weighted average cost), lastPxBySecurity from YU13, and the YU14 contract multiplier; all replicated state, all read at the same sequence.
cutqueuerisk.extract.cut (NATS)One message carrying the whole cut and its own row count, so truncation is detectable. Leader-only publish over a non-blocking SPSC queue and daemon thread; the ADR-048 shape, so the apply thread never blocks on the network.
price_snapshotstoreeod_price_snapshot (published closes)Immutable rows addressed by (session_date, version). Safe to read at any time precisely because a correction is a new version, never an update; unlike the positions read model.
reference_datastorecounterparties.csv (accountId to counterparty)Inherited from YU14 and rendered into the image. Supplies counterparty identifier, netting set, and currency as row attributes; the extract never nets by them.
fixturestoreImmutable extract object (+ its cut)Write-once under (sessionDate, priceVersion, consensusSequence), file:// on kind and gs:// in cloud. The cut is stored beside the fixture so the fixture can be rebuilt and byte-compared without the cluster.
readyqueuerisk.extract.ready (NATS)Carries the URI, the stamp, the row count, both hashes, and the quiescence witness sequence. Named so a risk.analytics.* return path slots in later without renaming this one.
risk_engineexternalPricing and risk enginePulls the object when announced, prices it, and computes VaR. Applies netting and CSA treatment itself; scores the identical portfolio across CPU, GPU, and TPU because the bytes are identical.