Files
foxhunt/crates/ml/tests/behavioral/oracle.rs
jgrusewski baf971ba54 diag(rl): emit v9 eval_warmup state to JSONL + cleanup lints
Diag: surfaces `risk_stack.eval_warmup.{remaining,active,blend,
floor_*,target_*}` so the v9 defensive-warmup window is observable
in diag.jsonl. `remaining` is the counter; `blend` is the
defensive-vs-normal mix coefficient (1.0 = full defensive, 0.0 =
normal); `floor_*` reflect the LIVE override values (read AFTER the
warmup kernel ran). Pre-warmup the kernel is a no-op (remaining=-1),
so v9 train-phase diag is bit-identical to v8.

Cleanup: tightens unreachable_pub items in tests/behavioral/* and
tests/sp5_producer_unit_tests.rs (pub → pub(crate)), removes
unused_mut on 6 sp5 scratch buffers, renames unused `step` loop
counter in alpha_baseline example, and explicitly discards an
intentionally-no-op `Command::assert` in cli_integration_test.
Reduces lint count by ~25; remaining 3 dead_code warnings flag
SP15 Phase 2A behavioral scaffolding (Phase 2B never landed —
deliberate signal, not noise).

Pre-existing pearl per feedback_no_hiding: do NOT suppress these
with #[allow]; the warnings ARE the design call surface.
2026-05-31 02:12:04 +02:00

81 lines
2.8 KiB
Rust
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.
//! SP15 Phase 2A — oracle policies for behavioral test harness.
//! Each oracle is a known-correct action sequence for a given synthetic
//! market type; tests assert the trained policy approaches the oracle.
use ml::cuda_pipeline::lob_bar::LobBar;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum MagBucket { Quarter, Half, Full }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum OracleAction {
Hold,
Long(MagBucket),
Short(MagBucket),
Flat,
}
/// Oracle for flat markets: always Hold.
pub(crate) fn flat_market_oracle(bars: &[LobBar]) -> Vec<OracleAction> {
vec![OracleAction::Hold; bars.len()]
}
/// Oracle for drift markets: take direction-of-trend, mag = Half.
pub(crate) fn drift_market_oracle(bars: &[LobBar]) -> Vec<OracleAction> {
let mut actions = Vec::with_capacity(bars.len());
actions.push(OracleAction::Hold); // first bar: no prior
for w in bars.windows(2) {
let action = if w[1].price > w[0].price + 0.05 {
OracleAction::Long(MagBucket::Half)
} else if w[1].price < w[0].price - 0.05 {
OracleAction::Short(MagBucket::Half)
} else {
OracleAction::Hold
};
actions.push(action);
}
actions
}
/// Oracle for OU markets: reverse at ±2σ extremes.
pub(crate) fn ou_market_oracle(bars: &[LobBar], mu: f32, sigma: f32) -> Vec<OracleAction> {
bars.iter().map(|b| {
let z = (b.price - mu) / sigma.max(1e-6);
if z > 2.0 { OracleAction::Short(MagBucket::Half) }
else if z < -2.0 { OracleAction::Long(MagBucket::Half) }
else { OracleAction::Hold }
}).collect()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::synthetic_markets::*;
#[test]
fn flat_oracle_all_hold() {
let bars = flat_market(100, 0.1, 0.25, 42);
let actions = flat_market_oracle(&bars);
assert_eq!(actions.len(), 100);
assert!(actions.iter().all(|a| *a == OracleAction::Hold));
}
#[test]
fn drift_oracle_takes_uptrend() {
let bars = drift_market(1000, 0.5, 0.1, 0.25, 42);
let actions = drift_market_oracle(&bars);
let long_count = actions.iter().filter(|a| matches!(a, OracleAction::Long(_))).count();
// Strong uptrend → most actions should be Long
assert!(long_count > 700, "drift_market_oracle Long count = {}, expected > 700", long_count);
}
#[test]
fn ou_oracle_reverses_at_extremes() {
let bars = ou_market(1000, 0.05, 1.0, 4500.0, 0.25, 42);
let actions = ou_market_oracle(&bars, 4500.0, 1.0);
// OU oracle should produce SOME reversion actions (not all Hold)
let action_count = actions.iter().filter(|a| !matches!(a, OracleAction::Hold)).count();
assert!(action_count > 0, "OU oracle produced zero non-Hold actions");
}
}