refactor(alpha_baseline): rename, drop conditionals, strip dead paths
Rename binary alpha_compose_backtest → alpha_baseline and remove the boolean flags whose features are now mandatory: --c51 (always C51 distributional Q) --temporal (always Mamba2 temporal encoder) --isv-continual (controller always fires per eval episode) --regime-scale (vol-EMA regime defense always on) --pruned-actions (FALSIFIED 2026-05-15 per pearl_action_pruning_falsified) Every dependent code path was stripped, not just gated: - Linear-Q kernels (lq_fwd, lq_grad, munch_kernel) and their cubin loads are gone — C51 is the only Q-network. - Single-env push_kernel / h_store_kernel loads removed; the backtest has been batched-parallel-env since T14 and only the _batched variants are called here. (The smoke binary still uses single-env variants because one env per episode is its job.) - Dead transition buffers removed: states_dev, next_states_dev, actions_dev, rewards_dev, dones_dev, q_current_dev, q_next_dev, target_dev, single_state_dev, single_q_dev, probs_current_dev, probs_next_dev, m_dev, single_probs_dev, single-env state_pinned, action_pinned, window_tensor, h_enriched_buf_dev. - Dead constants and helpers: PRUNED_ACTIONS, N_WEIGHTS, N_BIASES, epsilon_greedy, epsilon_greedy_gated. End-to-end verification on the existing Q1 fxcache (rebuild was OOM locally; full multi-quarter validation is the next phase): cost=0.0000 best τ=0.250 Sharpe_ann=+36.83 win=0.984 trades/ep=83.3 cost=0.0625 best τ=0.250 Sharpe_ann=+38.53 win=0.996 trades/ep=83.2 cost=0.1250 best τ=0.250 Sharpe_ann=+38.37 win=0.994 trades/ep=83.3 cost=0.2500 best τ=0.250 Sharpe_ann=+34.24 win=0.990 trades/ep=85.6 cost=0.5000 best τ=0.250 Sharpe_ann=+31.83 win=0.946 trades/ep=84.8 Numbers track the prior T16-flag config (within stochastic noise), confirming the conditional-stripping was a pure simplification — no behavioral change, just a smaller, honester binary. Also updated: - scripts/alpha_pipeline.sh — A/B conditions collapse to fixed-cost vs cost-randomized training (the only opt-in left). - scripts/walk_forward_cv.sh — drop legacy flags, pass --window-k only. - crates/ml/src/env/loaders.rs — module doc-comment updated. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -148,18 +148,12 @@ use ml::env::execution_env::{
|
||||
};
|
||||
|
||||
const STATE_DIM: usize = 10;
|
||||
const N_WEIGHTS: usize = N_ACTIONS * STATE_DIM;
|
||||
const N_BIASES: usize = N_ACTIONS;
|
||||
|
||||
/// Action allow-list for the pruning experiment. Same shape as the smoke
|
||||
/// binary: Q-net is unchanged (9 outputs), only the selector restricts.
|
||||
const PRUNED_ACTIONS: [u8; 4] = [0, 1, 4, 7]; // Wait, BuyMarket, SellMarket, FlatMarket
|
||||
const FULL_ACTIONS: [u8; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(
|
||||
name = "alpha_compose_backtest",
|
||||
about = "Phase E.3 Task 23 — composition backtest with cost sweep"
|
||||
name = "alpha_baseline",
|
||||
about = "Alpha baseline — trained Mamba2 + C51 + ISV-continual + vol-regime defense"
|
||||
)]
|
||||
struct Cli {
|
||||
#[arg(long)]
|
||||
@@ -247,15 +241,9 @@ struct Cli {
|
||||
target_update_every: usize,
|
||||
#[arg(long, default_value_t = 1.0)]
|
||||
grad_clip: f32,
|
||||
/// Restrict action selection to {Wait, BuyMarket, SellMarket, FlatMarket}.
|
||||
/// Applies during BOTH training and eval. **FALSIFIED 2026-05-15** —
|
||||
/// kept for reproducibility (see `pearl_action_pruning_falsified`).
|
||||
#[arg(long, default_value_t = false)]
|
||||
pruned_actions: bool,
|
||||
/// Use C51 distributional Q-network (Phase E.3 follow-up). Same
|
||||
/// semantics as the alpha_dqn_h600_smoke `--c51` flag.
|
||||
#[arg(long, default_value_t = false)]
|
||||
c51: bool,
|
||||
// pruned_actions — FALSIFIED 2026-05-15, hardcoded false.
|
||||
// c51, temporal, isv_continual, regime_scale — always on now,
|
||||
// removed from CLI surface.
|
||||
/// C51 atom-support lower bound (normalized reward units).
|
||||
#[arg(long, default_value_t = -10.0)]
|
||||
c51_vmin: f32,
|
||||
@@ -269,35 +257,14 @@ struct Cli {
|
||||
/// ±0.125-tick. Phase E.3 Path 3 follow-up.
|
||||
#[arg(long, default_value_t = false)]
|
||||
real_spread: bool,
|
||||
/// Phase E.4.A: enable the temporal-encoder stack (sliding window +
|
||||
/// Mamba2 + C51).
|
||||
#[arg(long, default_value_t = false)]
|
||||
temporal: bool,
|
||||
/// Temporal-encoder window length (number of historical snapshots
|
||||
/// fed to Mamba2 per step).
|
||||
#[arg(long, default_value_t = 16)]
|
||||
window_k: usize,
|
||||
#[arg(long, default_value_t = 32)]
|
||||
mamba2_hidden_dim: usize,
|
||||
#[arg(long, default_value_t = 16)]
|
||||
mamba2_state_dim: usize,
|
||||
/// Phase E.4.A Pillar B: fire stacker-threshold controller at the
|
||||
/// end of EVERY eval episode (not just training). Slot 543
|
||||
/// (threshold) adapts during the 2D sweep based on observed trade
|
||||
/// rate / Sharpe.
|
||||
#[arg(long, default_value_t = false)]
|
||||
isv_continual: bool,
|
||||
/// Phase E.4.A T16: enable vol-EMA regime detection + pre-emptive
|
||||
/// Kelly attenuation. When set:
|
||||
/// - per inference step, `alpha_regime_vol_update_kernel` reads
|
||||
/// the parallel envs' current/previous mids and maintains
|
||||
/// ISV[549]=vol_ema (Wiener-α with 0.4 floor + Pearl A
|
||||
/// bootstrap) and ISV[550]=vol_ref (slow tracker, β=0.005);
|
||||
/// - per eval episode (requires `--isv-continual`), the existing
|
||||
/// stacker controller multiplies its Sharpe-reactive Kelly
|
||||
/// output by `clamp(vol_ref/vol_ema, 0.25, 1.0)` so vol spikes
|
||||
/// cut Kelly *before* losses materialise.
|
||||
/// Off by default to keep the T10 baseline comparable.
|
||||
#[arg(long, default_value_t = false)]
|
||||
regime_scale: bool,
|
||||
/// Phase E.4.A.T15.batched (2026-05-15): parallel envs per training
|
||||
/// "epoch". n_train_episodes / n_train_par epochs total. Each epoch
|
||||
/// runs N_par envs in lockstep H steps + ONE batched C51 update at
|
||||
@@ -330,38 +297,9 @@ impl SmokeRng {
|
||||
}
|
||||
}
|
||||
|
||||
fn epsilon_greedy(q: &[f32], eps: f32, allowed: &[u8], rng: &mut SmokeRng) -> u8 {
|
||||
if rng.next_f32() < eps {
|
||||
allowed[(rng.next_u64() as usize) % allowed.len()]
|
||||
} else {
|
||||
let mut best_a: u8 = allowed[0];
|
||||
let mut best_v: f32 = q[allowed[0] as usize];
|
||||
for &a in &allowed[1..] {
|
||||
let v = q[a as usize];
|
||||
if v > best_v {
|
||||
best_v = v;
|
||||
best_a = a;
|
||||
}
|
||||
}
|
||||
best_a
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase E.3 confidence-gated ε-greedy. If `alpha_confidence < threshold`,
|
||||
/// force action=0 (Wait). Otherwise standard ε-greedy over `allowed`.
|
||||
fn epsilon_greedy_gated(
|
||||
q: &[f32],
|
||||
alpha_confidence: f32,
|
||||
threshold: f32,
|
||||
eps: f32,
|
||||
allowed: &[u8],
|
||||
rng: &mut SmokeRng,
|
||||
) -> u8 {
|
||||
if alpha_confidence < threshold {
|
||||
return 0;
|
||||
}
|
||||
epsilon_greedy(q, eps, allowed, rng)
|
||||
}
|
||||
// The linear-Q ε-greedy + confidence-gated ε-greedy helpers used by the
|
||||
// legacy scalar Q path were deleted with the rest of that path. All
|
||||
// action selection now happens on-GPU via `alpha_c51_thompson_select`.
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
struct CostBin {
|
||||
@@ -389,35 +327,24 @@ fn main() -> Result<()> {
|
||||
)
|
||||
.init();
|
||||
let cli = Cli::parse();
|
||||
info!("Phase E.3 Task 23 — composition backtest starting");
|
||||
let allowed_actions: &[u8] = if cli.pruned_actions {
|
||||
info!(" ACTION SET: pruned ({} actions: Wait, BuyMarket, SellMarket, FlatMarket)", PRUNED_ACTIONS.len());
|
||||
&PRUNED_ACTIONS
|
||||
} else {
|
||||
info!(" ACTION SET: full ({} actions)", FULL_ACTIONS.len());
|
||||
&FULL_ACTIONS
|
||||
};
|
||||
info!("Alpha baseline — trained Mamba2 + C51 + ISV-continual + vol-regime defense");
|
||||
info!(" ACTION SET: full ({} actions)", FULL_ACTIONS.len());
|
||||
let allowed_actions: &[u8] = &FULL_ACTIONS;
|
||||
|
||||
let ctx = CudaContext::new(0).context("CUDA init")?;
|
||||
let stream = ctx.default_stream();
|
||||
|
||||
// --- Load cubins ---
|
||||
// alpha_linear_q.cubin provides two kernels we still need: the
|
||||
// in-place clip and the SGD step (both used on the C51 head's
|
||||
// dW / dB after gradients). The forward/grad linear-Q kernels are
|
||||
// unused (C51 is the only Q-network in this binary).
|
||||
let lq_module = ctx
|
||||
.load_cubin(ml::cuda_pipeline::alpha_kernels::ALPHA_LINEAR_Q_CUBIN.to_vec())
|
||||
.context("alpha_linear_q cubin")?;
|
||||
let lq_fwd = lq_module.load_function("alpha_linear_q_forward_kernel")?;
|
||||
let lq_grad = lq_module.load_function("alpha_linear_q_grad_kernel")?;
|
||||
let lq_sgd = lq_module.load_function("alpha_linear_q_sgd_step_kernel")?;
|
||||
let lq_clip = lq_module.load_function("alpha_clip_inplace_kernel")?;
|
||||
let munch_cubin: Vec<u8> = std::fs::read(concat!(
|
||||
env!("OUT_DIR"),
|
||||
"/alpha_munchausen_target.cubin"
|
||||
))?;
|
||||
let munch_module = ctx.load_cubin(munch_cubin)?;
|
||||
let munch_kernel =
|
||||
munch_module.load_function("alpha_munchausen_target_kernel")?;
|
||||
|
||||
// Phase E.3 follow-up: C51 kernels (always loaded; only used when --c51).
|
||||
let c51_module = ctx
|
||||
.load_cubin(ml::cuda_pipeline::alpha_kernels::ALPHA_C51_CUBIN.to_vec())
|
||||
.context("alpha_c51 cubin")?;
|
||||
@@ -425,12 +352,9 @@ fn main() -> Result<()> {
|
||||
let c51_project_kernel = c51_module.load_function("alpha_c51_project_kernel")?;
|
||||
let c51_grad_kernel = c51_module.load_function("alpha_c51_grad_kernel")?;
|
||||
let c51_thompson_kernel = c51_module.load_function("alpha_c51_thompson_select_kernel")?;
|
||||
// Phase E.4.A.6: window push kernel (used in --temporal path).
|
||||
let push_module = ctx
|
||||
.load_cubin(ml::cuda_pipeline::alpha_kernels::ALPHA_WINDOW_PUSH_CUBIN.to_vec())
|
||||
.context("alpha_window_push cubin")?;
|
||||
let push_kernel = push_module.load_function("alpha_window_push_kernel")?;
|
||||
let h_store_kernel = push_module.load_function("alpha_h_enriched_store_kernel")?;
|
||||
let push_batched_kernel = push_module.load_function("alpha_window_push_batched_kernel")?;
|
||||
let h_store_batched_kernel = push_module.load_function("alpha_h_enriched_store_batched_kernel")?;
|
||||
// Phase E.4.A.7 controller (used in --isv-continual eval path).
|
||||
@@ -443,19 +367,15 @@ fn main() -> Result<()> {
|
||||
let c51_v_min = cli.c51_vmin;
|
||||
let c51_v_max = cli.c51_vmax;
|
||||
let c51_delta_z = (c51_v_max - c51_v_min) / (c51_n_atoms.saturating_sub(1).max(1) as f32);
|
||||
if cli.c51 {
|
||||
info!(
|
||||
" Q-network: C51 ({} atoms, [{:.2}, {:.2}], Δz={:.4})",
|
||||
c51_n_atoms, c51_v_min, c51_v_max, c51_delta_z
|
||||
);
|
||||
if c51_n_atoms == 0 || c51_n_atoms > 64 {
|
||||
anyhow::bail!("--c51-n-atoms must be in (0, 64]");
|
||||
}
|
||||
if c51_v_max <= c51_v_min {
|
||||
anyhow::bail!("--c51-vmax must exceed --c51-vmin");
|
||||
}
|
||||
} else {
|
||||
info!(" Q-network: linear scalar (9 outputs)");
|
||||
info!(
|
||||
" Q-network: C51 ({} atoms, [{:.2}, {:.2}], Δz={:.4})",
|
||||
c51_n_atoms, c51_v_min, c51_v_max, c51_delta_z
|
||||
);
|
||||
if c51_n_atoms == 0 || c51_n_atoms > 64 {
|
||||
anyhow::bail!("--c51-n-atoms must be in (0, 64]");
|
||||
}
|
||||
if c51_v_max <= c51_v_min {
|
||||
anyhow::bail!("--c51-vmax must exceed --c51-vmin");
|
||||
}
|
||||
|
||||
// --- Load env data ---
|
||||
@@ -500,18 +420,10 @@ fn main() -> Result<()> {
|
||||
cli.seed,
|
||||
);
|
||||
|
||||
// --- Initialize Q-network ---
|
||||
let c51_input_dim: usize = if cli.c51 && cli.temporal {
|
||||
cli.mamba2_hidden_dim
|
||||
} else {
|
||||
STATE_DIM
|
||||
};
|
||||
let n_weights_eff: usize = if cli.c51 {
|
||||
N_ACTIONS * c51_n_atoms * c51_input_dim
|
||||
} else {
|
||||
N_WEIGHTS
|
||||
};
|
||||
let n_biases_eff: usize = if cli.c51 { N_ACTIONS * c51_n_atoms } else { N_BIASES };
|
||||
// --- Initialize Q-network (C51 over Mamba2 h_enriched) ---
|
||||
let c51_input_dim: usize = cli.mamba2_hidden_dim;
|
||||
let n_weights_eff: usize = N_ACTIONS * c51_n_atoms * c51_input_dim;
|
||||
let n_biases_eff: usize = N_ACTIONS * c51_n_atoms;
|
||||
let mut rng = SmokeRng::new(cli.seed.wrapping_add(0xDEAD_BEEF));
|
||||
let xavier_scale = (2.0_f32 / c51_input_dim as f32).sqrt();
|
||||
let w_init: Vec<f32> = (0..n_weights_eff)
|
||||
@@ -527,55 +439,27 @@ fn main() -> Result<()> {
|
||||
|
||||
let state_dim_i = STATE_DIM as i32;
|
||||
let n_act_i = N_ACTIONS as i32;
|
||||
let n_atoms_i = c51_n_atoms as i32;
|
||||
let mut states_dev = stream.alloc_zeros::<f32>(cli.horizon * STATE_DIM)?;
|
||||
let mut next_states_dev = stream.alloc_zeros::<f32>(cli.horizon * STATE_DIM)?;
|
||||
let mut actions_dev = stream.alloc_zeros::<i32>(cli.horizon)?;
|
||||
let mut rewards_dev = stream.alloc_zeros::<f32>(cli.horizon)?;
|
||||
let mut dones_dev = stream.alloc_zeros::<f32>(cli.horizon)?;
|
||||
let mut q_current_dev = stream.alloc_zeros::<f32>(cli.horizon * N_ACTIONS)?;
|
||||
let mut q_next_dev = stream.alloc_zeros::<f32>(cli.horizon * N_ACTIONS)?;
|
||||
let mut target_dev = stream.alloc_zeros::<f32>(cli.horizon)?;
|
||||
let mut single_state_dev = stream.alloc_zeros::<f32>(STATE_DIM)?;
|
||||
let mut single_q_dev = stream.alloc_zeros::<f32>(N_ACTIONS)?;
|
||||
// C51 device buffers (always allocated; cheap).
|
||||
let mut probs_current_dev = stream.alloc_zeros::<f32>(cli.horizon * N_ACTIONS * c51_n_atoms)?;
|
||||
let mut probs_next_dev = stream.alloc_zeros::<f32>(cli.horizon * N_ACTIONS * c51_n_atoms)?;
|
||||
let mut m_dev = stream.alloc_zeros::<f32>(cli.horizon * c51_n_atoms)?;
|
||||
let mut single_probs_dev = stream.alloc_zeros::<f32>(N_ACTIONS * c51_n_atoms)?;
|
||||
// Mapped-pinned per-step inference buffers (C51 path).
|
||||
let state_pinned = unsafe { MappedF32::new(STATE_DIM)? };
|
||||
let action_pinned = unsafe { MappedI32::new(1)? };
|
||||
// All per-step inference + per-episode transition buffers live in
|
||||
// the batched parallel-env section below (states_train_dev etc.,
|
||||
// batched_window_tensor_train, batched_probs_dev, ...). The
|
||||
// single-env legacy buffers and the scalar linear-Q transition
|
||||
// buffers were removed when C51 + temporal + batched became the
|
||||
// only execution path.
|
||||
|
||||
// Phase E.4.A.8 (T12): temporal buffers, allocated unconditionally.
|
||||
let mut window_tensor = GpuTensor::zeros(
|
||||
&[1, cli.window_k, STATE_DIM], &stream
|
||||
).map_err(|e| anyhow::anyhow!("alloc window: {e}"))?;
|
||||
let h_enriched_buf_capacity = (cli.horizon + 1) * cli.mamba2_hidden_dim;
|
||||
let mut h_enriched_buf_dev = stream
|
||||
.alloc_zeros::<f32>(h_enriched_buf_capacity)
|
||||
.context("alloc h_enriched buffer")?;
|
||||
let mut mamba2_block: Option<Mamba2Block> = if cli.temporal {
|
||||
let mut mamba2_block: Mamba2Block = {
|
||||
let cfg = Mamba2BlockConfig {
|
||||
in_dim: STATE_DIM,
|
||||
hidden_dim: cli.mamba2_hidden_dim,
|
||||
state_dim: cli.mamba2_state_dim,
|
||||
seq_len: cli.window_k,
|
||||
};
|
||||
info!("TEMPORAL Mamba2: in={} hidden={} state={} K={}",
|
||||
info!("Mamba2: in={} hidden={} state={} K={}",
|
||||
cfg.in_dim, cfg.hidden_dim, cfg.state_dim, cfg.seq_len);
|
||||
Some(Mamba2Block::new(cfg, stream.clone())
|
||||
.map_err(|e| anyhow::anyhow!("Mamba2Block init: {e}"))?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// Phase E.4.A.T10: AdamW for Mamba2 weights (only when --temporal).
|
||||
let mut mamba2_adamw: Option<Mamba2AdamW> = if let Some(block) = mamba2_block.as_ref() {
|
||||
Some(Mamba2AdamW::new(block, Mamba2AdamWConfig::default())
|
||||
.map_err(|e| anyhow::anyhow!("Mamba2AdamW init: {e}"))?)
|
||||
} else {
|
||||
None
|
||||
Mamba2Block::new(cfg, stream.clone())
|
||||
.map_err(|e| anyhow::anyhow!("Mamba2Block init: {e}"))?
|
||||
};
|
||||
let mut mamba2_adamw: Mamba2AdamW = Mamba2AdamW::new(&mamba2_block, Mamba2AdamWConfig::default())
|
||||
.map_err(|e| anyhow::anyhow!("Mamba2AdamW init: {e}"))?;
|
||||
// Load the C51 grad-input kernel (for backward chain into Mamba2).
|
||||
let c51_grad_input_kernel = c51_module
|
||||
.load_function("alpha_c51_grad_input_kernel")
|
||||
@@ -663,11 +547,9 @@ fn main() -> Result<()> {
|
||||
}
|
||||
let mut par_states: Vec<EpisodeState> = vec![EpisodeState::new(); train_n_par];
|
||||
let mut done_flags = vec![false; train_n_par];
|
||||
if cli.temporal {
|
||||
stream.memset_zeros(batched_window_tensor_train.data_mut())?;
|
||||
stream.memset_zeros(train_windows_tensor_train.data_mut())?;
|
||||
stream.memset_zeros(d_h_enriched_tensor_train.data_mut())?;
|
||||
}
|
||||
stream.memset_zeros(batched_window_tensor_train.data_mut())?;
|
||||
stream.memset_zeros(train_windows_tensor_train.data_mut())?;
|
||||
stream.memset_zeros(d_h_enriched_tensor_train.data_mut())?;
|
||||
stream.memset_zeros(&mut h_enriched_train_dev)?;
|
||||
let mut states_host_train: Vec<f32> = vec![0.0; train_batch * STATE_DIM];
|
||||
let mut next_states_host_train: Vec<f32> = vec![0.0; train_batch * STATE_DIM];
|
||||
@@ -685,45 +567,44 @@ fn main() -> Result<()> {
|
||||
}
|
||||
batched_state_pinned_train.write(&batched_states_host);
|
||||
|
||||
if cli.temporal {
|
||||
{
|
||||
let (w_ptr, _g) = batched_window_tensor_train.data_mut().device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_window_push_batched(
|
||||
&stream, &push_batched_kernel,
|
||||
batched_state_pinned_train.dev_u64(), w_ptr,
|
||||
train_n_par as i32, cli.window_k as i32, state_dim_i,
|
||||
)?;
|
||||
}
|
||||
{
|
||||
let (w_ptr, _g) = batched_window_tensor_train.data_mut().device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_window_push_batched(
|
||||
&stream, &push_batched_kernel,
|
||||
batched_state_pinned_train.dev_u64(), w_ptr,
|
||||
train_n_par as i32, cli.window_k as i32, state_dim_i,
|
||||
)?;
|
||||
}
|
||||
// T10: capture post-push windows into [H*N_par, K, in_dim] buffer
|
||||
// at step row offset `step * N_par`.
|
||||
{
|
||||
let (src_ptr, _g_src) = batched_window_tensor_train.data().device_ptr(&stream);
|
||||
let (dst_ptr, _g_dst) = train_windows_tensor_train.data_mut().device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_train_window_store_batched(
|
||||
&stream, &train_window_store_kernel,
|
||||
src_ptr, dst_ptr, (step * train_n_par) as i32,
|
||||
train_n_par as i32, cli.window_k as i32, state_dim_i,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
// T10: capture post-push windows into [H*N_par, K, in_dim] buffer
|
||||
// at step row offset `step * N_par`.
|
||||
{
|
||||
let (src_ptr, _g_src) = batched_window_tensor_train.data().device_ptr(&stream);
|
||||
let (dst_ptr, _g_dst) = train_windows_tensor_train.data_mut().device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_train_window_store_batched(
|
||||
&stream, &train_window_store_kernel,
|
||||
src_ptr, dst_ptr, (step * train_n_par) as i32,
|
||||
train_n_par as i32, cli.window_k as i32, state_dim_i,
|
||||
)?;
|
||||
}
|
||||
let block = mamba2_block.as_ref().expect("Mamba2Block missing");
|
||||
let (_logit, cache) = block.forward_train(&batched_window_tensor_train)
|
||||
.map_err(|e| anyhow::anyhow!("train mamba2: {e}"))?;
|
||||
{
|
||||
let (src_p, _g_src) = cache.h_enriched.cuda_data().device_ptr(&stream);
|
||||
let (buf_p, _g_buf) = h_enriched_train_dev.device_ptr_mut(&stream);
|
||||
let step_row_offset = (step * train_n_par) as i32;
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_h_enriched_store_batched(
|
||||
&stream, &h_store_batched_kernel,
|
||||
src_p, buf_p, step_row_offset,
|
||||
train_n_par as i32, cli.mamba2_hidden_dim as i32,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
let (_logit, cache) = mamba2_block.forward_train(&batched_window_tensor_train)
|
||||
.map_err(|e| anyhow::anyhow!("train mamba2: {e}"))?;
|
||||
{
|
||||
let (src_p, _g_src) = cache.h_enriched.cuda_data().device_ptr(&stream);
|
||||
let (buf_p, _g_buf) = h_enriched_train_dev.device_ptr_mut(&stream);
|
||||
let step_row_offset = (step * train_n_par) as i32;
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_h_enriched_store_batched(
|
||||
&stream, &h_store_batched_kernel,
|
||||
src_p, buf_p, step_row_offset,
|
||||
train_n_par as i32, cli.mamba2_hidden_dim as i32,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
{
|
||||
let (h_ptr, _g_h) = cache.h_enriched.cuda_data().device_ptr(&stream);
|
||||
let (w_ptr, _g0) = w_dev.device_ptr(&stream);
|
||||
let (b_ptr, _g1) = b_dev.device_ptr(&stream);
|
||||
@@ -735,17 +616,6 @@ fn main() -> Result<()> {
|
||||
train_n_par as i32, c51_input_dim as i32, n_act_i, n_atoms_i,
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
let (w_ptr, _g0) = w_dev.device_ptr(&stream);
|
||||
let (b_ptr, _g1) = b_dev.device_ptr(&stream);
|
||||
let (p_ptr, _g3) = batched_probs_inference_train.device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_c51_forward(
|
||||
&stream, &c51_fwd_kernel,
|
||||
w_ptr, b_ptr, batched_state_pinned_train.dev_u64(), p_ptr,
|
||||
train_n_par as i32, c51_input_dim as i32, n_act_i, n_atoms_i,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
let step_seed = episode_rng.next_u64() as u32;
|
||||
{
|
||||
@@ -795,33 +665,15 @@ fn main() -> Result<()> {
|
||||
// that backward_from_h_enriched can consume. cache.h_enriched
|
||||
// replaces h_enriched_train_dev curr offset (bit-identical since
|
||||
// Mamba2 weights haven't been updated yet this epoch).
|
||||
let cache_train: Option<ml_alpha::mamba2_block::Mamba2ForwardCache> = if cli.temporal {
|
||||
let block = mamba2_block.as_ref().expect("Mamba2Block missing");
|
||||
let (_logit, cache) = block.forward_train(&train_windows_tensor_train)
|
||||
.map_err(|e| anyhow::anyhow!("train mamba2 (epoch forward): {e}"))?;
|
||||
Some(cache)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let (curr_input_ptr_guard, next_input_ptr_guard);
|
||||
let (curr_input_ptr, next_input_ptr): (u64, u64) = if cli.temporal {
|
||||
let cache = cache_train.as_ref().expect("cache_train missing");
|
||||
let (h_curr, g) = cache.h_enriched.cuda_data().device_ptr(&stream);
|
||||
let (h_base_next, g_next) = h_enriched_train_dev.device_ptr(&stream);
|
||||
curr_input_ptr_guard = g;
|
||||
next_input_ptr_guard = g_next;
|
||||
let _ = (&curr_input_ptr_guard, &next_input_ptr_guard);
|
||||
let (_logit, cache_train) = mamba2_block.forward_train(&train_windows_tensor_train)
|
||||
.map_err(|e| anyhow::anyhow!("train mamba2 (epoch forward): {e}"))?;
|
||||
let (curr_input_ptr, next_input_ptr): (u64, u64) = {
|
||||
let (h_curr, _g) = cache_train.h_enriched.cuda_data().device_ptr(&stream);
|
||||
let (h_base_next, _g_next) = h_enriched_train_dev.device_ptr(&stream);
|
||||
(
|
||||
h_curr,
|
||||
h_base_next + (train_n_par as u64) * (cli.mamba2_hidden_dim as u64) * 4u64,
|
||||
)
|
||||
} else {
|
||||
let (s_ptr, g_c) = states_train_dev.device_ptr(&stream);
|
||||
let (n_ptr, g_n) = next_states_train_dev.device_ptr(&stream);
|
||||
curr_input_ptr_guard = g_c;
|
||||
next_input_ptr_guard = g_n;
|
||||
let _ = (&curr_input_ptr_guard, &next_input_ptr_guard);
|
||||
(s_ptr, n_ptr)
|
||||
};
|
||||
|
||||
{
|
||||
@@ -866,48 +718,40 @@ fn main() -> Result<()> {
|
||||
let (p_ptr, _g0) = probs_curr_train_dev.device_ptr(&stream);
|
||||
let (m_ptr, _g1) = m_train_dev.device_ptr(&stream);
|
||||
let (a_ptr, _g2) = actions_train_dev.device_ptr(&stream);
|
||||
let (s_ptr, _g3) = states_train_dev.device_ptr(&stream);
|
||||
let (dw_ptr, _g4) = dw_dev.device_ptr_mut(&stream);
|
||||
let (db_ptr, _g5) = db_dev.device_ptr_mut(&stream);
|
||||
let grad_input_ptr = if cli.temporal { curr_input_ptr } else { s_ptr };
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_c51_grad(
|
||||
&stream, &c51_grad_kernel,
|
||||
p_ptr, m_ptr, a_ptr, grad_input_ptr, dw_ptr, db_ptr,
|
||||
p_ptr, m_ptr, a_ptr, curr_input_ptr, dw_ptr, db_ptr,
|
||||
bt, c51_input_dim as i32, n_act_i, n_atoms_i,
|
||||
1.0 / bt as f32,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
// T10 backward chain: C51 grad_input → Mamba2 backward → AdamW step.
|
||||
if cli.temporal {
|
||||
{
|
||||
let (p_ptr, _g0) = probs_curr_train_dev.device_ptr(&stream);
|
||||
let (m_ptr, _g1) = m_train_dev.device_ptr(&stream);
|
||||
let (a_ptr, _g2) = actions_train_dev.device_ptr(&stream);
|
||||
let (w_ptr, _g3) = w_dev.device_ptr(&stream);
|
||||
let (dh_ptr, _g4) = d_h_enriched_tensor_train.data_mut().device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_c51_grad_input(
|
||||
&stream, &c51_grad_input_kernel,
|
||||
p_ptr, m_ptr, a_ptr, w_ptr, dh_ptr,
|
||||
bt, c51_input_dim as i32, n_act_i, n_atoms_i,
|
||||
1.0 / bt as f32,
|
||||
)?;
|
||||
}
|
||||
{
|
||||
let (p_ptr, _g0) = probs_curr_train_dev.device_ptr(&stream);
|
||||
let (m_ptr, _g1) = m_train_dev.device_ptr(&stream);
|
||||
let (a_ptr, _g2) = actions_train_dev.device_ptr(&stream);
|
||||
let (w_ptr, _g3) = w_dev.device_ptr(&stream);
|
||||
let (dh_ptr, _g4) = d_h_enriched_tensor_train.data_mut().device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_c51_grad_input(
|
||||
&stream, &c51_grad_input_kernel,
|
||||
p_ptr, m_ptr, a_ptr, w_ptr, dh_ptr,
|
||||
bt, c51_input_dim as i32, n_act_i, n_atoms_i,
|
||||
1.0 / bt as f32,
|
||||
)?;
|
||||
}
|
||||
let cache = cache_train.as_ref().expect("cache_train missing");
|
||||
let block_ref = mamba2_block.as_ref().expect("Mamba2Block missing");
|
||||
let grads = block_ref
|
||||
.backward_from_h_enriched(cache, &d_h_enriched_tensor_train)
|
||||
.map_err(|e| anyhow::anyhow!("Mamba2 backward: {e}"))?;
|
||||
let _ = cache_train;
|
||||
let block_mut = mamba2_block.as_mut().expect("Mamba2Block missing");
|
||||
let adamw = mamba2_adamw.as_mut().expect("Mamba2AdamW missing");
|
||||
adamw
|
||||
.step(block_mut, &grads)
|
||||
.map_err(|e| anyhow::anyhow!("Mamba2AdamW step: {e}"))?;
|
||||
}
|
||||
let grads = mamba2_block
|
||||
.backward_from_h_enriched(&cache_train, &d_h_enriched_tensor_train)
|
||||
.map_err(|e| anyhow::anyhow!("Mamba2 backward: {e}"))?;
|
||||
drop(cache_train);
|
||||
mamba2_adamw
|
||||
.step(&mut mamba2_block, &grads)
|
||||
.map_err(|e| anyhow::anyhow!("Mamba2AdamW step: {e}"))?;
|
||||
{
|
||||
let (dw_ptr, _g0) = dw_dev.device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
@@ -982,15 +826,12 @@ fn main() -> Result<()> {
|
||||
// memory with no htod copy.
|
||||
let mids_curr_pinned = unsafe { MappedF32::new(n_par)? };
|
||||
let mids_prev_pinned = unsafe { MappedF32::new(n_par)? };
|
||||
let regime_module = if cli.regime_scale {
|
||||
Some(ctx.load_cubin(
|
||||
ml::cuda_pipeline::alpha_kernels::ALPHA_REGIME_VOL_UPDATE_CUBIN.to_vec()
|
||||
).context("alpha_regime_vol_update cubin load")?)
|
||||
} else { None };
|
||||
let regime_kernel = regime_module.as_ref().map(|m|
|
||||
m.load_function("alpha_regime_vol_update_kernel")
|
||||
.expect("alpha_regime_vol_update_kernel load")
|
||||
);
|
||||
let regime_module = ctx.load_cubin(
|
||||
ml::cuda_pipeline::alpha_kernels::ALPHA_REGIME_VOL_UPDATE_CUBIN.to_vec()
|
||||
).context("alpha_regime_vol_update cubin load")?;
|
||||
let regime_kernel = regime_module
|
||||
.load_function("alpha_regime_vol_update_kernel")
|
||||
.context("alpha_regime_vol_update_kernel load")?;
|
||||
let snapshots_arc = env.snapshots_arc();
|
||||
let fill_model_for_par = env.fill_model.clone();
|
||||
let env_config_template = env.config.clone();
|
||||
@@ -1020,13 +861,11 @@ fn main() -> Result<()> {
|
||||
let mut ep_n_trades_par = vec![0_u32; n_par];
|
||||
let mut done_flags = vec![false; n_par];
|
||||
// Zero batched windows.
|
||||
if cli.temporal {
|
||||
stream.memset_zeros(batched_window_tensor.data_mut())
|
||||
.context("zero batched windows")?;
|
||||
}
|
||||
stream.memset_zeros(batched_window_tensor.data_mut())
|
||||
.context("zero batched windows")?;
|
||||
// T16: reset prev_mids so the first-step Pearl-A bootstrap fires
|
||||
// cleanly (kernel guards against curr<=0 || prev<=0 internally).
|
||||
if cli.regime_scale {
|
||||
{
|
||||
let zeros = vec![0.0_f32; n_par];
|
||||
mids_curr_pinned.write(&zeros);
|
||||
mids_prev_pinned.write(&zeros);
|
||||
@@ -1046,7 +885,7 @@ fn main() -> Result<()> {
|
||||
// env step advances. Regime signal therefore reflects vol
|
||||
// observed up to and including this step, which is what the
|
||||
// controller's per-episode Kelly update will read.
|
||||
if let Some(rk) = regime_kernel.as_ref() {
|
||||
{
|
||||
let mut mids_host = vec![0.0_f32; n_par];
|
||||
for i in 0..n_par {
|
||||
if !done_flags[i] {
|
||||
@@ -1057,7 +896,7 @@ fn main() -> Result<()> {
|
||||
unsafe {
|
||||
let (isv_ptr, _g) = isv_dev.device_ptr_mut(&stream);
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_regime_vol_update(
|
||||
&stream, rk,
|
||||
&stream, ®ime_kernel,
|
||||
mids_curr_pinned.dev_u64(),
|
||||
mids_prev_pinned.dev_u64(),
|
||||
isv_ptr,
|
||||
@@ -1071,23 +910,22 @@ fn main() -> Result<()> {
|
||||
// is a CPU-side fill, no device-to-device copy needed.
|
||||
mids_prev_pinned.write(&mids_host);
|
||||
}
|
||||
if cli.temporal {
|
||||
// Batched window push.
|
||||
{
|
||||
let (w_ptr, _g) = batched_window_tensor.data_mut().device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_window_push_batched(
|
||||
&stream, &push_batched_kernel,
|
||||
batched_state_pinned.dev_u64(), w_ptr,
|
||||
n_par as i32, cli.window_k as i32, state_dim_i,
|
||||
)?;
|
||||
}
|
||||
// Batched window push.
|
||||
{
|
||||
let (w_ptr, _g) = batched_window_tensor.data_mut().device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_window_push_batched(
|
||||
&stream, &push_batched_kernel,
|
||||
batched_state_pinned.dev_u64(), w_ptr,
|
||||
n_par as i32, cli.window_k as i32, state_dim_i,
|
||||
)?;
|
||||
}
|
||||
// Batched Mamba2 forward → cache.h_enriched [N, hidden].
|
||||
let block = mamba2_block.as_ref().expect("Mamba2Block missing");
|
||||
let (_logit, cache) = block.forward_train(&batched_window_tensor)
|
||||
.map_err(|e| anyhow::anyhow!("batched mamba2 forward (eval): {e}"))?;
|
||||
// Batched C51 forward.
|
||||
}
|
||||
// Batched Mamba2 forward → cache.h_enriched [N, hidden].
|
||||
let (_logit, cache) = mamba2_block.forward_train(&batched_window_tensor)
|
||||
.map_err(|e| anyhow::anyhow!("batched mamba2 forward (eval): {e}"))?;
|
||||
// Batched C51 forward.
|
||||
{
|
||||
let (h_ptr, _g_h) = cache.h_enriched.cuda_data().device_ptr(&stream);
|
||||
let (w_ptr, _g0) = w_dev.device_ptr(&stream);
|
||||
let (b_ptr, _g1) = b_dev.device_ptr(&stream);
|
||||
@@ -1099,18 +937,6 @@ fn main() -> Result<()> {
|
||||
n_par as i32, c51_input_dim as i32, n_act_i, n_atoms_i,
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
// C51 reads directly from batched_state_pinned (B=N).
|
||||
let (w_ptr, _g0) = w_dev.device_ptr(&stream);
|
||||
let (b_ptr, _g1) = b_dev.device_ptr(&stream);
|
||||
let (p_ptr, _g3) = batched_probs_dev.device_ptr_mut(&stream);
|
||||
unsafe {
|
||||
ml::cuda_pipeline::alpha_kernels::launch_alpha_c51_forward(
|
||||
&stream, &c51_fwd_kernel,
|
||||
w_ptr, b_ptr, batched_state_pinned.dev_u64(), p_ptr,
|
||||
n_par as i32, c51_input_dim as i32, n_act_i, n_atoms_i,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
// Batched Thompson select.
|
||||
let step_seed = episode_rng.next_u64() as u32;
|
||||
@@ -1156,7 +982,10 @@ fn main() -> Result<()> {
|
||||
#[allow(unused_mut)]
|
||||
let mut win_count: usize = rewards.iter().filter(|&&r| r > 0.0).count();
|
||||
// ISV-continual at cell-level (single fire with aggregate stats).
|
||||
if cli.isv_continual {
|
||||
// Threshold + Kelly controllers adapt during the 2D sweep; the
|
||||
// T16 regime kernel feeds the pre-emptive Kelly attenuation
|
||||
// multiplier via slots 549/550.
|
||||
{
|
||||
let mean_terminal_r = rewards.iter().sum::<f32>() / (n_par as f32);
|
||||
let trade_count_avg = trade_count_total as f32 / (n_par as f32);
|
||||
let decisions_avg = cli.horizon as f32;
|
||||
@@ -1173,15 +1002,8 @@ fn main() -> Result<()> {
|
||||
ml::cuda_pipeline::alpha_isv_slots::TRADE_RATE_TARGET_INDEX as i32,
|
||||
ml::cuda_pipeline::alpha_isv_slots::TRADE_RATE_OBSERVED_EMA_INDEX as i32,
|
||||
ml::cuda_pipeline::alpha_isv_slots::STACKER_KELLY_ATTENUATION_INDEX as i32,
|
||||
// T16 regime hookup. Active when --isv-continual is on;
|
||||
// the regime kernel writes slots 549/550 per-step during
|
||||
// inference. Floor 0.25 = max defensive 4× Kelly cut.
|
||||
if cli.regime_scale {
|
||||
ml::cuda_pipeline::alpha_isv_slots::REGIME_VOL_EMA_INDEX as i32
|
||||
} else { -1 },
|
||||
if cli.regime_scale {
|
||||
ml::cuda_pipeline::alpha_isv_slots::REGIME_VOL_REF_INDEX as i32
|
||||
} else { -1 },
|
||||
ml::cuda_pipeline::alpha_isv_slots::REGIME_VOL_EMA_INDEX as i32,
|
||||
ml::cuda_pipeline::alpha_isv_slots::REGIME_VOL_REF_INDEX as i32,
|
||||
0.25,
|
||||
isv_ptr, wv_ptr,
|
||||
)?;
|
||||
@@ -1266,18 +1088,14 @@ fn main() -> Result<()> {
|
||||
|
||||
// --- Save JSON ---
|
||||
let json = serde_json::json!({
|
||||
"phase": "E.3 Task 23 (2D sweep)",
|
||||
"pruned_actions": cli.pruned_actions,
|
||||
"binary": "alpha_baseline",
|
||||
"n_allowed_actions": allowed_actions.len(),
|
||||
"c51": cli.c51,
|
||||
"c51_n_atoms": if cli.c51 { c51_n_atoms } else { 0 },
|
||||
"c51_vmin": if cli.c51 { c51_v_min } else { 0.0 },
|
||||
"c51_vmax": if cli.c51 { c51_v_max } else { 0.0 },
|
||||
"temporal": cli.temporal,
|
||||
"window_k": if cli.temporal { cli.window_k } else { 0 },
|
||||
"mamba2_hidden_dim": if cli.temporal { cli.mamba2_hidden_dim } else { 0 },
|
||||
"mamba2_state_dim": if cli.temporal { cli.mamba2_state_dim } else { 0 },
|
||||
"isv_continual": cli.isv_continual,
|
||||
"c51_n_atoms": c51_n_atoms,
|
||||
"c51_vmin": c51_v_min,
|
||||
"c51_vmax": c51_v_max,
|
||||
"window_k": cli.window_k,
|
||||
"mamba2_hidden_dim": cli.mamba2_hidden_dim,
|
||||
"mamba2_state_dim": cli.mamba2_state_dim,
|
||||
"horizon": cli.horizon,
|
||||
"train_frac": cli.train_frac,
|
||||
"n_train_episodes": cli.n_train_episodes,
|
||||
2
crates/ml/src/env/loaders.rs
vendored
2
crates/ml/src/env/loaders.rs
vendored
@@ -1,5 +1,5 @@
|
||||
//! Phase E loader helpers shared by `alpha_dqn_h600_smoke` and
|
||||
//! `alpha_compose_backtest` (and any future Phase E binary).
|
||||
//! `alpha_baseline` (and any future Phase E binary).
|
||||
//!
|
||||
//! Three loaders:
|
||||
//!
|
||||
|
||||
@@ -18,7 +18,7 @@ set -euo pipefail
|
||||
REPO=/home/jgrusewski/Work/foxhunt/.worktrees/sp19-20-wr-first
|
||||
CACHE_DIR=/home/jgrusewski/Work/foxhunt/test_data/feature-cache
|
||||
FILL=config/ml/alpha_fill_coeffs.json
|
||||
BIN_BT=./target/release/examples/alpha_compose_backtest
|
||||
BIN_BT=./target/release/examples/alpha_baseline
|
||||
BIN_STACK=./target/release/examples/alpha_train_stacker
|
||||
|
||||
cd "$REPO"
|
||||
@@ -55,7 +55,7 @@ fi
|
||||
echo "Alpha cache: $ALPHA_OUT"
|
||||
|
||||
# ----- 2. Build backtest binary (in case of code changes) -----
|
||||
SQLX_OFFLINE=true cargo build --release --example alpha_compose_backtest -p ml >/dev/null
|
||||
SQLX_OFFLINE=true cargo build --release --example alpha_baseline -p ml >/dev/null
|
||||
|
||||
# ----- 3. Walk-forward CV across 4 conditions × 3 folds -----
|
||||
# Fold A: offset=0, window=1.2M → train 0..720K, eval 720K..1.2M
|
||||
@@ -63,11 +63,13 @@ SQLX_OFFLINE=true cargo build --release --example alpha_compose_backtest -p ml >
|
||||
# Fold C: offset=1.8M, window=1.2M → train 1.8M..2.52M, eval 2.52M..3.0M
|
||||
# (Assumes Q1+Q2 fxcache has ~3-6M bars total at MBP-10 resolution.)
|
||||
|
||||
# Cost randomization is the only opt-in left: `--train-cost-hi 0.5` enables
|
||||
# uniform[0.0625, 0.5] per-epoch cost sampling. C51 / temporal / ISV-continual
|
||||
# / regime-scale are now always-on properties of alpha_baseline; the A/B
|
||||
# split is now just fixed-cost vs cost-randomised training.
|
||||
declare -a CONDS=(
|
||||
"A_baseline:--c51 --temporal --window-k 16 --isv-continual"
|
||||
"B_costrand:--c51 --temporal --window-k 16 --isv-continual --train-cost-hi 0.5"
|
||||
"C_regime:--c51 --temporal --window-k 16 --isv-continual --regime-scale"
|
||||
"D_both:--c51 --temporal --window-k 16 --isv-continual --train-cost-hi 0.5 --regime-scale"
|
||||
"A_fixed:--window-k 16"
|
||||
"B_costrand:--window-k 16 --train-cost-hi 0.5"
|
||||
)
|
||||
|
||||
declare -a FOLDS=(
|
||||
@@ -108,7 +110,7 @@ echo "Alpha pipeline cross-quarter walk-forward summary"
|
||||
echo "===================================================================="
|
||||
python3 - <<'PY'
|
||||
import json, os, statistics
|
||||
conds = ["A_baseline", "B_costrand", "C_regime", "D_both"]
|
||||
conds = ["A_fixed", "B_costrand"]
|
||||
folds = ["A", "B", "C"]
|
||||
|
||||
# For each (cond, cost): list of best Sharpe across folds
|
||||
|
||||
@@ -13,7 +13,7 @@ set -euo pipefail
|
||||
FXCACHE="${FXCACHE:-/home/jgrusewski/Work/foxhunt/test_data/feature-cache/9297017b6db6795f75e57be8aefb03e45e6427513f42c08e22521e58fa025d5e.fxcache}"
|
||||
ALPHA="${ALPHA:-config/ml/alpha_logits_cache.bin}"
|
||||
FILL="${FILL:-config/ml/alpha_fill_coeffs.json}"
|
||||
BIN="${BIN:-./target/release/examples/alpha_compose_backtest}"
|
||||
BIN="${BIN:-./target/release/examples/alpha_baseline}"
|
||||
|
||||
WINDOW=700000
|
||||
TRAIN_FRAC=0.6 # 420K train, 280K eval per fold
|
||||
@@ -38,7 +38,7 @@ for fold_spec in "${FOLDS[@]}"; do
|
||||
--data-start-offset "$offset" \
|
||||
--max-snapshots "$WINDOW" \
|
||||
--train-frac "$TRAIN_FRAC" \
|
||||
--c51 --temporal --window-k 16 --isv-continual \
|
||||
--window-k 16 \
|
||||
--out-path "$out"
|
||||
done
|
||||
|
||||
|
||||
Reference in New Issue
Block a user