fix: deduplicate recommendations and widen position sizing range
- Add dedup check in recommendation worker: skip generation when latest rec for same ticker+window has identical action/mode/confidence - Widen position sizing range (1-10% portfolio, 0.3-2% max loss) and factor in trend strength + evidence count for differentiated sizing - API returns only latest recommendation per ticker by default (DISTINCT ON) to eliminate duplicate rows in the frontend list view
This commit is contained in:
@@ -66,17 +66,17 @@ class EligibilityConfig:
|
||||
|
||||
# --- Position sizing rules (Requirement 7.3) ---
|
||||
# Base portfolio allocation percentage
|
||||
base_portfolio_pct: float = 0.02
|
||||
base_portfolio_pct: float = 0.01
|
||||
# Maximum portfolio allocation percentage
|
||||
max_portfolio_pct: float = 0.05
|
||||
max_portfolio_pct: float = 0.10
|
||||
# Base max loss percentage
|
||||
base_max_loss_pct: float = 0.005
|
||||
base_max_loss_pct: float = 0.003
|
||||
# Maximum max loss percentage
|
||||
max_max_loss_pct: float = 0.01
|
||||
max_max_loss_pct: float = 0.02
|
||||
# Confidence scaling: higher confidence → larger position (linear)
|
||||
confidence_sizing_weight: float = 0.5
|
||||
confidence_sizing_weight: float = 0.8
|
||||
# Contradiction penalty: higher contradiction → smaller position
|
||||
contradiction_sizing_penalty: float = 0.3
|
||||
contradiction_sizing_penalty: float = 0.5
|
||||
|
||||
|
||||
DEFAULT_ELIGIBILITY_CONFIG = EligibilityConfig()
|
||||
@@ -216,30 +216,40 @@ def _compute_position_sizing(
|
||||
) -> PositionSizing:
|
||||
"""Compute position sizing guidance from portfolio rules and signal quality.
|
||||
|
||||
Higher confidence → larger allocation (up to max).
|
||||
Higher confidence and trend strength → larger allocation (up to max).
|
||||
Higher contradiction → smaller allocation (penalty).
|
||||
Low evidence count further reduces allocation.
|
||||
"""
|
||||
# Start from base allocation
|
||||
confidence_scale = config.base_portfolio_pct + (
|
||||
config.confidence_sizing_weight
|
||||
* summary.confidence
|
||||
* (config.max_portfolio_pct - config.base_portfolio_pct)
|
||||
)
|
||||
# Confidence-based scaling over the full range
|
||||
confidence_factor = config.confidence_sizing_weight * summary.confidence
|
||||
# Trend strength multiplier — stronger trends justify larger positions
|
||||
strength_factor = 0.5 + 0.5 * summary.trend_strength # range [0.5, 1.0]
|
||||
|
||||
portfolio_range = config.max_portfolio_pct - config.base_portfolio_pct
|
||||
raw_portfolio = config.base_portfolio_pct + confidence_factor * strength_factor * portfolio_range
|
||||
|
||||
# Apply contradiction penalty
|
||||
contradiction_penalty = config.contradiction_sizing_penalty * summary.contradiction_score
|
||||
portfolio_pct = confidence_scale * (1.0 - contradiction_penalty)
|
||||
portfolio_pct = raw_portfolio * (1.0 - contradiction_penalty)
|
||||
|
||||
# Evidence count penalty — fewer sources = less confidence in sizing
|
||||
evidence_count = len(summary.top_supporting_evidence) + len(summary.top_opposing_evidence)
|
||||
if evidence_count < 3:
|
||||
portfolio_pct *= 0.5
|
||||
elif evidence_count < 5:
|
||||
portfolio_pct *= 0.75
|
||||
|
||||
# Clamp to bounds
|
||||
portfolio_pct = max(config.base_portfolio_pct * 0.5, min(portfolio_pct, config.max_portfolio_pct))
|
||||
|
||||
# Max loss scales similarly
|
||||
loss_scale = config.base_max_loss_pct + (
|
||||
config.confidence_sizing_weight
|
||||
* summary.confidence
|
||||
* (config.max_max_loss_pct - config.base_max_loss_pct)
|
||||
)
|
||||
max_loss_pct = loss_scale * (1.0 - contradiction_penalty)
|
||||
loss_range = config.max_max_loss_pct - config.base_max_loss_pct
|
||||
raw_loss = config.base_max_loss_pct + confidence_factor * strength_factor * loss_range
|
||||
max_loss_pct = raw_loss * (1.0 - contradiction_penalty)
|
||||
if evidence_count < 3:
|
||||
max_loss_pct *= 0.5
|
||||
elif evidence_count < 5:
|
||||
max_loss_pct *= 0.75
|
||||
max_loss_pct = max(config.base_max_loss_pct * 0.5, min(max_loss_pct, config.max_max_loss_pct))
|
||||
|
||||
return PositionSizing(
|
||||
|
||||
Reference in New Issue
Block a user