Add attention-aware PEAD caps and promote step75

main
I Luk Kim 5 months ago
parent b507fbf499
commit 02542248b7

@ -10,6 +10,8 @@ from collections import defaultdict
from pathlib import Path
from typing import Any
import requests
from libs.backtest.allocator import build_planned_order
from libs.backtest.artifacts import create_run_directory, write_all_artifacts
from libs.backtest.domain import (
@ -37,6 +39,7 @@ from libs.backtest.snapshot_store import SnapshotStore
from libs.backtest.splits import generate_walk_forward_windows
from libs.common.logging import get_logger
from libs.common.time_utils import utc_now
from libs.oracle_client.models import EventAttentionResponse
logger = get_logger(__name__)
@ -73,6 +76,17 @@ class BacktestRunner:
self.initial_equity = initial_equity
self.enable_engine_analysis = enable_engine_analysis
self._active_strategy_engines = self.config.get_active_strategy_engines()
self._attention_cache: dict[tuple[str, dt.date], EventAttentionResponse | None] = {}
self._attention_base_url: str | None = None
self._attention_session: requests.Session | None = None
if any(self._engine_requires_attention(engine) for engine in self.config.get_strategy_engines()):
from libs.common.config import get_settings
settings = get_settings()
self._attention_base_url = settings.stock_oracle_url.rstrip("/")
session = requests.Session()
session.headers.update({"User-Agent": "fithia2-backtester/1.0"})
self._attention_session = session
# Simulation state
self._equity = initial_equity
@ -430,6 +444,9 @@ class BacktestRunner:
engine_queues: dict[str, list[Candidate]] = {}
for engine in self._active_strategy_engines:
prelimit = self.config.signal.max_candidates_per_day
if self._engine_requires_attention(engine):
prelimit = max(prelimit * 5, prelimit)
raw_rows = (
self.store.get_candidates_for_reaction_date(date)
if engine.entry_timing_policy == "reaction_close"
@ -441,7 +458,9 @@ class BacktestRunner:
self.config.signal,
event_type_profiles=self.config.event_type_profiles or None,
strategy_engine=engine,
truncate_to=prelimit,
)
selected = self._apply_attention_filters(selected, engine)
if selected:
engine_queues[engine.engine_id] = selected
@ -454,6 +473,171 @@ class BacktestRunner:
return self._interleave_engine_candidates(engine_queues)
def _engine_requires_attention(self, engine: Any) -> bool:
return any(
value is not None
for value in (
engine.attention_min_wiki_spike_10d,
engine.attention_min_wiki_zscore_20d,
engine.attention_max_wiki_spike_10d,
engine.attention_max_wiki_zscore_20d,
engine.attention_min_article_count_3d,
engine.attention_min_us_article_count_3d,
engine.attention_min_resolver_confidence,
)
)
def _engine_requires_attention_data(self, engine: Any) -> bool:
"""Return True when the engine has at least one minimum-style gate.
Minimum gates require an actual attention payload to validate, while
maximum-only caps can treat missing data as "no veto".
"""
return any(
value is not None
for value in (
engine.attention_min_wiki_spike_10d,
engine.attention_min_wiki_zscore_20d,
engine.attention_min_article_count_3d,
engine.attention_min_us_article_count_3d,
engine.attention_min_resolver_confidence,
)
)
def _apply_attention_filters(
self,
candidates: list[Candidate],
engine: Any,
) -> list[Candidate]:
if not candidates or not self._engine_requires_attention(engine):
return candidates[: self.config.signal.max_candidates_per_day]
filtered: list[Candidate] = []
requires_data = self._engine_requires_attention_data(engine)
for candidate in candidates:
attention = self._get_event_attention(candidate)
if attention is None:
if not requires_data:
filtered.append(candidate)
continue
if not self._passes_attention_filters(engine, attention):
continue
filtered.append(self._attach_attention_features(candidate, attention))
filtered = rank_candidates(filtered)
return filtered[: self.config.signal.max_candidates_per_day]
def _get_event_attention(self, candidate: Candidate) -> EventAttentionResponse | None:
event_date = candidate.event_date or candidate.reaction_date
cache_key = (candidate.symbol, event_date)
if cache_key in self._attention_cache:
return self._attention_cache[cache_key]
if not self._attention_base_url or self._attention_session is None:
self._attention_cache[cache_key] = None
return None
try:
response = self._attention_session.get(
f"{self._attention_base_url}/api/v1/attention/event/{candidate.symbol}",
params={"event_date": event_date.isoformat()},
timeout=30,
)
if response.status_code >= 400:
logger.debug(
"attention_fetch_failed",
symbol=candidate.symbol,
event_date=event_date.isoformat(),
status_code=response.status_code,
)
self._attention_cache[cache_key] = None
return None
payload = EventAttentionResponse.model_validate(response.json())
except Exception as exc:
logger.warning(
"attention_fetch_error",
symbol=candidate.symbol,
event_date=event_date.isoformat(),
error=str(exc),
)
self._attention_cache[cache_key] = None
return None
self._attention_cache[cache_key] = payload
return payload
def _passes_attention_filters(
self,
engine: Any,
attention: EventAttentionResponse,
) -> bool:
if (
engine.attention_min_wiki_spike_10d is not None
and (
attention.wiki.spike_10d is None
or attention.wiki.spike_10d < engine.attention_min_wiki_spike_10d
)
):
return False
if (
engine.attention_min_wiki_zscore_20d is not None
and (
attention.wiki.zscore_20d is None
or attention.wiki.zscore_20d < engine.attention_min_wiki_zscore_20d
)
):
return False
if (
engine.attention_max_wiki_spike_10d is not None
and (
attention.wiki.spike_10d is not None
and attention.wiki.spike_10d > engine.attention_max_wiki_spike_10d
)
):
return False
if (
engine.attention_max_wiki_zscore_20d is not None
and (
attention.wiki.zscore_20d is not None
and attention.wiki.zscore_20d > engine.attention_max_wiki_zscore_20d
)
):
return False
if (
engine.attention_min_article_count_3d is not None
and attention.news.article_count_3d < engine.attention_min_article_count_3d
):
return False
if (
engine.attention_min_us_article_count_3d is not None
and attention.news.us_article_count_3d < engine.attention_min_us_article_count_3d
):
return False
if (
engine.attention_min_resolver_confidence is not None
and attention.entity.resolver_confidence < engine.attention_min_resolver_confidence
):
return False
return True
def _attach_attention_features(
self,
candidate: Candidate,
attention: EventAttentionResponse,
) -> Candidate:
features = dict(candidate.features)
features.update(
{
"attention_wiki_spike_10d": attention.wiki.spike_10d,
"attention_wiki_zscore_20d": attention.wiki.zscore_20d,
"attention_article_count_3d": attention.news.article_count_3d,
"attention_us_article_count_3d": attention.news.us_article_count_3d,
"attention_gdelt_status": attention.news.gdelt_status,
"attention_resolver_confidence": attention.entity.resolver_confidence,
}
)
return candidate.model_copy(update={"features": features})
def _interleave_engine_candidates(
self,
engine_queues: dict[str, list[Candidate]],

@ -0,0 +1,84 @@
{
"experiment_name": "pead_midcap_step68_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_acswiki115",
"dataset_snapshot_id": "midcap-filtered",
"description": "Step 68: Step66 plus a minimum wiki attention spike of 1.15x on the after-close short sleeve.",
"base_config": "configs/backtest/defaults.json",
"overrides": {
"strategy_engine_selection_mode": "global_score",
"event_type_profiles": {
"earnings_release": {"enabled": true, "direction_filter": "any", "max_holding_days_override": 7},
"guidance_update": {"enabled": false},
"management_change": {"enabled": false},
"material_contract": {"enabled": false},
"unknown": {"enabled": false},
"other_material_event": {"enabled": false}
},
"signal": {
"scoring_model": "pead",
"pead_reaction_threshold": 0.10,
"pead_volume_threshold": 2.0,
"score_threshold": 0.65,
"max_candidates_per_day": 4
},
"execution": {
"max_holding_days": 7,
"target_1_fraction": 1.0
},
"risk": {
"max_positions": 8,
"max_positions_per_sector": 8,
"max_daily_new_risk_pct": 0.04,
"cooldown_after_loss_streak": 0,
"cooldown_days": 0,
"veto_oneoff_penalty": 1.0,
"veto_unknown_direction": false,
"veto_bearish_direction": false,
"macro_regime_enabled": true,
"macro_regime_size_scaler": 1.0
}
},
"strategy_engines": [
{
"engine_id": "earnings_same_day_short_step14_capped",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 1.0,
"reaction_day_return_min": -0.45,
"shadow_only": false
},
{
"engine_id": "earnings_after_close_short_core_gap10_react12_acswiki115",
"event_types": ["earnings_release"],
"timing_class": "after_close",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 0.25,
"reaction_day_return_max": -0.12,
"gap_size_max": -0.10,
"attention_min_wiki_spike_10d": 1.15,
"shadow_only": false
},
{
"engine_id": "earnings_same_day_long_close12_gap10_trend",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "long_only",
"entry_timing_policy": "reaction_close",
"max_holding_days": 12,
"engine_risk_budget_pct": 0.25,
"gap_size_min": 0.10,
"target_atr_multiplier_override": 2.5,
"target_1_fraction_override": 0.33,
"trailing_model_override": "pct_10",
"trailing_warmup_days_override": 2,
"shadow_only": false
}
],
"splits": [],
"tags": ["pead", "midcap", "step68", "short_core", "attention", "wiki115", "after_close_short"],
"notes": null
}

@ -0,0 +1,84 @@
{
"experiment_name": "pead_midcap_step69_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_acswiki125",
"dataset_snapshot_id": "midcap-filtered",
"description": "Step 69: Step66 plus a minimum wiki attention spike of 1.25x on the after-close short sleeve.",
"base_config": "configs/backtest/defaults.json",
"overrides": {
"strategy_engine_selection_mode": "global_score",
"event_type_profiles": {
"earnings_release": {"enabled": true, "direction_filter": "any", "max_holding_days_override": 7},
"guidance_update": {"enabled": false},
"management_change": {"enabled": false},
"material_contract": {"enabled": false},
"unknown": {"enabled": false},
"other_material_event": {"enabled": false}
},
"signal": {
"scoring_model": "pead",
"pead_reaction_threshold": 0.10,
"pead_volume_threshold": 2.0,
"score_threshold": 0.65,
"max_candidates_per_day": 4
},
"execution": {
"max_holding_days": 7,
"target_1_fraction": 1.0
},
"risk": {
"max_positions": 8,
"max_positions_per_sector": 8,
"max_daily_new_risk_pct": 0.04,
"cooldown_after_loss_streak": 0,
"cooldown_days": 0,
"veto_oneoff_penalty": 1.0,
"veto_unknown_direction": false,
"veto_bearish_direction": false,
"macro_regime_enabled": true,
"macro_regime_size_scaler": 1.0
}
},
"strategy_engines": [
{
"engine_id": "earnings_same_day_short_step14_capped",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 1.0,
"reaction_day_return_min": -0.45,
"shadow_only": false
},
{
"engine_id": "earnings_after_close_short_core_gap10_react12_acswiki125",
"event_types": ["earnings_release"],
"timing_class": "after_close",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 0.25,
"reaction_day_return_max": -0.12,
"gap_size_max": -0.10,
"attention_min_wiki_spike_10d": 1.25,
"shadow_only": false
},
{
"engine_id": "earnings_same_day_long_close12_gap10_trend",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "long_only",
"entry_timing_policy": "reaction_close",
"max_holding_days": 12,
"engine_risk_budget_pct": 0.25,
"gap_size_min": 0.10,
"target_atr_multiplier_override": 2.5,
"target_1_fraction_override": 0.33,
"trailing_model_override": "pct_10",
"trailing_warmup_days_override": 2,
"shadow_only": false
}
],
"splits": [],
"tags": ["pead", "midcap", "step69", "short_core", "attention", "wiki125", "after_close_short"],
"notes": null
}

@ -0,0 +1,84 @@
{
"experiment_name": "pead_midcap_step70_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdswiki115",
"dataset_snapshot_id": "midcap-filtered",
"description": "Step 70: Step66 plus a minimum wiki attention spike of 1.15x on the same-day short sleeve.",
"base_config": "configs/backtest/defaults.json",
"overrides": {
"strategy_engine_selection_mode": "global_score",
"event_type_profiles": {
"earnings_release": {"enabled": true, "direction_filter": "any", "max_holding_days_override": 7},
"guidance_update": {"enabled": false},
"management_change": {"enabled": false},
"material_contract": {"enabled": false},
"unknown": {"enabled": false},
"other_material_event": {"enabled": false}
},
"signal": {
"scoring_model": "pead",
"pead_reaction_threshold": 0.10,
"pead_volume_threshold": 2.0,
"score_threshold": 0.65,
"max_candidates_per_day": 4
},
"execution": {
"max_holding_days": 7,
"target_1_fraction": 1.0
},
"risk": {
"max_positions": 8,
"max_positions_per_sector": 8,
"max_daily_new_risk_pct": 0.04,
"cooldown_after_loss_streak": 0,
"cooldown_days": 0,
"veto_oneoff_penalty": 1.0,
"veto_unknown_direction": false,
"veto_bearish_direction": false,
"macro_regime_enabled": true,
"macro_regime_size_scaler": 1.0
}
},
"strategy_engines": [
{
"engine_id": "earnings_same_day_short_step14_capped_sdswiki115",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 1.0,
"reaction_day_return_min": -0.45,
"attention_min_wiki_spike_10d": 1.15,
"shadow_only": false
},
{
"engine_id": "earnings_after_close_short_core_gap10_react12",
"event_types": ["earnings_release"],
"timing_class": "after_close",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 0.25,
"reaction_day_return_max": -0.12,
"gap_size_max": -0.10,
"shadow_only": false
},
{
"engine_id": "earnings_same_day_long_close12_gap10_trend",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "long_only",
"entry_timing_policy": "reaction_close",
"max_holding_days": 12,
"engine_risk_budget_pct": 0.25,
"gap_size_min": 0.10,
"target_atr_multiplier_override": 2.5,
"target_1_fraction_override": 0.33,
"trailing_model_override": "pct_10",
"trailing_warmup_days_override": 2,
"shadow_only": false
}
],
"splits": [],
"tags": ["pead", "midcap", "step70", "short_core", "attention", "wiki115", "same_day_short"],
"notes": null
}

@ -0,0 +1,84 @@
{
"experiment_name": "pead_midcap_step71_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax13",
"dataset_snapshot_id": "midcap-filtered",
"description": "Step 71: Step66 plus a maximum wiki attention spike of 1.30x on the same-day long sleeve.",
"base_config": "configs/backtest/defaults.json",
"overrides": {
"strategy_engine_selection_mode": "global_score",
"event_type_profiles": {
"earnings_release": {"enabled": true, "direction_filter": "any", "max_holding_days_override": 7},
"guidance_update": {"enabled": false},
"management_change": {"enabled": false},
"material_contract": {"enabled": false},
"unknown": {"enabled": false},
"other_material_event": {"enabled": false}
},
"signal": {
"scoring_model": "pead",
"pead_reaction_threshold": 0.10,
"pead_volume_threshold": 2.0,
"score_threshold": 0.65,
"max_candidates_per_day": 4
},
"execution": {
"max_holding_days": 7,
"target_1_fraction": 1.0
},
"risk": {
"max_positions": 8,
"max_positions_per_sector": 8,
"max_daily_new_risk_pct": 0.04,
"cooldown_after_loss_streak": 0,
"cooldown_days": 0,
"veto_oneoff_penalty": 1.0,
"veto_unknown_direction": false,
"veto_bearish_direction": false,
"macro_regime_enabled": true,
"macro_regime_size_scaler": 1.0
}
},
"strategy_engines": [
{
"engine_id": "earnings_same_day_short_step14_capped",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 1.0,
"reaction_day_return_min": -0.45,
"shadow_only": false
},
{
"engine_id": "earnings_after_close_short_core_gap10_react12",
"event_types": ["earnings_release"],
"timing_class": "after_close",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 0.25,
"reaction_day_return_max": -0.12,
"gap_size_max": -0.10,
"shadow_only": false
},
{
"engine_id": "earnings_same_day_long_close12_gap10_trend_wikimax13",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "long_only",
"entry_timing_policy": "reaction_close",
"max_holding_days": 12,
"engine_risk_budget_pct": 0.25,
"gap_size_min": 0.10,
"attention_max_wiki_spike_10d": 1.30,
"target_atr_multiplier_override": 2.5,
"target_1_fraction_override": 0.33,
"trailing_model_override": "pct_10",
"trailing_warmup_days_override": 2,
"shadow_only": false
}
],
"splits": [],
"tags": ["pead", "midcap", "step71", "attention", "same_day_long", "wiki_max13"],
"notes": null
}

@ -0,0 +1,84 @@
{
"experiment_name": "pead_midcap_step72_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax15",
"dataset_snapshot_id": "midcap-filtered",
"description": "Step 72: Step66 plus a maximum wiki attention spike of 1.50x on the same-day long sleeve.",
"base_config": "configs/backtest/defaults.json",
"overrides": {
"strategy_engine_selection_mode": "global_score",
"event_type_profiles": {
"earnings_release": {"enabled": true, "direction_filter": "any", "max_holding_days_override": 7},
"guidance_update": {"enabled": false},
"management_change": {"enabled": false},
"material_contract": {"enabled": false},
"unknown": {"enabled": false},
"other_material_event": {"enabled": false}
},
"signal": {
"scoring_model": "pead",
"pead_reaction_threshold": 0.10,
"pead_volume_threshold": 2.0,
"score_threshold": 0.65,
"max_candidates_per_day": 4
},
"execution": {
"max_holding_days": 7,
"target_1_fraction": 1.0
},
"risk": {
"max_positions": 8,
"max_positions_per_sector": 8,
"max_daily_new_risk_pct": 0.04,
"cooldown_after_loss_streak": 0,
"cooldown_days": 0,
"veto_oneoff_penalty": 1.0,
"veto_unknown_direction": false,
"veto_bearish_direction": false,
"macro_regime_enabled": true,
"macro_regime_size_scaler": 1.0
}
},
"strategy_engines": [
{
"engine_id": "earnings_same_day_short_step14_capped",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 1.0,
"reaction_day_return_min": -0.45,
"shadow_only": false
},
{
"engine_id": "earnings_after_close_short_core_gap10_react12",
"event_types": ["earnings_release"],
"timing_class": "after_close",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 0.25,
"reaction_day_return_max": -0.12,
"gap_size_max": -0.10,
"shadow_only": false
},
{
"engine_id": "earnings_same_day_long_close12_gap10_trend_wikimax15",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "long_only",
"entry_timing_policy": "reaction_close",
"max_holding_days": 12,
"engine_risk_budget_pct": 0.25,
"gap_size_min": 0.10,
"attention_max_wiki_spike_10d": 1.50,
"target_atr_multiplier_override": 2.5,
"target_1_fraction_override": 0.33,
"trailing_model_override": "pct_10",
"trailing_warmup_days_override": 2,
"shadow_only": false
}
],
"splits": [],
"tags": ["pead", "midcap", "step72", "attention", "same_day_long", "wiki_max15"],
"notes": null
}

@ -0,0 +1,84 @@
{
"experiment_name": "pead_midcap_step73_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax17",
"dataset_snapshot_id": "midcap-filtered",
"description": "Step 73: Step66 plus a maximum wiki attention spike of 1.70x on the same-day long sleeve.",
"base_config": "configs/backtest/defaults.json",
"overrides": {
"strategy_engine_selection_mode": "global_score",
"event_type_profiles": {
"earnings_release": {"enabled": true, "direction_filter": "any", "max_holding_days_override": 7},
"guidance_update": {"enabled": false},
"management_change": {"enabled": false},
"material_contract": {"enabled": false},
"unknown": {"enabled": false},
"other_material_event": {"enabled": false}
},
"signal": {
"scoring_model": "pead",
"pead_reaction_threshold": 0.10,
"pead_volume_threshold": 2.0,
"score_threshold": 0.65,
"max_candidates_per_day": 4
},
"execution": {
"max_holding_days": 7,
"target_1_fraction": 1.0
},
"risk": {
"max_positions": 8,
"max_positions_per_sector": 8,
"max_daily_new_risk_pct": 0.04,
"cooldown_after_loss_streak": 0,
"cooldown_days": 0,
"veto_oneoff_penalty": 1.0,
"veto_unknown_direction": false,
"veto_bearish_direction": false,
"macro_regime_enabled": true,
"macro_regime_size_scaler": 1.0
}
},
"strategy_engines": [
{
"engine_id": "earnings_same_day_short_step14_capped",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 1.0,
"reaction_day_return_min": -0.45,
"shadow_only": false
},
{
"engine_id": "earnings_after_close_short_core_gap10_react12",
"event_types": ["earnings_release"],
"timing_class": "after_close",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 0.25,
"reaction_day_return_max": -0.12,
"gap_size_max": -0.10,
"shadow_only": false
},
{
"engine_id": "earnings_same_day_long_close12_gap10_trend_wikimax17",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "long_only",
"entry_timing_policy": "reaction_close",
"max_holding_days": 12,
"engine_risk_budget_pct": 0.25,
"gap_size_min": 0.10,
"attention_max_wiki_spike_10d": 1.70,
"target_atr_multiplier_override": 2.5,
"target_1_fraction_override": 0.33,
"trailing_model_override": "pct_10",
"trailing_warmup_days_override": 2,
"shadow_only": false
}
],
"splits": [],
"tags": ["pead", "midcap", "step73", "attention", "same_day_long", "wiki_max17"],
"notes": null
}

@ -0,0 +1,84 @@
{
"experiment_name": "pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20",
"dataset_snapshot_id": "midcap-filtered",
"description": "Step 74: Step66 plus a maximum wiki attention spike of 2.00x on the same-day long sleeve.",
"base_config": "configs/backtest/defaults.json",
"overrides": {
"strategy_engine_selection_mode": "global_score",
"event_type_profiles": {
"earnings_release": {"enabled": true, "direction_filter": "any", "max_holding_days_override": 7},
"guidance_update": {"enabled": false},
"management_change": {"enabled": false},
"material_contract": {"enabled": false},
"unknown": {"enabled": false},
"other_material_event": {"enabled": false}
},
"signal": {
"scoring_model": "pead",
"pead_reaction_threshold": 0.10,
"pead_volume_threshold": 2.0,
"score_threshold": 0.65,
"max_candidates_per_day": 4
},
"execution": {
"max_holding_days": 7,
"target_1_fraction": 1.0
},
"risk": {
"max_positions": 8,
"max_positions_per_sector": 8,
"max_daily_new_risk_pct": 0.04,
"cooldown_after_loss_streak": 0,
"cooldown_days": 0,
"veto_oneoff_penalty": 1.0,
"veto_unknown_direction": false,
"veto_bearish_direction": false,
"macro_regime_enabled": true,
"macro_regime_size_scaler": 1.0
}
},
"strategy_engines": [
{
"engine_id": "earnings_same_day_short_step14_capped",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 1.0,
"reaction_day_return_min": -0.45,
"shadow_only": false
},
{
"engine_id": "earnings_after_close_short_core_gap10_react12",
"event_types": ["earnings_release"],
"timing_class": "after_close",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 0.25,
"reaction_day_return_max": -0.12,
"gap_size_max": -0.10,
"shadow_only": false
},
{
"engine_id": "earnings_same_day_long_close12_gap10_trend_wikimax20",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "long_only",
"entry_timing_policy": "reaction_close",
"max_holding_days": 12,
"engine_risk_budget_pct": 0.25,
"gap_size_min": 0.10,
"attention_max_wiki_spike_10d": 2.00,
"target_atr_multiplier_override": 2.5,
"target_1_fraction_override": 0.33,
"trailing_model_override": "pct_10",
"trailing_warmup_days_override": 2,
"shadow_only": false
}
],
"splits": [],
"tags": ["pead", "midcap", "step74", "attention", "same_day_long", "wiki_max20"],
"notes": null
}

@ -0,0 +1,84 @@
{
"experiment_name": "pead_midcap_step75_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax25",
"dataset_snapshot_id": "midcap-filtered",
"description": "Step 75: Step66 plus a maximum wiki attention spike of 2.50x on the same-day long sleeve.",
"base_config": "configs/backtest/defaults.json",
"overrides": {
"strategy_engine_selection_mode": "global_score",
"event_type_profiles": {
"earnings_release": {"enabled": true, "direction_filter": "any", "max_holding_days_override": 7},
"guidance_update": {"enabled": false},
"management_change": {"enabled": false},
"material_contract": {"enabled": false},
"unknown": {"enabled": false},
"other_material_event": {"enabled": false}
},
"signal": {
"scoring_model": "pead",
"pead_reaction_threshold": 0.10,
"pead_volume_threshold": 2.0,
"score_threshold": 0.65,
"max_candidates_per_day": 4
},
"execution": {
"max_holding_days": 7,
"target_1_fraction": 1.0
},
"risk": {
"max_positions": 8,
"max_positions_per_sector": 8,
"max_daily_new_risk_pct": 0.04,
"cooldown_after_loss_streak": 0,
"cooldown_days": 0,
"veto_oneoff_penalty": 1.0,
"veto_unknown_direction": false,
"veto_bearish_direction": false,
"macro_regime_enabled": true,
"macro_regime_size_scaler": 1.0
}
},
"strategy_engines": [
{
"engine_id": "earnings_same_day_short_step14_capped",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 1.0,
"reaction_day_return_min": -0.45,
"shadow_only": false
},
{
"engine_id": "earnings_after_close_short_core_gap10_react12",
"event_types": ["earnings_release"],
"timing_class": "after_close",
"direction": "short_only",
"entry_timing_policy": "next_open",
"max_holding_days": 7,
"engine_risk_budget_pct": 0.25,
"reaction_day_return_max": -0.12,
"gap_size_max": -0.10,
"shadow_only": false
},
{
"engine_id": "earnings_same_day_long_close12_gap10_trend_wikimax25",
"event_types": ["earnings_release"],
"timing_class": "same_day",
"direction": "long_only",
"entry_timing_policy": "reaction_close",
"max_holding_days": 12,
"engine_risk_budget_pct": 0.25,
"gap_size_min": 0.10,
"attention_max_wiki_spike_10d": 2.50,
"target_atr_multiplier_override": 2.5,
"target_1_fraction_override": 0.33,
"trailing_model_override": "pct_10",
"trailing_warmup_days_override": 2,
"shadow_only": false
}
],
"splits": [],
"tags": ["pead", "midcap", "step75", "attention", "same_day_long", "wiki_max25"],
"notes": null
}

@ -1,71 +1,85 @@
# Strategy Improvement Leaderboard
_Updated: 2026-03-17T10:37:12.332837+00:00_
_Updated: 2026-03-18T00:26:47.429362+00:00_
| # | Experiment | SQS | [T]PF | [T]Ret% | [T]WR | [T]Sharpe | [T]DD% | [T]N | [T]Gross% | [T]Net% | [T]DIM% | [V]PF | [V]Ret% | [V]WR | [V]Sharpe | [V]DD% | [V]N | [V]Gross% | [V]Net% | [V]DIM% | Date |
|---|-----------|-----|-------|---------|-------|-----------|--------|------|-----------|---------|---------|-------|---------|-------|-----------|--------|------|-----------|---------|---------|------|
| 1 | pead_midcap_step56_short_core_macro_block_crashcap_gap10_interleave_longtrend25 | 51.3 | 4.03 | +1.1 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 51.1 | 4.82 | +1.9 | 68% | 4.0 | 0.6 | 28 | 4.2 | -2.7 | 56.1 | 2026-03-17 |
| 2 | pead_midcap_step62_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10 | 50.9 | 3.69 | +1.0 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 48.9 | 4.64 | +1.8 | 69% | 4.5 | 0.4 | 26 | 3.5 | -2.0 | 49.1 | 2026-03-17 |
| 3 | pead_midcap_step66_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12 | 50.9 | 3.69 | +1.0 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 48.9 | 4.64 | +1.8 | 69% | 4.5 | 0.4 | 26 | 3.5 | -2.0 | 49.1 | 2026-03-17 |
| 4 | pead_midcap_step64_short_core_macro_block_crashcap_gap10_interleave_max4_acsgap10 | 50.6 | 3.69 | +1.0 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 48.9 | 4.33 | +1.7 | 65% | 3.7 | 0.6 | 26 | 3.8 | -2.3 | 49.1 | 2026-03-17 |
| 5 | pead_midcap_step55_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25 | 49.8 | 3.40 | +1.0 | 78% | 3.1 | 0.2 | 23 | 3.0 | -2.0 | 53.2 | 4.62 | +1.9 | 71% | 4.5 | 0.3 | 28 | 3.8 | -2.4 | 56.1 | 2026-03-17 |
| 6 | pead_midcap_step52_short_core_macro_block_crashcap_gap10 | 49.8 | 3.35 | +1.0 | 77% | 3.0 | 0.2 | 22 | 2.9 | -2.2 | 53.2 | 5.66 | +1.8 | 72% | 4.8 | 0.2 | 25 | 3.6 | -2.6 | 56.1 | 2026-03-17 |
| 7 | pead_midcap_step48_short_core_macro_block_nolong | 46.9 | 3.40 | +0.8 | 80% | 2.4 | 0.4 | 20 | 2.6 | +2.6 | 52.2 | 5.73 | +1.3 | 70% | 3.4 | 0.3 | 20 | 3.3 | +3.3 | 51.8 | 2026-03-17 |
| 8 | pead_midcap_step58_short_core_macro_block_crashcap_gap7_longtrend12_sdlong25 | 46.6 | 2.76 | +0.9 | 74% | 2.8 | 0.2 | 23 | 3.2 | -1.3 | 53.2 | 2.89 | +1.6 | 69% | 3.6 | 0.5 | 29 | 4.0 | -2.0 | 56.1 | 2026-03-17 |
| 9 | pead_midcap_step54_short_core_macro_block_crashcap_gap10_longtrend12 | 46.5 | 2.99 | +0.9 | 77% | 2.5 | 0.3 | 22 | 2.9 | -2.2 | 53.2 | 6.10 | +2.0 | 73% | 4.7 | 0.2 | 26 | 3.6 | -2.6 | 56.1 | 2026-03-17 |
| 10 | pead_midcap_step57_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4 | 46.5 | 2.66 | +0.9 | 75% | 2.9 | 0.2 | 24 | 3.2 | -2.2 | 53.2 | 4.44 | +1.9 | 69% | 4.5 | 0.3 | 29 | 3.9 | -2.5 | 56.1 | 2026-03-17 |
| 11 | pead_midcap_step46_short_core_macro_block_acshort12 | 45.8 | 4.52 | +1.3 | 71% | 3.6 | 0.3 | 21 | 2.1 | +2.1 | 40.4 | 2.44 | +1.3 | 69% | 3.2 | 0.4 | 26 | 4.0 | +4.0 | 57.9 | 2026-03-17 |
| 12 | pead_midcap_step36_balanced_sleeves_nofrac_aclong12_sdlong12 | 44.5 | 2.06 | +2.1 | 61% | 4.5 | 0.4 | 54 | 6.0 | +6.0 | 76.6 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 13 | pead_midcap_step51_short_core_macro_block_crashcap | 44.4 | 4.19 | +1.2 | 73% | 3.6 | 0.2 | 22 | 2.3 | -0.8 | 42.6 | 2.31 | +1.3 | 68% | 3.0 | 0.4 | 28 | 4.1 | -1.9 | 57.9 | 2026-03-17 |
| 14 | pead_midcap_step45_short_core_macro_block | 44.3 | 3.78 | +1.2 | 70% | 3.4 | 0.3 | 23 | 2.4 | +2.4 | 42.6 | 2.31 | +1.3 | 68% | 3.0 | 0.4 | 28 | 4.2 | +4.2 | 57.9 | 2026-03-17 |
| 15 | pead_midcap_step53_short_core_macro_block_crashcap_gap14 | 39.5 | 4.60 | +1.1 | 84% | 3.5 | 0.2 | 19 | 2.3 | +2.3 | 53.2 | 8.21 | +2.0 | 76% | 5.3 | 0.2 | 25 | 3.6 | +3.6 | 56.1 | 2026-03-17 |
| 16 | pead_midcap_step65_short_core_macro_block_crashcap_gap10_interleave_max4_acsgap12 | 38.3 | 3.60 | +0.9 | 79% | 3.2 | 0.2 | 19 | 1.9 | -0.9 | 38.3 | 4.56 | +1.5 | 67% | 4.0 | 0.5 | 24 | 3.4 | -1.9 | 47.4 | 2026-03-17 |
| 17 | pead_midcap_step63_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap12 | 38.2 | 3.60 | +0.9 | 79% | 3.2 | 0.2 | 19 | 1.9 | -0.9 | 38.3 | 5.27 | +1.8 | 71% | 4.9 | 0.3 | 24 | 3.1 | -1.6 | 45.6 | 2026-03-17 |
| 18 | pead_midcap_step67_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react14 | 38.2 | 3.60 | +0.9 | 79% | 3.2 | 0.2 | 19 | 1.9 | -0.9 | 38.3 | 5.33 | +1.8 | 72% | 4.4 | 0.5 | 25 | 3.2 | -1.7 | 47.4 | 2026-03-17 |
| 19 | pead_midcap_step50_same_day_short_long_macro_block | 36.2 | 3.21 | +0.8 | 60% | 2.7 | 0.4 | 15 | 1.6 | +1.6 | 38.3 | 2.21 | +1.0 | 65% | 2.7 | 0.3 | 20 | 3.4 | +3.4 | 43.9 | 2026-03-17 |
| 20 | pead_midcap_step30_balanced_sleeves_nofrac | 35.4 | 1.41 | +1.4 | 54% | 2.8 | 0.8 | 67 | 8.0 | +8.0 | 76.6 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 21 | pead_midcap_step47_short_core_macro_block_sdlong25 | 35.2 | 3.43 | +1.3 | 68% | 3.3 | 0.3 | 25 | 2.9 | +2.9 | 48.9 | 1.77 | +1.0 | 65% | 2.2 | 0.4 | 31 | 4.6 | +4.6 | 57.9 | 2026-03-17 |
| 22 | pead_midcap_step44_short_core_macro50 | 35.0 | 2.01 | +1.3 | 57% | 2.6 | 0.7 | 58 | 4.5 | -1.6 | 72.3 | 1.78 | +1.1 | 55% | 2.5 | 0.4 | 40 | 4.8 | -2.0 | 73.7 | 2026-03-17 |
| 23 | pead_midcap_step33_balanced_sleeves_nofrac_acshort6 | 35.0 | 1.47 | +1.2 | 52% | 2.3 | 0.7 | 48 | 6.2 | +6.2 | 70.2 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 24 | pead_midcap_step59_same_day_only_max4_longtrend25 | 33.2 | 2.61 | +0.6 | 69% | 2.3 | 0.3 | 13 | 1.4 | -0.5 | 31.9 | 6.63 | +1.9 | 73% | 4.5 | 0.4 | 22 | 3.9 | -2.4 | 42.1 | 2026-03-17 |
| 25 | pead_midcap_step60_same_day_only_interleave_max4_longtrend25 | 33.2 | 2.61 | +0.6 | 69% | 2.3 | 0.3 | 13 | 1.4 | -0.5 | 31.9 | 6.63 | +1.9 | 73% | 4.5 | 0.4 | 22 | 3.9 | -2.4 | 42.1 | 2026-03-17 |
| 26 | pead_midcap_step61_same_day_only_max5_longtrend25 | 33.2 | 2.61 | +0.6 | 69% | 2.3 | 0.3 | 13 | 1.4 | -0.5 | 31.9 | 6.63 | +1.9 | 73% | 4.5 | 0.4 | 22 | 3.9 | -2.4 | 42.1 | 2026-03-17 |
| 27 | pead_midcap_step43_short_core_sdlong25 | 31.7 | 1.66 | +1.5 | 57% | 2.0 | 1.3 | 58 | 7.1 | +7.1 | 72.3 | 1.46 | +1.0 | 56% | 1.9 | 0.6 | 45 | 6.2 | +6.2 | 73.7 | 2026-03-17 |
| 28 | pead_midcap_step41_short_core_sdlong12_acshort50 | 30.7 | 1.53 | +1.2 | 56% | 1.6 | 1.3 | 59 | 6.8 | +6.8 | 72.3 | 1.48 | +0.9 | 55% | 1.8 | 0.6 | 40 | 5.6 | +5.6 | 73.7 | 2026-03-17 |
| 29 | pead_midcap_step37_balanced_sleeves_aclong_vol3 | 30.6 | 1.38 | +1.2 | 54% | 2.5 | 0.8 | 63 | 7.5 | +7.5 | 76.6 | 1.38 | +1.1 | 51% | 1.8 | 0.9 | 57 | 7.9 | +7.9 | 77.2 | 2026-03-17 |
| 30 | pead_midcap_step42_short_core_only | 30.5 | 1.44 | +0.8 | 63% | 1.2 | 1.2 | 46 | 5.5 | +5.5 | 71.7 | 2.55 | +1.2 | 58% | 2.8 | 0.5 | 31 | 4.5 | +4.5 | 71.4 | 2026-03-17 |
| 31 | pead_midcap_step14_score65 | 29.9 | 1.22 | +0.7 | 57% | 1.3 | 0.9 | 72 | - | - | - | 1.40 | +1.0 | 56% | 1.6 | 0.7 | 66 | - | - | - | 2026-03-17 |
| 32 | pead_midcap_step18_nofrac | 29.4 | 1.23 | +0.8 | 52% | 1.4 | 0.9 | 64 | - | - | - | 1.46 | +1.2 | 47% | 1.9 | 0.6 | 55 | - | - | - | 2026-03-17 |
| 33 | pead_midcap_step31_balanced_sleeves_nofrac_acshort12 | 29.3 | 1.49 | +1.6 | 55% | 3.2 | 0.7 | 64 | 7.6 | +7.6 | 76.6 | 1.38 | +1.1 | 52% | 1.8 | 0.9 | 58 | 8.0 | +8.0 | 77.2 | 2026-03-17 |
| 34 | pead_midcap_step19_hold5 | 29.2 | 1.20 | +0.7 | 57% | 1.2 | 0.9 | 72 | - | - | - | 1.55 | +1.4 | 57% | 2.2 | 0.7 | 68 | - | - | - | 2026-03-17 |
| 35 | pead_midcap_step49_same_day_short_macro_block | 29.1 | 2.40 | +0.4 | 70% | 1.6 | 0.4 | 10 | 1.0 | +1.0 | 26.1 | 25.09 | +1.2 | 75% | 3.2 | 0.3 | 12 | 2.6 | +2.6 | 32.1 | 2026-03-17 |
| 36 | pead_midcap_step20_best3 | 28.7 | 1.22 | +0.7 | 52% | 1.3 | 0.9 | 64 | - | - | - | 1.61 | +1.6 | 48% | 2.5 | 0.6 | 56 | - | - | - | 2026-03-17 |
| 37 | pead_midcap_step40_short_core_sdlong12 | 28.6 | 1.77 | +1.5 | 58% | 2.2 | 1.1 | 55 | 6.4 | +6.4 | 72.3 | 1.48 | +0.9 | 55% | 1.8 | 0.6 | 40 | 5.6 | +5.6 | 73.7 | 2026-03-17 |
| 38 | pead_midcap_step17_target2 | 27.3 | 1.18 | +0.6 | 53% | 1.1 | 0.8 | 66 | - | - | - | 1.38 | +1.0 | 51% | 1.5 | 0.7 | 59 | - | - | - | 2026-03-17 |
| 39 | pead_midcap_step39_balanced_sleeves_sdlong12 | 27.0 | 1.50 | +1.5 | 55% | 3.4 | 0.5 | 62 | 7.4 | +7.4 | 76.6 | 1.38 | +1.0 | 51% | 1.7 | 0.9 | 53 | 7.5 | +7.5 | 77.2 | 2026-03-17 |
| 40 | pead_midcap_step27_sdlong_close7_budget25 | 26.4 | 1.17 | +0.6 | 54% | 0.9 | 1.3 | 68 | 8.5 | +8.5 | 72.3 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 41 | pead_midcap_step13_best | 26.3 | 1.12 | +0.4 | 55% | 0.8 | 0.9 | 75 | - | - | - | 1.61 | +1.6 | 59% | 2.2 | 0.7 | 70 | - | - | - | 2026-03-16 |
| 42 | pead_midcap_step23_sdlong_close7 | 24.9 | 1.13 | +0.5 | 54% | 0.7 | 1.4 | 69 | 8.6 | +8.6 | 72.3 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 43 | pead_midcap_step34_balanced_sleeves_nofrac_aclong25 | 23.9 | 1.62 | +1.8 | 56% | 3.8 | 0.6 | 62 | 7.4 | +7.4 | 76.6 | 1.30 | +0.9 | 51% | 1.4 | 0.9 | 57 | 7.9 | +7.9 | 77.2 | 2026-03-17 |
| 44 | pead_midcap_step16_react7_score65 | 23.8 | 0.97 | -0.1 | 56% | -0.2 | 1.6 | 89 | - | - | - | 2.01 | +2.8 | 63% | 3.7 | 0.8 | 83 | - | - | - | 2026-03-17 |
| 45 | pead_midcap_step5_maxcand3 | 23.4 | 0.95 | -0.2 | 54% | -0.4 | 1.4 | 96 | - | - | - | 2.08 | +3.3 | 65% | 4.0 | 1.1 | 89 | - | - | - | 2026-03-16 |
| 46 | pead_midcap_step38_balanced_sleeves_aclong_vol4 | 23.3 | 1.12 | +0.4 | 51% | 0.8 | 0.9 | 61 | 7.4 | +7.4 | 76.6 | 1.29 | +0.8 | 53% | 1.4 | 0.9 | 53 | 7.6 | +7.6 | 77.2 | 2026-03-17 |
| 47 | pead_midcap_step15_react7 | 23.0 | 0.94 | -0.3 | 55% | -0.5 | 1.6 | 91 | - | - | - | 1.89 | +2.6 | 62% | 3.5 | 0.9 | 84 | - | - | - | 2026-03-17 |
| 48 | pead_midcap_portfolio_v2 | 23.0 | 1.08 | +0.3 | 51% | 0.5 | 1.8 | 70 | 7.9 | +7.9 | 72.3 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 49 | pead_midcap_step11_score60 | 22.1 | 1.02 | +0.1 | 52% | 0.2 | 0.9 | 77 | - | - | - | 1.91 | +2.3 | 62% | 3.0 | 0.7 | 72 | - | - | - | 2026-03-16 |
| 50 | pead_midcap_step12_vol2x | 22.1 | 1.02 | +0.1 | 52% | 0.1 | 0.9 | 77 | - | - | - | 1.91 | +2.3 | 62% | 3.0 | 0.7 | 72 | - | - | - | 2026-03-16 |
| 51 | pead_midcap_step3_10pct | 21.9 | 1.00 | +0.0 | 50% | 0.0 | 1.4 | 98 | - | - | - | 1.66 | +2.0 | 60% | 2.9 | 0.7 | 78 | - | - | - | 2026-03-16 |
| 52 | pead_midcap_step10_short | 21.5 | 1.00 | -0.0 | 52% | -0.0 | 0.9 | 79 | - | - | - | 1.61 | +1.6 | 59% | 2.2 | 0.7 | 70 | - | - | - | 2026-03-16 |
| 53 | pead_midcap_step35_balanced_sleeves_nofrac_aclong12 | 21.2 | 2.01 | +2.2 | 61% | 4.2 | 0.4 | 56 | 6.2 | +1.1 | 76.6 | 1.24 | +0.7 | 51% | 1.2 | 0.9 | 53 | 7.5 | +1.6 | 77.2 | 2026-03-17 |
| 54 | pead_midcap_step2_notrail | 17.2 | 0.93 | -0.3 | 67% | -0.4 | 1.7 | 54 | - | - | - | 1.07 | +0.4 | 73% | 0.4 | 1.7 | 62 | - | - | - | 2026-03-16 |
| 55 | pead_midcap_step1_fixedr | 16.2 | 0.91 | -0.5 | 47% | -0.7 | 1.5 | 95 | - | - | - | 1.77 | +2.8 | 49% | 3.4 | 1.6 | 69 | - | - | - | 2026-03-16 |
| 56 | pead_midcap_combo_10pct_maxcand3 | 15.9 | 0.97 | -0.1 | 51% | -0.2 | 0.9 | 79 | - | - | - | 1.91 | +2.3 | 62% | 3.0 | 0.7 | 72 | - | - | - | 2026-03-16 |
| 57 | pead_midcap_step6_drift | 14.7 | 0.86 | -0.9 | 43% | -1.6 | 1.7 | 100 | - | - | - | 1.70 | +2.7 | 51% | 3.7 | 1.0 | 75 | - | - | - | 2026-03-16 |
| 58 | pead_midcap_step7_fixedr | 13.8 | 0.94 | -0.2 | 45% | -0.4 | 1.0 | 71 | - | - | - | 2.00 | +2.4 | 53% | 3.1 | 0.7 | 53 | - | - | - | 2026-03-16 |
| 59 | pead_midcap_step4_longonly | 12.2 | 0.84 | -0.8 | 45% | -1.2 | 1.4 | 78 | - | - | - | 1.43 | +1.5 | 61% | 1.7 | 1.6 | 76 | - | - | - | 2026-03-16 |
| 60 | pead_midcap_step8_nft | 11.5 | 0.65 | -1.8 | 41% | -3.0 | 2.2 | 71 | - | - | - | 1.55 | +1.8 | 46% | 2.4 | 1.0 | 57 | - | - | - | 2026-03-16 |
| 61 | pead_midcap_step9_stop2 | 11.4 | 0.77 | -1.7 | 45% | -1.8 | 2.5 | 71 | - | - | - | 1.81 | +3.2 | 53% | 2.8 | 1.2 | 53 | - | - | - | 2026-03-16 |
| 2 | pead_midcap_step75_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax25 | 51.1 | 3.69 | +1.0 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 48.9 | 5.15 | +1.9 | 73% | 4.6 | 0.3 | 26 | 3.5 | -2.0 | 49.1 | 2026-03-18 |
| 3 | pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20 | 51.1 | 3.69 | +1.0 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 48.9 | 5.15 | +1.9 | 73% | 4.6 | 0.3 | 26 | 3.5 | -2.0 | 49.1 | 2026-03-18 |
| 4 | pead_midcap_step62_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10 | 50.9 | 3.69 | +1.0 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 48.9 | 4.64 | +1.8 | 69% | 4.5 | 0.4 | 26 | 3.5 | -2.0 | 49.1 | 2026-03-17 |
| 5 | pead_midcap_step66_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12 | 50.9 | 3.69 | +1.0 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 48.9 | 4.64 | +1.8 | 69% | 4.5 | 0.4 | 26 | 3.5 | -2.0 | 49.1 | 2026-03-17 |
| 6 | pead_midcap_step64_short_core_macro_block_crashcap_gap10_interleave_max4_acsgap10 | 50.6 | 3.69 | +1.0 | 80% | 3.4 | 0.2 | 20 | 2.5 | -1.5 | 48.9 | 4.33 | +1.7 | 65% | 3.7 | 0.6 | 26 | 3.8 | -2.3 | 49.1 | 2026-03-17 |
| 7 | pead_midcap_step55_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25 | 49.8 | 3.40 | +1.0 | 78% | 3.1 | 0.2 | 23 | 3.0 | -2.0 | 53.2 | 4.62 | +1.9 | 71% | 4.5 | 0.3 | 28 | 3.8 | -2.4 | 56.1 | 2026-03-17 |
| 8 | pead_midcap_step52_short_core_macro_block_crashcap_gap10 | 49.8 | 3.35 | +1.0 | 77% | 3.0 | 0.2 | 22 | 2.9 | -2.2 | 53.2 | 5.66 | +1.8 | 72% | 4.8 | 0.2 | 25 | 3.6 | -2.6 | 56.1 | 2026-03-17 |
| 9 | pead_midcap_step48_short_core_macro_block_nolong | 46.9 | 3.40 | +0.8 | 80% | 2.4 | 0.4 | 20 | 2.6 | +2.6 | 52.2 | 5.73 | +1.3 | 70% | 3.4 | 0.3 | 20 | 3.3 | +3.3 | 51.8 | 2026-03-17 |
| 10 | pead_midcap_step58_short_core_macro_block_crashcap_gap7_longtrend12_sdlong25 | 46.6 | 2.76 | +0.9 | 74% | 2.8 | 0.2 | 23 | 3.2 | -1.3 | 53.2 | 2.89 | +1.6 | 69% | 3.6 | 0.5 | 29 | 4.0 | -2.0 | 56.1 | 2026-03-17 |
| 11 | pead_midcap_step54_short_core_macro_block_crashcap_gap10_longtrend12 | 46.5 | 2.99 | +0.9 | 77% | 2.5 | 0.3 | 22 | 2.9 | -2.2 | 53.2 | 6.10 | +2.0 | 73% | 4.7 | 0.2 | 26 | 3.6 | -2.6 | 56.1 | 2026-03-17 |
| 12 | pead_midcap_step57_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4 | 46.5 | 2.66 | +0.9 | 75% | 2.9 | 0.2 | 24 | 3.2 | -2.2 | 53.2 | 4.44 | +1.9 | 69% | 4.5 | 0.3 | 29 | 3.9 | -2.5 | 56.1 | 2026-03-17 |
| 13 | pead_midcap_step46_short_core_macro_block_acshort12 | 45.8 | 4.52 | +1.3 | 71% | 3.6 | 0.3 | 21 | 2.1 | +2.1 | 40.4 | 2.44 | +1.3 | 69% | 3.2 | 0.4 | 26 | 4.0 | +4.0 | 57.9 | 2026-03-17 |
| 14 | pead_midcap_step36_balanced_sleeves_nofrac_aclong12_sdlong12 | 44.5 | 2.06 | +2.1 | 61% | 4.5 | 0.4 | 54 | 6.0 | +6.0 | 76.6 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 15 | pead_midcap_step51_short_core_macro_block_crashcap | 44.4 | 4.19 | +1.2 | 73% | 3.6 | 0.2 | 22 | 2.3 | -0.8 | 42.6 | 2.31 | +1.3 | 68% | 3.0 | 0.4 | 28 | 4.1 | -1.9 | 57.9 | 2026-03-17 |
| 16 | pead_midcap_step45_short_core_macro_block | 44.3 | 3.78 | +1.2 | 70% | 3.4 | 0.3 | 23 | 2.4 | +2.4 | 42.6 | 2.31 | +1.3 | 68% | 3.0 | 0.4 | 28 | 4.2 | +4.2 | 57.9 | 2026-03-17 |
| 17 | pead_midcap_step53_short_core_macro_block_crashcap_gap14 | 39.5 | 4.60 | +1.1 | 84% | 3.5 | 0.2 | 19 | 2.3 | +2.3 | 53.2 | 8.21 | +2.0 | 76% | 5.3 | 0.2 | 25 | 3.6 | +3.6 | 56.1 | 2026-03-17 |
| 18 | pead_midcap_step65_short_core_macro_block_crashcap_gap10_interleave_max4_acsgap12 | 38.3 | 3.60 | +0.9 | 79% | 3.2 | 0.2 | 19 | 1.9 | -0.9 | 38.3 | 4.56 | +1.5 | 67% | 4.0 | 0.5 | 24 | 3.4 | -1.9 | 47.4 | 2026-03-17 |
| 19 | pead_midcap_step63_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap12 | 38.2 | 3.60 | +0.9 | 79% | 3.2 | 0.2 | 19 | 1.9 | -0.9 | 38.3 | 5.27 | +1.8 | 71% | 4.9 | 0.3 | 24 | 3.1 | -1.6 | 45.6 | 2026-03-17 |
| 20 | pead_midcap_step67_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react14 | 38.2 | 3.60 | +0.9 | 79% | 3.2 | 0.2 | 19 | 1.9 | -0.9 | 38.3 | 5.33 | +1.8 | 72% | 4.4 | 0.5 | 25 | 3.2 | -1.7 | 47.4 | 2026-03-17 |
| 21 | pead_midcap_step50_same_day_short_long_macro_block | 36.2 | 3.21 | +0.8 | 60% | 2.7 | 0.4 | 15 | 1.6 | +1.6 | 38.3 | 2.21 | +1.0 | 65% | 2.7 | 0.3 | 20 | 3.4 | +3.4 | 43.9 | 2026-03-17 |
| 22 | pead_midcap_step30_balanced_sleeves_nofrac | 35.4 | 1.41 | +1.4 | 54% | 2.8 | 0.8 | 67 | 8.0 | +8.0 | 76.6 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 23 | pead_midcap_step47_short_core_macro_block_sdlong25 | 35.2 | 3.43 | +1.3 | 68% | 3.3 | 0.3 | 25 | 2.9 | +2.9 | 48.9 | 1.77 | +1.0 | 65% | 2.2 | 0.4 | 31 | 4.6 | +4.6 | 57.9 | 2026-03-17 |
| 24 | pead_midcap_step44_short_core_macro50 | 35.0 | 2.01 | +1.3 | 57% | 2.6 | 0.7 | 58 | 4.5 | -1.6 | 72.3 | 1.78 | +1.1 | 55% | 2.5 | 0.4 | 40 | 4.8 | -2.0 | 73.7 | 2026-03-17 |
| 25 | pead_midcap_step33_balanced_sleeves_nofrac_acshort6 | 35.0 | 1.47 | +1.2 | 52% | 2.3 | 0.7 | 48 | 6.2 | +6.2 | 70.2 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 26 | pead_midcap_step59_same_day_only_max4_longtrend25 | 33.2 | 2.61 | +0.6 | 69% | 2.3 | 0.3 | 13 | 1.4 | -0.5 | 31.9 | 6.63 | +1.9 | 73% | 4.5 | 0.4 | 22 | 3.9 | -2.4 | 42.1 | 2026-03-17 |
| 27 | pead_midcap_step60_same_day_only_interleave_max4_longtrend25 | 33.2 | 2.61 | +0.6 | 69% | 2.3 | 0.3 | 13 | 1.4 | -0.5 | 31.9 | 6.63 | +1.9 | 73% | 4.5 | 0.4 | 22 | 3.9 | -2.4 | 42.1 | 2026-03-17 |
| 28 | pead_midcap_step61_same_day_only_max5_longtrend25 | 33.2 | 2.61 | +0.6 | 69% | 2.3 | 0.3 | 13 | 1.4 | -0.5 | 31.9 | 6.63 | +1.9 | 73% | 4.5 | 0.4 | 22 | 3.9 | -2.4 | 42.1 | 2026-03-17 |
| 29 | pead_midcap_step43_short_core_sdlong25 | 31.7 | 1.66 | +1.5 | 57% | 2.0 | 1.3 | 58 | 7.1 | +7.1 | 72.3 | 1.46 | +1.0 | 56% | 1.9 | 0.6 | 45 | 6.2 | +6.2 | 73.7 | 2026-03-17 |
| 30 | pead_midcap_step41_short_core_sdlong12_acshort50 | 30.7 | 1.53 | +1.2 | 56% | 1.6 | 1.3 | 59 | 6.8 | +6.8 | 72.3 | 1.48 | +0.9 | 55% | 1.8 | 0.6 | 40 | 5.6 | +5.6 | 73.7 | 2026-03-17 |
| 31 | pead_midcap_step37_balanced_sleeves_aclong_vol3 | 30.6 | 1.38 | +1.2 | 54% | 2.5 | 0.8 | 63 | 7.5 | +7.5 | 76.6 | 1.38 | +1.1 | 51% | 1.8 | 0.9 | 57 | 7.9 | +7.9 | 77.2 | 2026-03-17 |
| 32 | pead_midcap_step42_short_core_only | 30.5 | 1.44 | +0.8 | 63% | 1.2 | 1.2 | 46 | 5.5 | +5.5 | 71.7 | 2.55 | +1.2 | 58% | 2.8 | 0.5 | 31 | 4.5 | +4.5 | 71.4 | 2026-03-17 |
| 33 | pead_midcap_step14_score65 | 29.9 | 1.22 | +0.7 | 57% | 1.3 | 0.9 | 72 | - | - | - | 1.40 | +1.0 | 56% | 1.6 | 0.7 | 66 | - | - | - | 2026-03-17 |
| 34 | pead_midcap_step18_nofrac | 29.4 | 1.23 | +0.8 | 52% | 1.4 | 0.9 | 64 | - | - | - | 1.46 | +1.2 | 47% | 1.9 | 0.6 | 55 | - | - | - | 2026-03-17 |
| 35 | pead_midcap_step31_balanced_sleeves_nofrac_acshort12 | 29.3 | 1.49 | +1.6 | 55% | 3.2 | 0.7 | 64 | 7.6 | +7.6 | 76.6 | 1.38 | +1.1 | 52% | 1.8 | 0.9 | 58 | 8.0 | +8.0 | 77.2 | 2026-03-17 |
| 36 | pead_midcap_step19_hold5 | 29.2 | 1.20 | +0.7 | 57% | 1.2 | 0.9 | 72 | - | - | - | 1.55 | +1.4 | 57% | 2.2 | 0.7 | 68 | - | - | - | 2026-03-17 |
| 37 | pead_midcap_step49_same_day_short_macro_block | 29.1 | 2.40 | +0.4 | 70% | 1.6 | 0.4 | 10 | 1.0 | +1.0 | 26.1 | 25.09 | +1.2 | 75% | 3.2 | 0.3 | 12 | 2.6 | +2.6 | 32.1 | 2026-03-17 |
| 38 | pead_midcap_step20_best3 | 28.7 | 1.22 | +0.7 | 52% | 1.3 | 0.9 | 64 | - | - | - | 1.61 | +1.6 | 48% | 2.5 | 0.6 | 56 | - | - | - | 2026-03-17 |
| 39 | pead_midcap_step40_short_core_sdlong12 | 28.6 | 1.77 | +1.5 | 58% | 2.2 | 1.1 | 55 | 6.4 | +6.4 | 72.3 | 1.48 | +0.9 | 55% | 1.8 | 0.6 | 40 | 5.6 | +5.6 | 73.7 | 2026-03-17 |
| 40 | pead_midcap_step17_target2 | 27.3 | 1.18 | +0.6 | 53% | 1.1 | 0.8 | 66 | - | - | - | 1.38 | +1.0 | 51% | 1.5 | 0.7 | 59 | - | - | - | 2026-03-17 |
| 41 | pead_midcap_step39_balanced_sleeves_sdlong12 | 27.0 | 1.50 | +1.5 | 55% | 3.4 | 0.5 | 62 | 7.4 | +7.4 | 76.6 | 1.38 | +1.0 | 51% | 1.7 | 0.9 | 53 | 7.5 | +7.5 | 77.2 | 2026-03-17 |
| 42 | pead_midcap_step27_sdlong_close7_budget25 | 26.4 | 1.17 | +0.6 | 54% | 0.9 | 1.3 | 68 | 8.5 | +8.5 | 72.3 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 43 | pead_midcap_step13_best | 26.3 | 1.12 | +0.4 | 55% | 0.8 | 0.9 | 75 | - | - | - | 1.61 | +1.6 | 59% | 2.2 | 0.7 | 70 | - | - | - | 2026-03-16 |
| 44 | pead_midcap_step23_sdlong_close7 | 24.9 | 1.13 | +0.5 | 54% | 0.7 | 1.4 | 69 | 8.6 | +8.6 | 72.3 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 45 | pead_midcap_step34_balanced_sleeves_nofrac_aclong25 | 23.9 | 1.62 | +1.8 | 56% | 3.8 | 0.6 | 62 | 7.4 | +7.4 | 76.6 | 1.30 | +0.9 | 51% | 1.4 | 0.9 | 57 | 7.9 | +7.9 | 77.2 | 2026-03-17 |
| 46 | pead_midcap_step16_react7_score65 | 23.8 | 0.97 | -0.1 | 56% | -0.2 | 1.6 | 89 | - | - | - | 2.01 | +2.8 | 63% | 3.7 | 0.8 | 83 | - | - | - | 2026-03-17 |
| 47 | pead_midcap_step5_maxcand3 | 23.4 | 0.95 | -0.2 | 54% | -0.4 | 1.4 | 96 | - | - | - | 2.08 | +3.3 | 65% | 4.0 | 1.1 | 89 | - | - | - | 2026-03-16 |
| 48 | pead_midcap_step38_balanced_sleeves_aclong_vol4 | 23.3 | 1.12 | +0.4 | 51% | 0.8 | 0.9 | 61 | 7.4 | +7.4 | 76.6 | 1.29 | +0.8 | 53% | 1.4 | 0.9 | 53 | 7.6 | +7.6 | 77.2 | 2026-03-17 |
| 49 | pead_midcap_step15_react7 | 23.0 | 0.94 | -0.3 | 55% | -0.5 | 1.6 | 91 | - | - | - | 1.89 | +2.6 | 62% | 3.5 | 0.9 | 84 | - | - | - | 2026-03-17 |
| 50 | pead_midcap_portfolio_v2 | 23.0 | 1.08 | +0.3 | 51% | 0.5 | 1.8 | 70 | 7.9 | +7.9 | 72.3 | - | - | - | - | - | 0 | - | - | - | 2026-03-17 |
| 51 | pead_midcap_step11_score60 | 22.1 | 1.02 | +0.1 | 52% | 0.2 | 0.9 | 77 | - | - | - | 1.91 | +2.3 | 62% | 3.0 | 0.7 | 72 | - | - | - | 2026-03-16 |
| 52 | pead_midcap_step12_vol2x | 22.1 | 1.02 | +0.1 | 52% | 0.1 | 0.9 | 77 | - | - | - | 1.91 | +2.3 | 62% | 3.0 | 0.7 | 72 | - | - | - | 2026-03-16 |
| 53 | pead_midcap_step3_10pct | 21.9 | 1.00 | +0.0 | 50% | 0.0 | 1.4 | 98 | - | - | - | 1.66 | +2.0 | 60% | 2.9 | 0.7 | 78 | - | - | - | 2026-03-16 |
| 54 | pead_midcap_step10_short | 21.5 | 1.00 | -0.0 | 52% | -0.0 | 0.9 | 79 | - | - | - | 1.61 | +1.6 | 59% | 2.2 | 0.7 | 70 | - | - | - | 2026-03-16 |
| 55 | pead_midcap_step35_balanced_sleeves_nofrac_aclong12 | 21.2 | 2.01 | +2.2 | 61% | 4.2 | 0.4 | 56 | 6.2 | +1.1 | 76.6 | 1.24 | +0.7 | 51% | 1.2 | 0.9 | 53 | 7.5 | +1.6 | 77.2 | 2026-03-17 |
| 56 | pead_midcap_step2_notrail | 17.2 | 0.93 | -0.3 | 67% | -0.4 | 1.7 | 54 | - | - | - | 1.07 | +0.4 | 73% | 0.4 | 1.7 | 62 | - | - | - | 2026-03-16 |
| 57 | pead_midcap_step1_fixedr | 16.2 | 0.91 | -0.5 | 47% | -0.7 | 1.5 | 95 | - | - | - | 1.77 | +2.8 | 49% | 3.4 | 1.6 | 69 | - | - | - | 2026-03-16 |
| 58 | pead_midcap_combo_10pct_maxcand3 | 15.9 | 0.97 | -0.1 | 51% | -0.2 | 0.9 | 79 | - | - | - | 1.91 | +2.3 | 62% | 3.0 | 0.7 | 72 | - | - | - | 2026-03-16 |
| 59 | pead_midcap_step6_drift | 14.7 | 0.86 | -0.9 | 43% | -1.6 | 1.7 | 100 | - | - | - | 1.70 | +2.7 | 51% | 3.7 | 1.0 | 75 | - | - | - | 2026-03-16 |
| 60 | pead_midcap_step7_fixedr | 13.8 | 0.94 | -0.2 | 45% | -0.4 | 1.0 | 71 | - | - | - | 2.00 | +2.4 | 53% | 3.1 | 0.7 | 53 | - | - | - | 2026-03-16 |
| 61 | pead_midcap_step4_longonly | 12.2 | 0.84 | -0.8 | 45% | -1.2 | 1.4 | 78 | - | - | - | 1.43 | +1.5 | 61% | 1.7 | 1.6 | 76 | - | - | - | 2026-03-16 |
| 62 | pead_midcap_step8_nft | 11.5 | 0.65 | -1.8 | 41% | -3.0 | 2.2 | 71 | - | - | - | 1.55 | +1.8 | 46% | 2.4 | 1.0 | 57 | - | - | - | 2026-03-16 |
| 63 | pead_midcap_step9_stop2 | 11.4 | 0.77 | -1.7 | 45% | -1.8 | 2.5 | 71 | - | - | - | 1.81 | +3.2 | 53% | 2.8 | 1.2 | 53 | - | - | - | 2026-03-16 |
## Recent Entries
### IMP-0063 (2026-03-18) — pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20
Hypothesis: A softer 2.0x wiki attention cap on same-day longs may remove only the most crowded winners while preserving the rest of the long sleeve.
Verdict: **BETTER** (SQS 51.1)
Reasoning: With max-only attention caps treating missing data as pass-through, the 2.0x cap lifted train from +5.09% to +5.50% and valid from +1.78% to +1.89% while holding test at +0.98% and cutting drawdown.
Next: Probe slightly looser same-day-long wiki caps to find the best plateau without giving back the valid lift.
### IMP-0062 (2026-03-18) — pead_midcap_step75_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax25
Hypothesis: Relaxing the same-day-long wiki cap to 2.5x may keep the recent valid/test improvements while recovering more train-side winners.
Verdict: **BETTER** (SQS 51.1)
Reasoning: The 2.5x cap matched step74 on valid and test, but improved train again to +5.53% with PF 1.72 and max drawdown 0.83%. This is the current best attention-aware branch.
Next: Use step75 as the new attention-enhanced baseline; only continue if a new change improves test without giving back the train and valid gains.
### IMP-0061 (2026-03-17) — pead_midcap_step67_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react14
Hypothesis: A stricter 14% downside reaction requirement may further improve the filtered after-close short sleeve by keeping only the sharpest downside continuation setups.
Verdict: **NEUTRAL** (SQS 38.2)
@ -84,15 +98,3 @@ Verdict: **WORSE** (SQS 38.3)
Reasoning: Train ticked up slightly, but valid deteriorated meaningfully and test did not improve. Interleaving is not helping this filtered branch.
Next: Stay with the non-interleaved filtered short sleeve; the next branch should tune the filtered after-close short only if we need more test return.
### IMP-0058 (2026-03-17) — pead_midcap_step64_short_core_macro_block_crashcap_gap10_interleave_max4_acsgap10
Hypothesis: Interleaving the filtered mixed-sleeve portfolio might recover some of the earlier test strength without sacrificing the new train lift from the after-close gap gate.
Verdict: **WORSE** (SQS 50.6)
Reasoning: Test held steady, but valid return and drawdown got materially worse while train did not improve. The gap filter works better with raw global-score ranking than with interleaving.
Next: Keep global-score selection and treat step62/63 as the active return-first branch.
### IMP-0057 (2026-03-17) — pead_midcap_step63_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap12
Hypothesis: A stricter 12% negative gap gate on after-close shorts may further improve the mixed-sleeve portfolio by concentrating the short sleeve into only the sharpest downside reactions.
Verdict: **BETTER** (SQS 38.2)
Reasoning: The 12% gate slightly improved train and valid versus step62 while keeping test near 0.95% with lower drawdown than the old mixed-sleeve base. This is the strongest return-first variant so far.
Next: Combine the after-close gap gate with interleaved max4 sleeve selection to test whether test return can recover toward the 1.0%+ level.

@ -27,6 +27,60 @@
"valid_days_in_market_pct": 56.14035087719298,
"timestamp": "2026-03-17T10:10:07.544224+00:00"
},
{
"entry_id": "IMP-0062",
"experiment_name": "pead_midcap_step75_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax25",
"sqs_score": 51.1,
"sqs_v2_score": 87.7,
"promotion_score": 89.0,
"unified_score": 51.1,
"profit_factor": 3.693559917731055,
"total_return_pct": 0.9821623910714115,
"win_rate": 0.8,
"sharpe_ratio": 3.3957804338520745,
"max_drawdown_pct": 0.23230116536263104,
"trade_count": 20,
"avg_gross_exposure_pct": 2.4512706589430846,
"avg_net_exposure_pct": -1.4631851279456756,
"days_in_market_pct": 48.93617021276596,
"valid_profit_factor": 5.152433125121816,
"valid_total_return_pct": 1.8894543248131377,
"valid_win_rate": 0.7307692307692307,
"valid_sharpe_ratio": 4.619467913159227,
"valid_max_drawdown_pct": 0.3363495615309106,
"valid_trade_count": 26,
"valid_avg_gross_exposure_pct": 3.5196735893617825,
"valid_avg_net_exposure_pct": -2.0114023765395337,
"valid_days_in_market_pct": 49.122807017543856,
"timestamp": "2026-03-18T00:26:34.499172+00:00"
},
{
"entry_id": "IMP-0063",
"experiment_name": "pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20",
"sqs_score": 51.1,
"sqs_v2_score": 87.7,
"promotion_score": 89.0,
"unified_score": 51.1,
"profit_factor": 3.693559917731055,
"total_return_pct": 0.9821623910714115,
"win_rate": 0.8,
"sharpe_ratio": 3.3957804338520745,
"max_drawdown_pct": 0.23230116536263104,
"trade_count": 20,
"avg_gross_exposure_pct": 2.4512706589430846,
"avg_net_exposure_pct": -1.4631851279456756,
"days_in_market_pct": 48.93617021276596,
"valid_profit_factor": 5.152433125121816,
"valid_total_return_pct": 1.8894543248131377,
"valid_win_rate": 0.7307692307692307,
"valid_sharpe_ratio": 4.619467913159227,
"valid_max_drawdown_pct": 0.3363495615309106,
"valid_trade_count": 26,
"valid_avg_gross_exposure_pct": 3.5196735893617825,
"valid_avg_net_exposure_pct": -2.0114023765395337,
"valid_days_in_market_pct": 49.122807017543856,
"timestamp": "2026-03-18T00:26:34.560883+00:00"
},
{
"entry_id": "IMP-0056",
"experiment_name": "pead_midcap_step62_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10",
@ -1648,5 +1702,5 @@
"timestamp": "2026-03-16T23:01:55.163461+00:00"
}
],
"updated_at": "2026-03-17T10:37:12.332837+00:00"
"updated_at": "2026-03-18T00:26:47.429362+00:00"
}

