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>
59 lines
2.2 KiB
Plaintext
59 lines
2.2 KiB
Plaintext
// 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;
|
||
}
|
||
}
|
||
}
|