Class VenueScorecard
java.lang.Object
com.quantfinlib.execution.VenueScorecard
Streaming per-venue execution quality — the equities counterpart of
fx.LpScorecard: displayed prices tell you where a venue claims
you'll trade; the scorecard tells you what actually happens when you send
there. Everything the AdaptiveSor needs beyond the quote:
- Fill rate: EWMA of {1 fill, 0 miss} per marketable child, the venue's reliability. Quotes fade, systems reject, sessions hiccup; a venue that fills 80% of what you send is worth less than its displayed price says;
- Response latency — EWMA of send→ack/fill time as you measure it, which routinely disagrees with the venue's advertised number;
- Hidden liquidity — for dark venues, an EWMA of the shares each probe actually found. "Unknown" becomes an estimate only by probing and remembering;
- Post-fill markout (adverse selection): what the mid does
one horizon after your fill, signed in your trading direction.
Positive means the price kept going your way (a clean fill);
negative means it reverted (you paid the spread to trade against
informed or stale flow, the "fade" venues). Arm it via the extended
onFill(int, long, boolean, double, long)and feed mids viaonMid(double, long); it is the equities counterpart offx.LpScorecard's post-reject markout. The markout leg makes the card single-symbol:onMid(double, long)matures every pending fill against the one mid it is given, and the markout is in absolute price units. Use one card per symbol once you use it (the fill-rate/latency stats alone were symbol-agnostic).
All statistics are exponentially weighted per event so the card tracks
current behavior (each EWMA seeds from the prior / first observation, so a
venue is never scored below "never tried" for its first fill). Before any
data, fillRate(int) returns a configurable optimistic prior (a new
venue deserves flow until it proves otherwise). Zero allocation per event,
single writer (the execution-events thread).
This is the streaming venue-quality tool for the routing hot
path; VenueBenchmark is the batch counterpart (fill rate,
effective spread and markout over a sample list) for post-trade venue
analysis.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intPending fill-markout slots per venue (bursts deeper overwrite oldest). -
Constructor Summary
ConstructorsConstructorDescriptionVenueScorecard(int venueCount) 5% event weight, 0.95 prior, 100 ms markout horizon.VenueScorecard(int venueCount, double alpha, double fillRatePrior) 100 ms markout horizon.VenueScorecard(int venueCount, double alpha, double fillRatePrior, long markoutHorizonNanos) -
Method Summary
Modifier and TypeMethodDescriptiondoubleexpectedHiddenShares(int venue) EWMA shares found per dark probe (0 before any probe).longfilled(int venue) doublefillRate(int venue) EWMA fill probability; the optimistic prior before any data.doubleThe before-any-data prior (also what unregistered venues score as).longFill markouts matured across all venues — the wiring canary: zero while fills accrue meansonMid(double, long)is not being fed and the router's adverse-selection term is silently disabled.doublemeasuredLatencyNanos(int venue) EWMA measured response latency in nanos (0 before any data).voidonDarkProbe(int venue, long sharesFilled) A dark probe's outcome: how many shares it actually found (0 is a real observation — an empty pool teaches as much as a full one).voidonFill(int venue, long responseNanos) A marketable child filled (fully or partially counts as a fill).voidonFill(int venue, long responseNanos, boolean buy, double midAtFill, long timestampNanos) A fill with the context that arms its markout: direction, the mid at fill time, and the fill timestamp.voidonMid(double mid, long timestampNanos) Mid update for the card's one symbol (see the class doc): matures every pending fill markout whose horizon has elapsed.voidonMiss(int venue, long responseNanos) A marketable child that came back unfilled (faded, rejected, expired).doublepostFillMarkout(int venue) EWMA post-fill markout in price units — positive means the mid kept moving your way after fills at this venue; negative means it reverted: you crossed the spread into informed or stale flow, the per-share costAdaptiveSorprices as adverse selection. 0 before any matured markout.longprobes(int venue) voidRestores the card; pending fill markouts (intraday) reset.longsent(int venue) intvoidwriteState(DataOutput out) Persists the learned venue quality — fill rates, measured latencies, dark-probe estimates and fill markouts are exactly what a router should not have to relearn every morning.
-
Field Details
-
PENDING_RING
public static final int PENDING_RINGPending fill-markout slots per venue (bursts deeper overwrite oldest).- See Also:
-
-
Constructor Details
-
VenueScorecard
public VenueScorecard(int venueCount, double alpha, double fillRatePrior, long markoutHorizonNanos) - Parameters:
venueCount- number of venues (dense indices)alpha- EWMA weight per event, e.g. 0.05fillRatePrior- fill rate assumed before any data, e.g. 0.95markoutHorizonNanos- how long after a fill the markout is read, e.g. 100ms =100_000_000L
-
VenueScorecard
public VenueScorecard(int venueCount, double alpha, double fillRatePrior) 100 ms markout horizon. -
VenueScorecard
public VenueScorecard(int venueCount) 5% event weight, 0.95 prior, 100 ms markout horizon.
-
-
Method Details
-
onFill
public void onFill(int venue, long responseNanos) A marketable child filled (fully or partially counts as a fill). -
onMiss
public void onMiss(int venue, long responseNanos) A marketable child that came back unfilled (faded, rejected, expired). -
onFill
public void onFill(int venue, long responseNanos, boolean buy, double midAtFill, long timestampNanos) A fill with the context that arms its markout: direction, the mid at fill time, and the fill timestamp. Feed mids viaonMid(double, long)and the move one horizon later is attributed to this venue. A NaN mid still counts the fill but can never start a markout (maturing against NaN would poison the EWMA and silently distort routing). -
onMid
public void onMid(double mid, long timestampNanos) Mid update for the card's one symbol (see the class doc): matures every pending fill markout whose horizon has elapsed. Non-finite mids are ignored — one Inf sentinel maturing a slot would seed the EWMA at ±Inf and the next blend would NaN it forever, silently disabling the router's adverse-selection term. The common no-pending case is a single compare. -
onDarkProbe
public void onDarkProbe(int venue, long sharesFilled) A dark probe's outcome: how many shares it actually found (0 is a real observation — an empty pool teaches as much as a full one). The estimate seeds from the first probe rather than ramping from 0, so one good probe doesn't collapse subsequent probe sizes. -
fillRate
public double fillRate(int venue) EWMA fill probability; the optimistic prior before any data. -
fillRatePrior
public double fillRatePrior()The before-any-data prior (also what unregistered venues score as). -
measuredLatencyNanos
public double measuredLatencyNanos(int venue) EWMA measured response latency in nanos (0 before any data). -
postFillMarkout
public double postFillMarkout(int venue) EWMA post-fill markout in price units — positive means the mid kept moving your way after fills at this venue; negative means it reverted: you crossed the spread into informed or stale flow, the per-share costAdaptiveSorprices as adverse selection. 0 before any matured markout. -
maturedFillMarkouts
public long maturedFillMarkouts()Fill markouts matured across all venues — the wiring canary: zero while fills accrue meansonMid(double, long)is not being fed and the router's adverse-selection term is silently disabled. -
sent
public long sent(int venue) -
filled
public long filled(int venue) -
probes
public long probes(int venue) -
venueCount
public int venueCount() -
writeState
Persists the learned venue quality — fill rates, measured latencies, dark-probe estimates and fill markouts are exactly what a router should not have to relearn every morning. Format version 2 (version 1, from before the markout existed, is still readable). Seepersist.Checkpoint.- Throws:
IOException
-
readState
Restores the card; pending fill markouts (intraday) reset. Reads both format versions: a v1 checkpoint restores everything it has and leaves the markout state cold. Throws on a venue-count mismatch or an unknown version.- Throws:
IOException
-