fix(filter): deprioritize recent movers instead of dropping, exempt mean_reversion pipeline
- Change recent_mover_action default from "filter" to "deprioritize" so candidates that moved >10% in the past 7 days reach the ranker (with lowered priority + context annotation) rather than being silently dropped - Exempt mean_reversion pipeline candidates (rsi_oversold) from the recent-mover action entirely — stocks that pulled back hard are the signal, not a disqualifier Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bab7106d7d
commit
471030facc
|
|
@ -478,22 +478,30 @@ class CandidateFilter:
|
||||||
cand["recent_move_status"] = reaction.get("status")
|
cand["recent_move_status"] = reaction.get("status")
|
||||||
|
|
||||||
if reaction.get("status") == "lagging":
|
if reaction.get("status") == "lagging":
|
||||||
if self.recent_mover_action == "filter":
|
# Mean-reversion candidates are expected to have moved — exempt them
|
||||||
filtered_reasons["recent_moved"] += 1
|
from tradingagents.dataflows.discovery.scanner_registry import SCANNER_REGISTRY
|
||||||
change_pct = reaction.get("price_change_pct", 0)
|
source = cand.get("source", "")
|
||||||
logger.info(
|
scanner_cls = SCANNER_REGISTRY.scanners.get(source)
|
||||||
f"Filtered {ticker}: Already moved {change_pct:+.1f}% in last "
|
scanner_pipeline = getattr(scanner_cls, "pipeline", None)
|
||||||
f"{self.recent_movement_lookback_days} days"
|
is_mean_reversion = scanner_pipeline == "mean_reversion"
|
||||||
)
|
|
||||||
continue
|
if not is_mean_reversion:
|
||||||
if self.recent_mover_action == "deprioritize":
|
if self.recent_mover_action == "filter":
|
||||||
cand["priority"] = "low"
|
filtered_reasons["recent_moved"] += 1
|
||||||
existing_context = cand.get("context", "")
|
change_pct = reaction.get("price_change_pct", 0)
|
||||||
change_pct = reaction.get("price_change_pct", 0)
|
logger.info(
|
||||||
cand["context"] = (
|
f"Filtered {ticker}: Already moved {change_pct:+.1f}% in last "
|
||||||
f"{existing_context} | ⚠️ Recent move: {change_pct:+.1f}% "
|
f"{self.recent_movement_lookback_days} days"
|
||||||
f"over {self.recent_movement_lookback_days}d"
|
)
|
||||||
)
|
continue
|
||||||
|
if self.recent_mover_action == "deprioritize":
|
||||||
|
cand["priority"] = "low"
|
||||||
|
existing_context = cand.get("context", "")
|
||||||
|
change_pct = reaction.get("price_change_pct", 0)
|
||||||
|
cand["context"] = (
|
||||||
|
f"{existing_context} | ⚠️ Recent move: {change_pct:+.1f}% "
|
||||||
|
f"over {self.recent_movement_lookback_days}d"
|
||||||
|
)
|
||||||
|
|
||||||
# Liquidity filter based on average volume
|
# Liquidity filter based on average volume
|
||||||
if self.min_average_volume:
|
if self.min_average_volume:
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ DEFAULT_CONFIG = {
|
||||||
"filter_recent_movers": True, # Enable/disable filter
|
"filter_recent_movers": True, # Enable/disable filter
|
||||||
"recent_movement_lookback_days": 7, # Days to check for recent moves
|
"recent_movement_lookback_days": 7, # Days to check for recent moves
|
||||||
"recent_movement_threshold": 10.0, # % change threshold
|
"recent_movement_threshold": 10.0, # % change threshold
|
||||||
"recent_mover_action": "filter", # "filter" or "deprioritize"
|
"recent_mover_action": "deprioritize", # "filter" or "deprioritize"
|
||||||
# Volume / compression detection
|
# Volume / compression detection
|
||||||
"volume_cache_key": "default", # Cache key for volume data
|
"volume_cache_key": "default", # Cache key for volume data
|
||||||
"min_market_cap": 0, # Minimum market cap in billions (0 = no filter)
|
"min_market_cap": 0, # Minimum market cap in billions (0 = no filter)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue