dau_core.temporal¶
Golden models for the temporal-finance hero workflow.
The fused workflow this file is the CPU reference for:
- quotes ─┐
├─> backward as-of ─> midpoint/spread/sign ─┐
- trades ─┘ ├─> time/vol/$ bars
└─> rolling features
Everything here operates on the encoded integer domain the hardware sees —
symbol ids are int32 dictionary codes, timestamps are int64, prices/sizes are
int64 fixed-point (the host quantizes at a chosen scale before staging, exactly
as dau_polars.ohlcv does with its micro-unit SCALE). The models are
therefore scale-agnostic integer arithmetic: a caller that quantizes price and
size at scales Sp and Ss gets dollar volume in Sp*Ss units and must
express dollar-bar thresholds in the same units. Division is deferred (Q100
discipline): bars and rolling windows emit exact integer accumulators
(sum / sum-of-squares / count) and the host divides once, so every value on the
wire is exact.
State is bounded and per-symbol: the as-of tile holds one current quote per
symbol partition; a bar tile holds one open bar; a rolling tile holds one
window. The pre-sort precondition (both streams ordered by (symbol_id, time))
is the same one the sorted-scan tiles already require — the host sorts, or the
range-partitioner + sorter path does.
These are semantic references, ahead of the HDL. The int64 timestamp / sum
tiles and the as-of / windowed-stat tiles byte-compare against them.
Attributes¶
Classes¶
The per-row derived features of one aligned market row. |
|
One closed bar over aligned market rows. OHLC on price, plus exact |
|
The exact integer accumulators of one full rolling window — mean and |
|
A deterministic (seeded) quote/trade fixture in the encoded domain, both |
Functions¶
|
Backward as-of join: each trade attached to the most recent quote for |
|
Drop the as-of misses — the aligned market rows the downstream fused |
|
|
|
|
|
The stateless quote-rule trade sign: |
|
|
|
|
|
Alias of |
|
Derive the fused per-row market features for a stream of aligned market |
|
|
|
Fixed-width time bars: trades bucket by |
|
Threshold-clock bars: accumulate |
|
Volume bars: close when cumulative traded size reaches |
|
Dollar bars: close when cumulative notional ( |
|
Imbalance bars: close when |
|
|
|
Per-symbol rolling sum of the last |
|
Per-symbol rolling minimum of the last |
|
Per-symbol rolling maximum of the last |
|
Per-symbol rolling |
|
Mean from a rolling moment. |
|
Variance from a rolling moment ( |
|
Sample standard deviation from a rolling moment. |
|
Per-symbol exponentially weighted moving average, non-adjusted recursion |
|
Per-symbol first difference ( |
|
Per-symbol gap flags: |
|
Generate a deterministic quote/trade fixture: per symbol, a random-walk |
Module Contents¶
- dau_core.temporal._T¶
- dau_core.temporal.QuoteRow¶
- dau_core.temporal.TradeRow¶
- dau_core.temporal.MarketRow¶
- dau_core.temporal.asof_backward(trades: collections.abc.Iterable[TradeRow], quotes: collections.abc.Iterable[QuoteRow], *, tolerance: int | None = None) list[MarketRow | None][source]¶
Backward as-of join: each trade attached to the most recent quote for the same symbol whose
quote_time <= trade_time(and, whentoleranceis set,trade_time - quote_time <= tolerance). Emits one entry per input trade, in input order — a matched(symbol_id, time, price, size, bid, ask)market row, orNonewhen no quote qualifies (the miss is a typed residue;matched_rows()drops them).Matches
polars.DataFrame.join_asof(strategy="backward", by="symbol", tolerance=...): on equal timestamps the last qualifying quote wins. Both streams must be pre-sorted by(symbol_id, time). The tile holds one current quote per symbol partition and advances it monotonically — bounded state, one pass.
- dau_core.temporal.matched_rows(aligned: collections.abc.Iterable[MarketRow | None]) list[MarketRow][source]¶
Drop the as-of misses — the aligned market rows the downstream fused stages consume.
- dau_core.temporal.midpoint(bid: int, ask: int) int[source]¶
(bid + ask) // 2(floor). The quote midpoint in the price scale.
- dau_core.temporal.trade_sign(price: int, bid: int, ask: int) int[source]¶
The stateless quote-rule trade sign:
+1above the midpoint,-1below,0at it. (The tick-test tie-break needs prior state and is a later windowed variant.)
- dau_core.temporal.signed_volume(price: int, size: int, bid: int, ask: int) int[source]¶
trade_sign * size— size credited to the initiating side.
- dau_core.temporal.dollar_volume(price: int, size: int) int[source]¶
price * size— notional inprice_scale * size_scaleunits (the VWAP numerator; exact, host rescales).
- dau_core.temporal.vwap_numerator(price: int, size: int) int[source]¶
Alias of
dollar_volume(): VWAP =sum(price*size) / sum(size), accumulated over a bar and divided once by the host.
- class dau_core.temporal.MarketFeatures[source]¶
The per-row derived features of one aligned market row.
- symbol_id: int¶
- time: int¶
- price: int¶
- size: int¶
- midpoint: int¶
- spread: int¶
- trade_sign: int¶
- signed_volume: int¶
- dollar_volume: int¶
- dau_core.temporal.market_features(rows: collections.abc.Iterable[MarketRow]) list[MarketFeatures][source]¶
Derive the fused per-row market features for a stream of aligned market rows (the
derivestage of the workflow plan).
- class dau_core.temporal.TemporalBar[source]¶
One closed bar over aligned market rows. OHLC on price, plus exact integer accumulators (volume, dollar/vwap-numerator, signed volume, count) so VWAP and averages divide once on the host —
int64on the wire (seeINT64_MAX).open_time/close_timecarry the ordering keys for associative cross-batch merge.- symbol_id: int¶
- open: int¶
- high: int¶
- low: int¶
- close: int¶
- volume: int¶
- dollar: int¶
- signed_volume: int¶
- count: int¶
- open_time: int¶
- close_time: int¶
- _extend(time: int, price: int, size: int, signed: int) TemporalBar[source]¶
- dau_core.temporal._open_bar(symbol_id: int, time: int, price: int, size: int, signed: int) TemporalBar[source]¶
- dau_core.temporal.time_bars(rows: collections.abc.Iterable[MarketRow], *, bar_width: int) list[TemporalBar][source]¶
Fixed-width time bars: trades bucket by
time // bar_width; a bar spans one(symbol_id, bucket)and closes when the bucket or symbol changes. Rows must be pre-sorted by(symbol_id, time). Matchesgroup_by_dynamic(every=bar_width, closed="left")per symbol.
- dau_core.temporal._accumulator_bars(rows: collections.abc.Iterable[MarketRow], *, threshold: int, metric: str) list[TemporalBar][source]¶
Threshold-clock bars: accumulate
metricper symbol and close the bar on the trade that reachesthreshold(the crossing trade is included — the López de Prado convention). A symbol change closes the open bar. Emits a trailing partial bar at end-of-stream.
- dau_core.temporal.volume_bars(rows: collections.abc.Iterable[MarketRow], *, threshold: int) list[TemporalBar][source]¶
Volume bars: close when cumulative traded size reaches
threshold.
- dau_core.temporal.dollar_bars(rows: collections.abc.Iterable[MarketRow], *, threshold: int) list[TemporalBar][source]¶
Dollar bars: close when cumulative notional (
sum price*size) reachesthreshold(same units asdollar_volume()).
- dau_core.temporal.imbalance_bars(rows: collections.abc.Iterable[MarketRow], *, threshold: int) list[TemporalBar][source]¶
Imbalance bars: close when
|cumulative signed volume|reachesthreshold— a bar per unit of net directional flow.
- dau_core.temporal._rolling(values: collections.abc.Iterable[tuple[int, int]], *, window: int, reduce: collections.abc.Callable[[list[int]], _T]) list[_T | None][source]¶
- dau_core.temporal.rolling_sum(values: collections.abc.Iterable[tuple[int, int]], *, window: int) list[int | None][source]¶
Per-symbol rolling sum of the last
windowvalues (exact int).
- dau_core.temporal.rolling_min(values: collections.abc.Iterable[tuple[int, int]], *, window: int) list[int | None][source]¶
Per-symbol rolling minimum of the last
windowvalues.
- dau_core.temporal.rolling_max(values: collections.abc.Iterable[tuple[int, int]], *, window: int) list[int | None][source]¶
Per-symbol rolling maximum of the last
windowvalues.
- class dau_core.temporal.RollingMoment[source]¶
The exact integer accumulators of one full rolling window — mean and variance divide once on the host (
moment_mean(),moment_var()).- count: int¶
- total: int¶
- total_sq: int¶
- dau_core.temporal.rolling_moments(values: collections.abc.Iterable[tuple[int, int]], *, window: int) list[RollingMoment | None][source]¶
Per-symbol rolling
(count, sum, sum_of_squares)over the lastwindowvalues — the deferred-division form of rolling mean/variance.REFUSES a window whose sum of squares leaves a signed 64-bit accumulator. That is the tile’s arithmetic precondition, and it binds inside the int32 domain:
(2**31-1)**2is already2**61, so a full-range int32 column overflowssum_sqfrom window 3. The tile cannot check it — it sees one row at a time and has no bound to compare against — and it wraps silently into a wrong variance rather than erroring. Python integers do not wrap, so a golden that computed the exact value would DISAGREE with the hardware over exactly the inputs the contract excludes, and the bench comparing the two would be the only thing that ever noticed. Raising instead keeps the reference and the datapath from ever quietly parting company: inside the precondition they are equal, and outside it neither claims an answer.The proof properly lives further upstream — dau-polars refuses to route a rolling scan whose value column declares no
magnitude_bits— so this is a backstop for a direct caller, not the primary check.
- dau_core.temporal.moment_mean(moment: RollingMoment) float[source]¶
Mean from a rolling moment.
- dau_core.temporal.moment_var(moment: RollingMoment, *, ddof: int = 1) float[source]¶
Variance from a rolling moment (
ddof=1sample variance, matchingpolars.rolling_var). Raises on an under-determined window.The numerator
count*sum_sq - sum*sumis formed in exact integers before the single float divide — dividingsum*sumfirst (float) would cancel the variance away at fixed-point magnitudes (e.g. three consecutive values near1e9).
- dau_core.temporal.moment_std(moment: RollingMoment, *, ddof: int = 1) float[source]¶
Sample standard deviation from a rolling moment.
The root of
moment_var(), and deliberately defined in terms of it rather than independently: polars’rolling_stdis the root of itsrolling_var, so any other formulation would disagree with the reference in the last place for no benefit.On device this is where the divide and sqrt tiles land – variance divides before it roots – which is why the numerator stays exact integers right up to the single divide.
- dau_core.temporal.ewma(values: collections.abc.Iterable[tuple[int, int]], *, alpha: float) list[float][source]¶
Per-symbol exponentially weighted moving average, non-adjusted recursion (
e[0] = x[0];e[i] = alpha*x[i] + (1-alpha)*e[i-1]) — matchespl.col(x).ewm_mean(alpha=alpha, adjust=False).over("symbol"). Float: the reference real-valued semantics the fixed-point tile approximates under its declared error budget.
- dau_core.temporal.deltas(values: collections.abc.Iterable[tuple[int, int]]) list[int | None][source]¶
Per-symbol first difference (
value[i] - value[i-1];Nonefor the first row of each symbol) — matchespl.col(x).diff().over("symbol").
- dau_core.temporal.gaps(times: collections.abc.Iterable[tuple[int, int]], *, max_gap: int) list[bool][source]¶
Per-symbol gap flags:
Truewheretime[i] - time[i-1] > max_gap(the first row of each symbol is never a gap).
- class dau_core.temporal.MarketStream[source]¶
A deterministic (seeded) quote/trade fixture in the encoded domain, both streams sorted by
(symbol_id, time).- quotes: tuple[QuoteRow, ...]¶
- trades: tuple[TradeRow, ...]¶
- dau_core.temporal.generate_market_stream(*, seed: int, num_symbols: int = 4, quotes_per_symbol: int = 24, trades_per_symbol: int = 40, price_scale: int = 1000000) MarketStream[source]¶
Generate a deterministic quote/trade fixture: per symbol, a random-walk two-sided quote (micro-dollar prices) and interleaved trades in integer share sizes priced near the prevailing midpoint — so
dollar_volumeaccumulators stay comfortably in int64. Sameseed⇒ byte-identical output (replay determinism). Uses only the stdlibrandom— zero-dependency, like the rest of dau-core.Both paths are exercised by construction: one trade per symbol is placed just before that symbol’s first quote, so
asof_backward()always produces at least one miss as well as matches.