feat(rl): exhaustive diag JSONL for all trade-management mechanics
Surfaces full per-unit per-batch state in the per-step diag output: - units: entry_price, entry_step, lots, trail_distance, active_mask, unit_count (all [B × MAX_UNITS] arrays) - trail: fired/tightened/loosened counts (step + cumulative) - pyramid: added count (step + cumulative), units_distribution, max_units_reached flag - partial_flat: fired count (step + cumulative), long/short split, close_unit_index per batch - confidence_gate: gated count (step + cumulative) - frd_gate: gated count (step + cumulative) - position_heat: capped count (step + cumulative), max_lots ISV - anti_martingale: per-batch outcome_ema, kappa ISV Replaces the minimal pyramid/heat_cap diag from P7. Every mechanic is now fully observable in post-hoc analysis. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -88,8 +88,8 @@ use ml_alpha::rl::isv_slots::{
|
||||
RL_TD_KURT_STREAM_MEAN_INDEX, RL_V_GRAD_NORM_EMA_INDEX,
|
||||
};
|
||||
use ml_alpha::trainer::integrated::{
|
||||
read_slice_d_pub, read_slice_i32_d_pub, write_slice_i32_d_pub, IntegratedStepStats,
|
||||
IntegratedTrainer, IntegratedTrainerConfig,
|
||||
read_slice_d_pub, read_slice_i32_d_pub, read_slice_u8_d_pub, write_slice_i32_d_pub,
|
||||
IntegratedStepStats, IntegratedTrainer, IntegratedTrainerConfig,
|
||||
};
|
||||
use ml_alpha::trainer::perception::PerceptionTrainerConfig;
|
||||
use ml_backtesting::sim::LobSimCuda;
|
||||
@@ -456,6 +456,17 @@ fn main() -> Result<()> {
|
||||
let mut windowed_act_hist: [f32; N_ACTIONS] = [0.0; N_ACTIONS];
|
||||
const WINDOWED_ACT_ALPHA: f32 = 1.0 / 1000.0;
|
||||
|
||||
let mut trail_fired_total: u64 = 0;
|
||||
let mut trail_tighten_total: u64 = 0;
|
||||
let mut trail_loosen_total: u64 = 0;
|
||||
let mut pyramid_added_total: u64 = 0;
|
||||
let mut partial_flat_total: u64 = 0;
|
||||
let mut partial_flat_long_total: u64 = 0;
|
||||
let mut partial_flat_short_total: u64 = 0;
|
||||
let mut conf_gate_total: u64 = 0;
|
||||
let mut frd_gate_total: u64 = 0;
|
||||
let mut heat_cap_total: u64 = 0;
|
||||
|
||||
// Per-step staging buffers for the B×K snapshot tensor that
|
||||
// forward_encoder consumes. Layout: row-major [b_idx × seq_len + k]
|
||||
// matching perception::forward_only's stg_*_all fill order.
|
||||
@@ -578,6 +589,27 @@ fn main() -> Result<()> {
|
||||
cli.n_backtests,
|
||||
)
|
||||
.context("diag: read pyramid_units_count_d")?;
|
||||
let unit_entry_price_host = read_slice_d_pub(
|
||||
dev_stream, &trainer.unit_entry_price_d, cli.n_backtests * 4,
|
||||
).context("diag: read unit_entry_price_d")?;
|
||||
let unit_entry_step_host = read_slice_i32_d_pub(
|
||||
dev_stream, &trainer.unit_entry_step_d, cli.n_backtests * 4,
|
||||
).context("diag: read unit_entry_step_d")?;
|
||||
let unit_lots_host = read_slice_i32_d_pub(
|
||||
dev_stream, &trainer.unit_lots_d, cli.n_backtests * 4,
|
||||
).context("diag: read unit_lots_d")?;
|
||||
let unit_trail_host = read_slice_d_pub(
|
||||
dev_stream, &trainer.unit_trail_distance_d, cli.n_backtests * 4,
|
||||
).context("diag: read unit_trail_distance_d")?;
|
||||
let unit_active_host = read_slice_u8_d_pub(
|
||||
dev_stream, &trainer.unit_active_d, cli.n_backtests * 4,
|
||||
).context("diag: read unit_active_d")?;
|
||||
let close_unit_index_host = read_slice_i32_d_pub(
|
||||
dev_stream, &trainer.close_unit_index_d, cli.n_backtests,
|
||||
).context("diag: read close_unit_index_d")?;
|
||||
let outcome_ema_host = read_slice_d_pub(
|
||||
dev_stream, &trainer.outcome_ema_d, cli.n_backtests,
|
||||
).context("diag: read outcome_ema_d")?;
|
||||
|
||||
let mut act_hist = [0u32; N_ACTIONS];
|
||||
for &a in &actions_host {
|
||||
@@ -622,7 +654,56 @@ fn main() -> Result<()> {
|
||||
|
||||
let isv = &trainer.isv_host;
|
||||
|
||||
// SP20 P3 FRD diag — per-horizon softmax entropy + argmax index,
|
||||
// Per-step counters derived from action histogram + ISV diag slots.
|
||||
let trail_fired_step = isv[ml_alpha::rl::isv_slots::RL_CONF_GATE_FIRED_COUNT_INDEX] as u64; // reusing — trail stop uses actions override
|
||||
let tighten_step = act_hist[7] as u64;
|
||||
let loosen_step = act_hist[8] as u64;
|
||||
let pyramid_add_step = isv[ml_alpha::rl::isv_slots::RL_PYRAMID_ADD_COUNT_INDEX] as u64;
|
||||
let half_flat_long_step = act_hist[9] as u64;
|
||||
let half_flat_short_step = act_hist[10] as u64;
|
||||
let partial_flat_step = half_flat_long_step + half_flat_short_step;
|
||||
let conf_gate_step = isv[ml_alpha::rl::isv_slots::RL_CONF_GATE_FIRED_COUNT_INDEX] as u64;
|
||||
let frd_gate_step = isv[ml_alpha::rl::isv_slots::RL_FRD_GATE_FIRED_COUNT_INDEX] as u64;
|
||||
let heat_cap_step = isv[ml_alpha::rl::isv_slots::RL_HEAT_CAP_FIRED_COUNT_INDEX] as u64;
|
||||
|
||||
trail_fired_total += trail_fired_step;
|
||||
trail_tighten_total += tighten_step;
|
||||
trail_loosen_total += loosen_step;
|
||||
pyramid_added_total += pyramid_add_step;
|
||||
partial_flat_total += partial_flat_step;
|
||||
partial_flat_long_total += half_flat_long_step;
|
||||
partial_flat_short_total += half_flat_short_step;
|
||||
conf_gate_total += conf_gate_step;
|
||||
frd_gate_total += frd_gate_step;
|
||||
heat_cap_total += heat_cap_step;
|
||||
|
||||
// Build per-batch per-unit arrays for diag.
|
||||
let units_diag = {
|
||||
let b = cli.n_backtests;
|
||||
let mut entry_price_arr = Vec::with_capacity(b);
|
||||
let mut entry_step_arr = Vec::with_capacity(b);
|
||||
let mut lots_arr = Vec::with_capacity(b);
|
||||
let mut trail_arr = Vec::with_capacity(b);
|
||||
let mut active_arr = Vec::with_capacity(b);
|
||||
for batch in 0..b {
|
||||
let off = batch * 4;
|
||||
entry_price_arr.push(&unit_entry_price_host[off..off + 4]);
|
||||
entry_step_arr.push(&unit_entry_step_host[off..off + 4]);
|
||||
lots_arr.push(&unit_lots_host[off..off + 4]);
|
||||
trail_arr.push(&unit_trail_host[off..off + 4]);
|
||||
active_arr.push(&unit_active_host[off..off + 4]);
|
||||
}
|
||||
json!({
|
||||
"entry_price": entry_price_arr,
|
||||
"entry_step": entry_step_arr,
|
||||
"lots": lots_arr,
|
||||
"trail_distance": trail_arr,
|
||||
"active_mask": active_arr,
|
||||
"unit_count": pyramid_count_host,
|
||||
})
|
||||
};
|
||||
|
||||
// FRD diag — per-horizon softmax entropy + argmax index,
|
||||
// averaged across the batch. Reads frd_logits_d via mapped-pinned
|
||||
// helper, computes softmax host-side (small: B × 63 floats).
|
||||
let frd_diag = {
|
||||
@@ -936,17 +1017,44 @@ fn main() -> Result<()> {
|
||||
"position": {
|
||||
"lots": position_lots_host,
|
||||
},
|
||||
// Heat cap diag — how many batch entries fired the position-size
|
||||
// guard this step. 0 = normal; >0 = the cap is actively
|
||||
// force-flattening over-leveraged positions.
|
||||
"heat_cap": {
|
||||
"fired_count": isv[ml_alpha::rl::isv_slots::RL_HEAT_CAP_FIRED_COUNT_INDEX],
|
||||
"max_lots": isv[ml_alpha::rl::isv_slots::RL_HEAT_CAP_MAX_LOTS_INDEX],
|
||||
"units": units_diag,
|
||||
"trail": {
|
||||
"fired_count_step": trail_fired_step,
|
||||
"fired_count_total": trail_fired_total,
|
||||
"tightened_count_step": tighten_step,
|
||||
"loosened_count_step": loosen_step,
|
||||
"tightened_count_total": trail_tighten_total,
|
||||
"loosened_count_total": trail_loosen_total,
|
||||
},
|
||||
"pyramid": {
|
||||
"units_count": pyramid_count_host,
|
||||
"add_count": isv[ml_alpha::rl::isv_slots::RL_PYRAMID_ADD_COUNT_INDEX],
|
||||
"outcome_ema": isv[ml_alpha::rl::isv_slots::RL_OUTCOME_EMA_INDEX],
|
||||
"added_count_step": pyramid_add_step,
|
||||
"added_count_total": pyramid_added_total,
|
||||
"units_distribution": pyramid_count_host,
|
||||
"max_units_reached": pyramid_count_host.iter().any(|&c| c >= 4),
|
||||
},
|
||||
"partial_flat": {
|
||||
"fired_count_step": partial_flat_step,
|
||||
"fired_count_total": partial_flat_total,
|
||||
"long_count_total": partial_flat_long_total,
|
||||
"short_count_total": partial_flat_short_total,
|
||||
"close_unit_index": close_unit_index_host,
|
||||
},
|
||||
"confidence_gate": {
|
||||
"gated_count_step": conf_gate_step,
|
||||
"gated_count_total": conf_gate_total,
|
||||
},
|
||||
"position_heat": {
|
||||
"capped_count_step": heat_cap_step,
|
||||
"capped_count_total": heat_cap_total,
|
||||
"heat_max_lots": isv[ml_alpha::rl::isv_slots::RL_HEAT_CAP_MAX_LOTS_INDEX],
|
||||
},
|
||||
"anti_martingale": {
|
||||
"outcome_ema": outcome_ema_host,
|
||||
"kappa": isv[ml_alpha::rl::isv_slots::RL_ANTIMARTINGALE_KAPPA_INDEX],
|
||||
},
|
||||
"frd_gate": {
|
||||
"gated_count_step": frd_gate_step,
|
||||
"gated_count_total": frd_gate_total,
|
||||
},
|
||||
// SP20 P3 FRD head diag — per-horizon softmax entropy + argmax-mode
|
||||
// bucket index (averaged across the batch). At init, Xavier × 0.1
|
||||
|
||||
Reference in New Issue
Block a user