Quant review 2026-09-26: alert cooldown, plain-language alerts, M15 grade-A SELL block, 1R printed targets, panel/breach fixes
Live signals.db review (2026-09-04 → 09-25, 100 unique setups replayed on the scans' stored candles): the stop-hunt claim is refuted (71% of stop-outs ran ≥ 1R past the stop, the same as the books' 70–72%); −25.1R of the −37.8R raw live book were consecutive-bar re-entries the backtester's 5-bar cooldown never takes; the cooldown view sits at the 3rd–5th percentile of the books' three-week windows. Delivery (book-neutral): - telegram_bot: 5-bar alert cooldown per timeframe (_ALERT_COOLDOWN_BARS = backtest.cooldown_bars); setup block prints the trail first as the tested exit, TP1/TP2 as guides with their R, "Planned TP1 RR", and one validated-book line per setup class (agent_panel_base_rates.json); the informational 100-pip TP line is removed (owner request). - AI block rewritten for a new trader: "AI check: the odds look better than / worse than / about usual", the chance "in 100" against the usual odds, one reason for and one against, no verdict word or confidence figure; rendered whenever the verdict carries a probability. agent_panel: persona prompts ban trading jargon (PANEL_PROMPT_VERSION v2.1-2026-09-26); the macro-source verdict now carries its persona's p_win (every live v2 row had panel_probability NULL). Dashboard and guides mirror the wording. - telegram_bot: level-breach rescans skip the settlement-pause window (the 20:45 M15 bar was re-logged at 22:01/22:06/22:11 every evening). Signal (pre-registered rule-1 campaign, CUDA twin paired with gpu_backtest.py): - M15 grade-A SELLs blocked (sell_min_quality ["A+","B"], M15 override 6): W2 813/+154.15R PF 1.53 vs 931/+146.14R PF 1.43, OOS +68.5 vs +60.67, W3 max DD 20.9 vs 19.3R. PASSED a–f. - Printed target 1 floored at 1R in every generator (signals.tp_print_floor_rr), applied AFTER the min-RR and spread gates so no trade changes; mirrored in cuda_signal_kernels.py K2. Label-only re-pin of all four timeframes (only tp1/rr_planned columns move). A floor applied before the gate cost −24.6R and was rejected. - FAILED: M15 min_rr_ratio 1.0 (trade-identical, −2.0R). Owner's call: M5 tp_floor_rr 1.0 (+48.9R W2, max DD 10.1 → 15.9R), not shipped. New pins: M5 W2 e599c8a8…, M15 W2 5b65ecf6…, M15 OOS 09b8a8e7…, H1 W3 a44fd19b…, H4 W3 f3587bae…; twin and reference MD5s equal on every window. Base-rate table rebuilt from the new pins. Suite 558 passed. Evidence: backtest/research/rr_and_sell_campaign_2026-09-26.md (plus the 2026-09-18 loss-anatomy and wrong-direction reports it builds on). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -208,7 +208,7 @@ PARAMS_F = (
|
||||
"rsi_overbought", "rsi_oversold", "rsi_neutral_upper", "rsi_neutral_lower",
|
||||
"adx_strong_trend", "adx_very_strong", "adx_slope_emerging_threshold", "roc_threshold",
|
||||
"min_rr_ratio", "tp_tightening_factor", "round_trip_cost", "min_tp_cost_multiple",
|
||||
"min_sl_pips", "tp_floor_rr",
|
||||
"min_sl_pips", "tp_floor_rr", "tp_print_floor_rr",
|
||||
"tp_atr_multiplier", "sl_atr_multiplier", "min_atr_threshold", "v2_sl_atr_multiplier",
|
||||
"m5_min_abs_score", "m5_min_confirmation_score", "m5_sell_min_rsi",
|
||||
"m5_pullback_min_score", "m5_pullback_adx_min",
|
||||
@@ -332,6 +332,7 @@ def pack_params(platform_cfg, bt_cfg) -> Tuple[np.ndarray, np.ndarray, np.ndarra
|
||||
"min_rr_ratio": s.min_rr_ratio, "tp_tightening_factor": s.tp_tightening_factor,
|
||||
"round_trip_cost": s.round_trip_cost, "min_tp_cost_multiple": s.min_tp_cost_multiple,
|
||||
"min_sl_pips": s.min_sl_pips, "tp_floor_rr": s.tp_floor_rr,
|
||||
"tp_print_floor_rr": max(s.tp_floor_rr, getattr(s, "tp_print_floor_rr", 0.0)),
|
||||
"tp_atr_multiplier": x.tp_atr_multiplier, "sl_atr_multiplier": x.sl_atr_multiplier,
|
||||
"min_atr_threshold": x.min_atr_threshold, "v2_sl_atr_multiplier": x.v2_sl_atr_multiplier,
|
||||
"m5_min_abs_score": x.m5_min_abs_score,
|
||||
@@ -1804,11 +1805,20 @@ void fb2_aggregate(const double* __restrict__ open_p, const double* __restrict__
|
||||
tp1 = price + (tp1 - price) * tfac;
|
||||
tp2 = price + (tp2 - price) * tfac;
|
||||
const double sl_distance = fabs(price - sl_);
|
||||
const double tp_distance = fabs(tp1 - price);
|
||||
const double rr = (sl_distance > 0.0) ? tp_distance / sl_distance : 0.0;
|
||||
double tp_distance = fabs(tp1 - price);
|
||||
double rr = (sl_distance > 0.0) ? tp_distance / sl_distance : 0.0;
|
||||
if (!(rr < min_rr - 1e-9)) {
|
||||
if (tp_distance < min_tp) { WARN(W_spread_gate_atr, tp_distance); }
|
||||
else {
|
||||
{ // printed-target floor AFTER the gates (signal_aggregator 2026-09-26)
|
||||
const double floor_dist = sl_distance * PF[PF_tp_print_floor_rr];
|
||||
if (tp_distance < floor_dist) {
|
||||
tp_distance = floor_dist;
|
||||
if (is_buy) { tp1 = price + floor_dist; tp2 = price + floor_dist * 1.5; }
|
||||
else { tp1 = price - floor_dist; tp2 = price - floor_dist * 1.5; }
|
||||
rr = tp_distance / sl_distance;
|
||||
}
|
||||
}
|
||||
strategy = STRAT_XAU_ATR; direction = is_buy ? 1 : -1;
|
||||
setup_entry = price;
|
||||
setup_sl = fb2_pyround(sl_, 100.0);
|
||||
@@ -1865,11 +1875,20 @@ void fb2_aggregate(const double* __restrict__ open_p, const double* __restrict__
|
||||
tp1 = entry + (tp1 - entry) * tfac;
|
||||
tp2 = entry + (tp2 - entry) * tfac;
|
||||
if (is_buy) tp2 = PYMAX(tp2, tp1 + atr); else tp2 = PYMIN(tp2, tp1 - atr);
|
||||
const double tp1_distance = fabs(tp1 - entry);
|
||||
const double rr = (sl_distance > 0.0) ? tp1_distance / sl_distance : 0.0;
|
||||
double tp1_distance = fabs(tp1 - entry);
|
||||
double rr = (sl_distance > 0.0) ? tp1_distance / sl_distance : 0.0;
|
||||
if (!(rr < min_rr - 1e-9)) {
|
||||
if (tp1_distance < min_tp) { WARN(W_spread_gate_generic, tp1_distance); }
|
||||
else {
|
||||
{ // printed-target floor AFTER the gates (signal_aggregator 2026-09-26)
|
||||
const double floor_dist = sl_distance * PF[PF_tp_print_floor_rr];
|
||||
if (tp1_distance < floor_dist) {
|
||||
tp1_distance = floor_dist;
|
||||
if (is_buy) { tp1 = entry + floor_dist; tp2 = PYMAX(tp2, tp1 + atr); }
|
||||
else { tp1 = entry - floor_dist; tp2 = PYMIN(tp2, tp1 - atr); }
|
||||
rr = tp1_distance / sl_distance;
|
||||
}
|
||||
}
|
||||
strategy = STRAT_GENERIC; direction = is_buy ? 1 : -1;
|
||||
setup_entry = entry; setup_sl = sl_price; setup_tp1 = tp1; setup_tp2 = tp2;
|
||||
rr_rounded = fb2_pyround(rr, 100.0);
|
||||
@@ -2005,8 +2024,18 @@ void fb2_aggregate(const double* __restrict__ open_p, const double* __restrict__
|
||||
sl_dist = PYMAX((hit.anchor + 0.5 * atr) - entry, min_sl_price);
|
||||
sl_ = entry + sl_dist; tp1 = entry - height; tp2 = entry - 1.5 * height;
|
||||
}
|
||||
const double rr = (sl_dist > 0.0) ? height / sl_dist : 0.0;
|
||||
double rr = (sl_dist > 0.0) ? height / sl_dist : 0.0;
|
||||
if (!(rr < min_rr - 1e-9) && !(height < min_tp)) {
|
||||
{ // printed-target floor AFTER the gates (signal_aggregator 2026-09-26)
|
||||
double tp1_dist = height;
|
||||
const double floor_dist = sl_dist * PF[PF_tp_print_floor_rr];
|
||||
if (tp1_dist < floor_dist) {
|
||||
tp1_dist = floor_dist;
|
||||
if (is_buy) { tp1 = entry + floor_dist; tp2 = entry + 1.5 * floor_dist; }
|
||||
else { tp1 = entry - floor_dist; tp2 = entry - 1.5 * floor_dist; }
|
||||
rr = tp1_dist / sl_dist;
|
||||
}
|
||||
}
|
||||
strategy = STRAT_XAU_CP; direction = hit.dir;
|
||||
setup_entry = entry; setup_sl = sl_; setup_tp1 = tp1; setup_tp2 = tp2;
|
||||
rr_rounded = fb2_pyround(rr, 100.0);
|
||||
|
||||
Reference in New Issue
Block a user