@ -59,3 +59,5 @@
{"entry_id":"IMP-0059","timestamp":"2026-03-17T10:22:41.560235+00:00","experiment_name":"pead_midcap_step65_short_core_macro_block_crashcap_gap10_interleave_max4_acsgap12","hypothesis":"A stricter after-close gap gate plus interleaving may produce the strongest hybrid of train lift and balanced sleeve participation.","config_delta":{"base_experiment":"pead_midcap_step63_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap12","changes":{}},"results":{"train":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102155749766_057bd373","trade_count":182,"profit_factor":1.6174212176205378,"total_return_pct":5.077465154216028,"win_rate":0.5439560439560439,"max_drawdown_pct":1.5094301004863888,"sharpe_ratio":1.1510607734250322,"monthly_win_rate":0.6666666666666666,"equity_curve_r_squared":0.7322022304994754,"avg_gross_exposure_pct":2.127978254795758,"avg_net_exposure_pct":-0.5837963895741501,"days_in_market_pct":25.46045503791983},"valid":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102201332544_057bd373","trade_count":24,"profit_factor":4.557936520788986,"total_return_pct":1.5351686099939834,"win_rate":0.6666666666666666,"max_drawdown_pct":0.5303323192221483,"sharpe_ratio":3.9755987852769445,"monthly_win_rate":1.0,"equity_curve_r_squared":0.6279656300903311,"avg_gross_exposure_pct":3.4173394039982,"avg_net_exposure_pct":-1.9446456373142142,"days_in_market_pct":47.368421052631575},"test":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102206620963_057bd373","trade_count":19,"profit_factor":3.6038727896341176,"total_return_pct":0.9494594526291912,"win_rate":0.7894736842105263,"max_drawdown_pct":0.23230116536263104,"sharpe_ratio":3.2438715317612528,"monthly_win_rate":0.6666666666666666,"equity_curve_r_squared":0.8958519994688269,"avg_gross_exposure_pct":1.9049388001836767,"avg_net_exposure_pct":-0.9171395725318859,"days_in_market_pct":38.297872340425535}},"sqs_score":38.3,"sqs_breakdown":{"valid_quality":81.1,"test_quality":57.7,"floor_quality":57.7,"gap_quality":38.7},"sqs_v2_score":44.4,"sqs_v2_breakdown":{"profitability":83.8,"risk":100.0,"consistency":95.8,"robustness":55.0,"capital_efficiency":98.1},"promotion_score":69.0,"promotion_breakdown":{"valid_quality":89.1,"test_quality":44.4,"floor_quality":44.4},"unified_score":38.3,"unified_breakdown":{"valid_quality":81.1,"test_quality":57.7,"floor_quality":57.7,"gap_quality":38.7},"verdict":"worse","verdict_reasoning":"Train ticked up slightly, but valid deteriorated meaningfully and test did not improve. Interleaving is not helping this filtered branch.","next_direction":"Stay with the non-interleaved filtered short sleeve; the next branch should tune the filtered after-close short only if we need more test return.","tags":["pead","midcap","step65","short","core","macro","block","crashcap","gap10","interleave","max4","acsgap12"]}
{"entry_id":"IMP-0060","timestamp":"2026-03-17T10:26:25.356022+00:00","experiment_name":"pead_midcap_step66_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12","hypothesis":"Adding a 12% downside reaction requirement on top of the 10% after-close gap filter may remove the weakest residual after-close shorts without sacrificing the recent OOS edge.","config_delta":{"base_experiment":"pead_midcap_step62_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10","changes":{}},"results":{"train":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102528258441_f85583ef","trade_count":187,"profit_factor":1.6195866594933024,"total_return_pct":5.086267802803064,"win_rate":0.5508021390374331,"max_drawdown_pct":1.2717965470897303,"sharpe_ratio":1.1327429527860058,"monthly_win_rate":0.64,"equity_curve_r_squared":0.7645174872600673,"avg_gross_exposure_pct":2.1004912456069564,"avg_net_exposure_pct":-0.671173830932749,"days_in_market_pct":25.46045503791983},"valid":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102534670418_f85583ef","trade_count":26,"profit_factor":4.640144626555104,"total_return_pct":1.7785589226570302,"win_rate":0.6923076923076923,"max_drawdown_pct":0.394474954823559,"sharpe_ratio":4.453025001679815,"monthly_win_rate":1.0,"equity_curve_r_squared":0.5596638198344033,"avg_gross_exposure_pct":3.5028084000751822,"avg_net_exposure_pct":-2.028975630946834,"days_in_market_pct":49.122807017543856},"test":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102539620352_f85583ef","trade_count":20,"profit_factor":3.693559917731055,"total_return_pct":0.9821623910714115,"win_rate":0.8,"max_drawdown_pct":0.23230116536263104,"sharpe_ratio":3.3957804338520745,"monthly_win_rate":0.6666666666666666,"equity_curve_r_squared":0.9033229833419024,"avg_gross_exposure_pct":2.4512706589430846,"avg_net_exposure_pct":-1.4631851279456756,"days_in_market_pct":48.93617021276596}},"sqs_score":50.9,"sqs_breakdown":{"valid_quality":81.7,"test_quality":79.2,"floor_quality":79.2,"gap_quality":100.0},"sqs_v2_score":87.7,"sqs_v2_breakdown":{"profitability":83.9,"risk":100.0,"consistency":95.8,"robustness":55.6,"capital_efficiency":86.1},"promotion_score":88.9,"promotion_breakdown":{"valid_quality":89.9,"test_quality":87.7,"floor_quality":87.7},"unified_score":50.9,"unified_breakdown":{"valid_quality":81.7,"test_quality":79.2,"floor_quality":79.2,"gap_quality":100.0},"verdict":"better","verdict_reasoning":"This matched step62 on valid/test while lifting train from +5.01% to +5.09%. It is a cleaner version of the filtered short-sleeve branch with no observable downside so far.","next_direction":"Use step66 as the balanced return-first branch; only test further changes if they can raise test above +1.0% without giving back the train lift.","tags":["pead","midcap","step66","short","core","macro","block","crashcap","gap10","longtrend12","sdlong25","max4","acsgap10","react12"]}
{"entry_id":"IMP-0061","timestamp":"2026-03-17T10:26:25.840092+00:00","experiment_name":"pead_midcap_step67_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react14","hypothesis":"A stricter 14% downside reaction requirement may further improve the filtered after-close short sleeve by keeping only the sharpest downside continuation setups.","config_delta":{"base_experiment":"pead_midcap_step66_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12","changes":{}},"results":{"train":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102528258779_fbf8df06","trade_count":176,"profit_factor":1.72971812082782,"total_return_pct":5.315512807515508,"win_rate":0.5625,"max_drawdown_pct":1.1823507388022194,"sharpe_ratio":1.1862508329604826,"monthly_win_rate":0.625,"equity_curve_r_squared":0.7409760880151399,"avg_gross_exposure_pct":1.9641530768509556,"avg_net_exposure_pct":-0.5086575725921745,"days_in_market_pct":24.918743228602384},"valid":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102534670454_fbf8df06","trade_count":25,"profit_factor":5.331499198553463,"total_return_pct":1.8247351197415846,"win_rate":0.72,"max_drawdown_pct":0.480176430930607,"sharpe_ratio":4.44451943654,"monthly_win_rate":1.0,"equity_curve_r_squared":0.5922580595870112,"avg_gross_exposure_pct":3.1678311806010018,"avg_net_exposure_pct":-1.6948561495104018,"days_in_market_pct":47.368421052631575},"test":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260317102539620462_fbf8df06","trade_count":19,"profit_factor":3.6038727896341176,"total_return_pct":0.9494594526291912,"win_rate":0.7894736842105263,"max_drawdown_pct":0.23230116536263104,"sharpe_ratio":3.2438715317612528,"monthly_win_rate":0.6666666666666666,"equity_curve_r_squared":0.8958519994688269,"avg_gross_exposure_pct":1.9049388001836767,"avg_net_exposure_pct":-0.9171395725318859,"days_in_market_pct":38.297872340425535}},"sqs_score":38.2,"sqs_breakdown":{"valid_quality":82.1,"test_quality":57.7,"floor_quality":57.7,"gap_quality":35.3},"sqs_v2_score":44.4,"sqs_v2_breakdown":{"profitability":83.8,"risk":100.0,"consistency":95.8,"robustness":55.0,"capital_efficiency":98.1},"promotion_score":69.5,"promotion_breakdown":{"valid_quality":90.1,"test_quality":44.4,"floor_quality":44.4},"unified_score":38.2,"unified_breakdown":{"valid_quality":82.1,"test_quality":57.7,"floor_quality":57.7,"gap_quality":35.3},"verdict":"neutral","verdict_reasoning":"This pushed train to +5.32% and lifted valid slightly, but test slipped back to +0.95%. It is a stronger train-focused branch, not a clear overall winner versus step66.","next_direction":"Favor step66 for balance; step67 is only useful if we optimize explicitly for train-heavy return.","tags":["pead","midcap","step67","short","core","macro","block","crashcap","gap10","longtrend12","sdlong25","max4","acsgap10","react14"]}
{"entry_id":"IMP-0062","timestamp":"2026-03-18T00:26:34.499172+00:00","experiment_name":"pead_midcap_step75_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax25","hypothesis":"Relaxing the same-day-long wiki cap to 2.5x may keep the recent valid/test improvements while recovering more train-side winners.","config_delta":{"base_experiment":"pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20","changes":{}},"results":{"train":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260318002559460557_055a2ca2","trade_count":180,"profit_factor":1.7183536412179259,"total_return_pct":5.531892938803169,"win_rate":0.5555555555555556,"max_drawdown_pct":0.8347191141018186,"sharpe_ratio":1.2684934328885868,"monthly_win_rate":0.64,"equity_curve_r_squared":0.7601796269335234,"avg_gross_exposure_pct":2.008337112244506,"avg_net_exposure_pct":-0.7674520551002029,"days_in_market_pct":25.243770314192847},"valid":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260318002602446002_055a2ca2","trade_count":26,"profit_factor":5.152433125121816,"total_return_pct":1.8894543248131377,"win_rate":0.7307692307692307,"max_drawdown_pct":0.3363495615309106,"sharpe_ratio":4.619467913159227,"monthly_win_rate":1.0,"equity_curve_r_squared":0.5647234901994412,"avg_gross_exposure_pct":3.5196735893617825,"avg_net_exposure_pct":-2.0114023765395337,"days_in_market_pct":49.122807017543856},"test":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260318002604865162_055a2ca2","trade_count":20,"profit_factor":3.693559917731055,"total_return_pct":0.9821623910714115,"win_rate":0.8,"max_drawdown_pct":0.23230116536263104,"sharpe_ratio":3.3957804338520745,"monthly_win_rate":0.6666666666666666,"equity_curve_r_squared":0.9033229833419024,"avg_gross_exposure_pct":2.4512706589430846,"avg_net_exposure_pct":-1.4631851279456756,"days_in_market_pct":48.93617021276596}},"sqs_score":51.1,"sqs_breakdown":{"valid_quality":82.2,"test_quality":79.2,"floor_quality":79.2,"gap_quality":100.0},"sqs_v2_score":87.7,"sqs_v2_breakdown":{"profitability":83.9,"risk":100.0,"consistency":95.8,"robustness":55.6,"capital_efficiency":86.1},"promotion_score":89.0,"promotion_breakdown":{"valid_quality":90.1,"test_quality":87.7,"floor_quality":87.7},"unified_score":51.1,"unified_breakdown":{"valid_quality":82.2,"test_quality":79.2,"floor_quality":79.2,"gap_quality":100.0},"verdict":"better","verdict_reasoning":"The 2.5x cap matched step74 on valid and test, but improved train again to +5.53% with PF 1.72 and max drawdown 0.83%. This is the current best attention-aware branch.","next_direction":"Use step75 as the new attention-enhanced baseline; only continue if a new change improves test without giving back the train and valid gains.","tags":["pead","midcap","step75","short","core","macro","block","crashcap","gap10","longtrend12","sdlong25","max4","acsgap10","react12","sdlongwikimax25"]}
{"entry_id":"IMP-0063","timestamp":"2026-03-18T00:26:34.560883+00:00","experiment_name":"pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20","hypothesis":"A softer 2.0x wiki attention cap on same-day longs may remove only the most crowded winners while preserving the rest of the long sleeve.","config_delta":{"base_experiment":"pead_midcap_step66_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12","changes":{}},"results":{"train":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260318002321542287_c26693fe","trade_count":180,"profit_factor":1.7106415339502974,"total_return_pct":5.499557295406717,"win_rate":0.5555555555555556,"max_drawdown_pct":0.9072510123247227,"sharpe_ratio":1.258863317918341,"monthly_win_rate":0.64,"equity_curve_r_squared":0.7602115966092211,"avg_gross_exposure_pct":2.005910127419666,"avg_net_exposure_pct":-0.780485770578354,"days_in_market_pct":25.02708559046587},"valid":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260318002322170891_c26693fe","trade_count":26,"profit_factor":5.152433125121816,"total_return_pct":1.8894543248131377,"win_rate":0.7307692307692307,"max_drawdown_pct":0.3363495615309106,"sharpe_ratio":4.619467913159227,"monthly_win_rate":1.0,"equity_curve_r_squared":0.5647234901994412,"avg_gross_exposure_pct":3.5196735893617825,"avg_net_exposure_pct":-2.0114023765395337,"days_in_market_pct":49.122807017543856},"test":{"run_id":"bt_baseline_swing_v1_midcap-filte_20260318002322307890_c26693fe","trade_count":20,"profit_factor":3.693559917731055,"total_return_pct":0.9821623910714115,"win_rate":0.8,"max_drawdown_pct":0.23230116536263104,"sharpe_ratio":3.3957804338520745,"monthly_win_rate":0.6666666666666666,"equity_curve_r_squared":0.9033229833419024,"avg_gross_exposure_pct":2.4512706589430846,"avg_net_exposure_pct":-1.4631851279456756,"days_in_market_pct":48.93617021276596}},"sqs_score":51.1,"sqs_breakdown":{"valid_quality":82.2,"test_quality":79.2,"floor_quality":79.2,"gap_quality":100.0},"sqs_v2_score":87.7,"sqs_v2_breakdown":{"profitability":83.9,"risk":100.0,"consistency":95.8,"robustness":55.6,"capital_efficiency":86.1},"promotion_score":89.0,"promotion_breakdown":{"valid_quality":90.1,"test_quality":87.7,"floor_quality":87.7},"unified_score":51.1,"unified_breakdown":{"valid_quality":82.2,"test_quality":79.2,"floor_quality":79.2,"gap_quality":100.0},"verdict":"better","verdict_reasoning":"With max-only attention caps treating missing data as pass-through, the 2.0x cap lifted train from +5.09% to +5.50% and valid from +1.78% to +1.89% while holding test at +0.98% and cutting drawdown.","next_direction":"Probe slightly looser same-day-long wiki caps to find the best plateau without giving back the valid lift.","tags":["pead","midcap","step74","short","core","macro","block","crashcap","gap10","longtrend12","sdlong25","max4","acsgap10","react12","sdlongwikimax20"]}

@ -272,6 +272,13 @@ class StrategyEngineConfig(BaseModel):
reaction_day_return_max: float | None = None
gap_size_min: float | None = None
gap_size_max: float | None = None
attention_min_wiki_spike_10d: float | None = None
attention_min_wiki_zscore_20d: float | None = None
attention_max_wiki_spike_10d: float | None = None
attention_max_wiki_zscore_20d: float | None = None
attention_min_article_count_3d: int | None = None
attention_min_us_article_count_3d: int | None = None
attention_min_resolver_confidence: float | None = None
shadow_only: bool = False
enabled: bool = True

@ -364,6 +364,7 @@ def select_candidates(
signal_config: SignalConfig,
event_type_profiles: dict[str, EventTypeProfile] | None = None,
strategy_engine: StrategyEngineConfig | None = None,
truncate_to: int | None = None,
) -> list[Candidate]:
"""Full selection pipeline: build → filter → rank → truncate."""
candidates = []
@ -385,7 +386,10 @@ def select_candidates(
if event_type_profiles:
candidates = filter_by_event_type(candidates, event_type_profiles)
candidates = rank_candidates(candidates)
candidates = truncate_candidates(candidates, signal_config.max_candidates_per_day)
candidates = truncate_candidates(
candidates,
truncate_to if truncate_to is not None else signal_config.max_candidates_per_day,
)
return candidates

@ -457,3 +457,196 @@ class TestBacktestRunIntegration:
assert effective_exec.target_1_fraction == pytest.approx(0.33)
assert effective_exec.trailing_model == "pct_10"
assert effective_exec.trailing_warmup_days == 2
def test_attention_gate_filters_engine_candidates(self):
from apps.backtester.run import BacktestRunner
from libs.backtest.domain import ExperimentManifest, StrategyEngineConfig
from libs.backtest.snapshot_store import SnapshotStore
from libs.oracle_client.models import EntityInfo, EventAttentionResponse, NewsFeatures, WikiFeatures
date = dt.date(2026, 1, 7)
store = SnapshotStore(
candidates_by_exec_date={
date: [
{
"event_id": "EVT::ATTN::PASS",
"symbol": "PASS",
"execution_date": date,
"entry_date": "2026-01-07",
"event_date": "2026-01-06",
"event_close": 100.0,
"gap_size": 0.12,
"entry_price": 100.0,
"score": 0.90,
"sector": "Technology",
"event_type": "earnings_release",
"event_timestamp": "2026-01-06T21:00:00+00:00",
"filing_time_bucket": "post_market",
"reaction_date": "2026-01-06",
"reaction_day_return": -0.12,
"avg_dollar_volume": 8_000_000.0,
"atr_14": 4.0,
},
{
"event_id": "EVT::ATTN::FAIL",
"symbol": "FAIL",
"execution_date": date,
"entry_date": "2026-01-07",
"event_date": "2026-01-06",
"event_close": 101.0,
"gap_size": 0.11,
"entry_price": 101.0,
"score": 0.89,
"sector": "Technology",
"event_type": "earnings_release",
"event_timestamp": "2026-01-06T21:00:00+00:00",
"filing_time_bucket": "post_market",
"reaction_date": "2026-01-06",
"reaction_day_return": -0.11,
"avg_dollar_volume": 7_500_000.0,
"atr_14": 4.0,
},
]
},
bars_by_symbol_date={
"PASS": {date: {"date": date, "open": 100.0, "high": 100.0, "low": 95.0, "close": 96.0, "volume": 1_000_000}},
"FAIL": {date: {"date": date, "open": 101.0, "high": 102.0, "low": 98.0, "close": 99.0, "volume": 900_000}},
},
)
manifest = ExperimentManifest(
experiment_name="attention_gate_test",
dataset_snapshot_id="test_snapshot",
base_config="configs/backtest/defaults.json",
overrides={},
strategy_engines=[
StrategyEngineConfig(
engine_id="same_day_short_attention",
event_types=["earnings_release"],
timing_class="same_day",
direction="short_only",
attention_min_wiki_spike_10d=1.2,
)
],
)
config = _make_config(strategy_engines=manifest.strategy_engines)
runner = BacktestRunner(manifest=manifest, config=config, store=store)
def _fake_attention(candidate):
spike = 1.5 if candidate.symbol == "PASS" else 0.9
return EventAttentionResponse(
ticker=candidate.symbol,
event_date="2026-01-06",
entity=EntityInfo(
ticker=candidate.symbol,
canonical_name=candidate.symbol,
resolver_confidence=0.9,
),
wiki=WikiFeatures(spike_10d=spike, zscore_20d=1.0),
news=NewsFeatures(),
metadata={},
)
runner._get_event_attention = _fake_attention # type: ignore[method-assign]
selected = runner._select_candidates_for_date(date)
assert [candidate.symbol for candidate in selected] == ["PASS"]
assert selected[0].features["attention_wiki_spike_10d"] == pytest.approx(1.5)
def test_attention_max_gate_allows_missing_payload(self):
from apps.backtester.run import BacktestRunner
from libs.backtest.domain import ExperimentManifest, StrategyEngineConfig
from libs.backtest.snapshot_store import SnapshotStore
date = dt.date(2026, 1, 6)
store = SnapshotStore(
candidates_by_exec_date={
date: [
{
"event_id": "EVT::ATTN::KNOWN",
"symbol": "KNOWN",
"execution_date": date,
"entry_date": "2026-01-06",
"event_date": "2026-01-06",
"event_close": 100.0,
"gap_size": 0.12,
"entry_price": 100.0,
"score": 0.90,
"sector": "Technology",
"event_type": "earnings_release",
"event_timestamp": "2026-01-06T21:00:00+00:00",
"filing_time_bucket": "post_market",
"reaction_date": "2026-01-06",
"reaction_day_return": 0.15,
"avg_dollar_volume": 8_000_000.0,
"atr_14": 4.0,
},
{
"event_id": "EVT::ATTN::MISSING",
"symbol": "MISSING",
"execution_date": date,
"entry_date": "2026-01-06",
"event_date": "2026-01-06",
"event_close": 101.0,
"gap_size": 0.11,
"entry_price": 101.0,
"score": 0.89,
"sector": "Technology",
"event_type": "earnings_release",
"event_timestamp": "2026-01-06T21:00:00+00:00",
"filing_time_bucket": "post_market",
"reaction_date": "2026-01-06",
"reaction_day_return": 0.14,
"avg_dollar_volume": 7_500_000.0,
"atr_14": 4.0,
},
]
},
bars_by_symbol_date={
"KNOWN": {date: {"date": date, "open": 100.0, "high": 105.0, "low": 99.0, "close": 103.0, "volume": 1_000_000}},
"MISSING": {date: {"date": date, "open": 101.0, "high": 104.0, "low": 100.0, "close": 102.0, "volume": 900_000}},
},
)
manifest = ExperimentManifest(
experiment_name="attention_max_gate_test",
dataset_snapshot_id="test_snapshot",
base_config="configs/backtest/defaults.json",
overrides={},
strategy_engines=[
StrategyEngineConfig(
engine_id="same_day_long_attention_cap",
event_types=["earnings_release"],
timing_class="same_day",
direction="long_only",
entry_timing_policy="reaction_close",
gap_size_min=0.10,
attention_max_wiki_spike_10d=1.5,
)
],
)
config = _make_config(strategy_engines=manifest.strategy_engines)
runner = BacktestRunner(manifest=manifest, config=config, store=store)
def _fake_attention(candidate):
if candidate.symbol == "KNOWN":
from libs.oracle_client.models import EntityInfo, EventAttentionResponse, NewsFeatures, WikiFeatures
return EventAttentionResponse(
ticker=candidate.symbol,
event_date="2026-01-06",
entity=EntityInfo(
ticker=candidate.symbol,
canonical_name=candidate.symbol,
resolver_confidence=0.9,
),
wiki=WikiFeatures(spike_10d=1.4, zscore_20d=0.5),
news=NewsFeatures(),
metadata={},
)
return None
runner._get_event_attention = _fake_attention # type: ignore[method-assign]
selected = runner._select_candidates_for_date(date)
assert [candidate.symbol for candidate in selected] == ["KNOWN", "MISSING"]
assert selected[0].features["attention_wiki_spike_10d"] == pytest.approx(1.4)
assert "attention_wiki_spike_10d" not in selected[1].features

Loading…
Cancel
Save