Files
foxhunt/crates/ml-backtesting/cuda/book_update.cu
jgrusewski dc8c37e11e feat(ml-backtesting): ATR-EMA on mid-price in book_update_apply_snapshot
Per-event Wiener-α=0.4 EMA on |Δmid| with first-observation bootstrap.
Floor source for the SL/trail-distance controller (spec §6). Thread 0
of the broadcast-snapshot kernel handles the update per backtest;
threads 1..9 still handle the 10 level writes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 23:49:02 +02:00

59 lines
2.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// book_update.cu — MBP-10 snapshot apply.
//
// Replaces the per-block book state with the broadcast snapshot. The
// full top-10 image overwrites the previous state (MBP-10 semantics).
// One block per backtest; thread tid handles one of 10 levels per side
// (10 threads used out of 32 in the warp; remainder idle).
//
// Per feedback_no_atomicadd.md: no atomics — single-writer per level.
// Per spec §2: same snapshot broadcast to every backtest in v1.
#include "lob_state.cuh"
// Books are laid out [n_backtests, 4 fields × 10 levels].
// Field order: bid_px, bid_sz, ask_px, ask_sz (one contiguous Book per backtest).
extern "C" __global__ void book_update_apply_snapshot(
const float* __restrict__ bid_px_in, // [10] — broadcast
const float* __restrict__ bid_sz_in, // [10]
const float* __restrict__ ask_px_in, // [10]
const float* __restrict__ ask_sz_in, // [10]
Book* __restrict__ books_out, // [n_backtests]
float* __restrict__ prev_mid, // [n_backtests]
float* __restrict__ atr_mid_ema, // [n_backtests]
int n_backtests
) {
int b = blockIdx.x;
int tid = threadIdx.x;
if (b >= n_backtests) return;
if (tid < 10) {
Book& bk = books_out[b];
bk.bid_px[tid] = bid_px_in[tid];
bk.bid_sz[tid] = bid_sz_in[tid];
bk.ask_px[tid] = ask_px_in[tid];
bk.ask_sz[tid] = ask_sz_in[tid];
}
// Thread 0 handles per-backtest ATR-EMA update against the broadcast mid.
if (tid == 0) {
const float mid = 0.5f * (bid_px_in[0] + ask_px_in[0]);
const float prev = prev_mid[b];
if (prev == 0.0f) {
// First-observation bootstrap (pearl_first_observation_bootstrap).
prev_mid[b] = mid;
// atr_mid_ema stays 0 until event 2.
} else {
const float delta = fabsf(mid - prev);
const float ema = atr_mid_ema[b];
if (ema == 0.0f) {
// First non-zero delta: replace directly.
atr_mid_ema[b] = delta;
} else {
// Wiener-α=0.4 EMA (pearl_wiener_alpha_floor_for_nonstationary).
atr_mid_ema[b] = 0.4f * delta + 0.6f * ema;
}
prev_mid[b] = mid;
}
}
}