diff --git a/apps/backtester/run.py b/apps/backtester/run.py index 43d99c9..8f3bcf8 100644 --- a/apps/backtester/run.py +++ b/apps/backtester/run.py @@ -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]], diff --git a/configs/experiments/pead_midcap_step68_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_acswiki115.json b/configs/experiments/pead_midcap_step68_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_acswiki115.json new file mode 100644 index 0000000..85a06a7 --- /dev/null +++ b/configs/experiments/pead_midcap_step68_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_acswiki115.json @@ -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 +} diff --git a/configs/experiments/pead_midcap_step69_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_acswiki125.json b/configs/experiments/pead_midcap_step69_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_acswiki125.json new file mode 100644 index 0000000..2059ebd --- /dev/null +++ b/configs/experiments/pead_midcap_step69_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_acswiki125.json @@ -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 +} diff --git a/configs/experiments/pead_midcap_step70_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdswiki115.json b/configs/experiments/pead_midcap_step70_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdswiki115.json new file mode 100644 index 0000000..8878879 --- /dev/null +++ b/configs/experiments/pead_midcap_step70_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdswiki115.json @@ -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 +} diff --git a/configs/experiments/pead_midcap_step71_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax13.json b/configs/experiments/pead_midcap_step71_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax13.json new file mode 100644 index 0000000..bf7867b --- /dev/null +++ b/configs/experiments/pead_midcap_step71_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax13.json @@ -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 +} diff --git a/configs/experiments/pead_midcap_step72_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax15.json b/configs/experiments/pead_midcap_step72_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax15.json new file mode 100644 index 0000000..b36e9b3 --- /dev/null +++ b/configs/experiments/pead_midcap_step72_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax15.json @@ -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 +} diff --git a/configs/experiments/pead_midcap_step73_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax17.json b/configs/experiments/pead_midcap_step73_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax17.json new file mode 100644 index 0000000..845222c --- /dev/null +++ b/configs/experiments/pead_midcap_step73_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax17.json @@ -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 +} diff --git a/configs/experiments/pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20.json b/configs/experiments/pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20.json new file mode 100644 index 0000000..1bca5e3 --- /dev/null +++ b/configs/experiments/pead_midcap_step74_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax20.json @@ -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 +} diff --git a/configs/experiments/pead_midcap_step75_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax25.json b/configs/experiments/pead_midcap_step75_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax25.json new file mode 100644 index 0000000..11c6982 --- /dev/null +++ b/configs/experiments/pead_midcap_step75_short_core_macro_block_crashcap_gap10_longtrend12_sdlong25_max4_acsgap10_react12_sdlongwikimax25.json @@ -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 +} diff --git a/journal/LEADERBOARD.md b/journal/LEADERBOARD.md index 2a8dcf2..d279ed9 100644 --- a/journal/LEADERBOARD.md +++ b/journal/LEADERBOARD.md @@ -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. - diff --git a/journal/experiment_registry.json b/journal/experiment_registry.json index 23903cf..91c95e5 100644 --- a/journal/experiment_registry.json +++ b/journal/experiment_registry.json @@ -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" } \ No newline at end of file diff --git a/journal/improvement_journal.jsonl b/journal/improvement_journal.jsonl index b6a48a4..0279d70 100644 --- a/journal/improvement_journal.jsonl +++ b/journal/improvement_journal.jsonl @@ -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"]} diff --git a/libs/backtest/domain.py b/libs/backtest/domain.py index 4983f67..aac4cfa 100644 --- a/libs/backtest/domain.py +++ b/libs/backtest/domain.py @@ -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 diff --git a/libs/backtest/selector.py b/libs/backtest/selector.py index 1a78d51..39e26a3 100644 --- a/libs/backtest/selector.py +++ b/libs/backtest/selector.py @@ -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 diff --git a/tests/integration/backtest/test_backtest_run.py b/tests/integration/backtest/test_backtest_run.py index 0653f46..af9a344 100644 --- a/tests/integration/backtest/test_backtest_run.py +++ b/tests/integration/backtest/test_backtest_run.py @@ -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