fix: align production defaults and close review parity gaps
Ship greenfield min_rr=2.0 and conf=0, read-only Structural S/R, indicator cache invalidation, and UI/gate language that treats GTL as screening not exit. Align strategy_rank missing-vol fallback live vs backtest, single-source PRIMARY_TARGET_MIN_RR, expand prod parity tests, and drop dead FE clients.
This commit is contained in:
@@ -59,6 +59,7 @@ from app.services.admin_service import get_activation_config, update_setting
|
||||
from app.services.indicator_service import _extract_ohlcv, compute_atr
|
||||
from app.services.momentum_service import (
|
||||
STRATEGY_RANK_MOMENTUM_WEIGHT,
|
||||
blend_strategy_rank,
|
||||
compute_realized_vol_6m,
|
||||
)
|
||||
from app.services.outcome_service import (
|
||||
@@ -77,6 +78,7 @@ from app.services.qualification import (
|
||||
setup_qualifies,
|
||||
)
|
||||
from app.services.recommendation_service import (
|
||||
PRIMARY_TARGET_MIN_RR,
|
||||
_choose_recommended_action,
|
||||
_classify_by_probability,
|
||||
_prune_floor_pinned_targets,
|
||||
@@ -337,11 +339,11 @@ def _window_setups(
|
||||
targets = _prune_floor_pinned_targets(targets)
|
||||
primary = _select_primary_target(
|
||||
targets,
|
||||
min_rr=1.5,
|
||||
min_rr=PRIMARY_TARGET_MIN_RR,
|
||||
)
|
||||
if primary is None:
|
||||
continue
|
||||
# Flag the primary so qualification's EV uses the primary target's
|
||||
# Flag the primary so qualification uses the primary target's
|
||||
# probability (matching production's enhance_trade_setup).
|
||||
for t in targets:
|
||||
t["is_primary"] = t is primary
|
||||
@@ -1265,15 +1267,27 @@ def _assign_weighted_blend(
|
||||
primary_weight: float,
|
||||
secondary_key: str,
|
||||
) -> None:
|
||||
secondary_weight = 1.0 - primary_weight
|
||||
"""Blend ranks; fall back to primary when secondary is missing.
|
||||
|
||||
Matches live ``blend_strategy_rank`` for the production 80/20 key: a name
|
||||
with residual momentum but no vol history keeps its mom percentile instead
|
||||
of ranking as 0 / None at the bottom of the book.
|
||||
"""
|
||||
for c in candidates:
|
||||
primary = c.get(primary_key)
|
||||
secondary = c.get(secondary_key)
|
||||
c[output_key] = (
|
||||
primary * primary_weight + secondary * secondary_weight
|
||||
if primary is not None and secondary is not None
|
||||
else None
|
||||
)
|
||||
# Production weight path: reuse the shared helper so live/sim cannot drift.
|
||||
if primary_weight == STRATEGY_RANK_MOMENTUM_WEIGHT:
|
||||
c[output_key] = blend_strategy_rank(
|
||||
None if primary is None else float(primary),
|
||||
None if secondary is None else float(secondary),
|
||||
momentum_weight=primary_weight,
|
||||
)
|
||||
continue
|
||||
if primary is not None and secondary is not None:
|
||||
c[output_key] = primary * primary_weight + secondary * (1.0 - primary_weight)
|
||||
else:
|
||||
c[output_key] = primary
|
||||
|
||||
|
||||
def _assign_residual_low_vol_blend(candidates: list[dict]) -> None:
|
||||
|
||||
Reference in New Issue
Block a user