feat: trade mandate (budget + horizon) wired end-to-end
- database.py: add trade_budget_eur / preferred_horizon_min/max config defaults and include them in cycle config migrations - auto_cycle.py: read trade params from config and inject into cycle_meta - ai_analyzer.py: inject INVESTOR TRADE MANDATE block into scoring and suggestion prompts so GPT-4o penalises horizon mismatches and sizes within the capital cap - Config.tsx: Trade Parameters card with budget + horizon sliders and live mandate summary - TradeIdeas.tsx: horizon filter pills (< 1M / 1-3M / 3-6M / > 6M) and budget/horizon indicator pulled from saved config - useApi.ts: extend useUpdateCycleConfig type with new config fields Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -619,10 +619,25 @@ Scoring instructions:
|
||||
_portfolio_sc_section = f"\n{portfolio_context_block}\n" if portfolio_context_block else ""
|
||||
_inst_sc_section = f"\n{institutional_block}\n" if institutional_block else ""
|
||||
|
||||
# Trade mandate block from cycle_meta
|
||||
_budget = _cm.get("trade_budget_eur", 5000)
|
||||
_h_min = _cm.get("preferred_horizon_min", 30)
|
||||
_h_max = _cm.get("preferred_horizon_max", 180)
|
||||
_max_pos = round(_budget * 0.25)
|
||||
_trade_mandate_sc = (
|
||||
f"\n## INVESTOR TRADE MANDATE\n"
|
||||
f"- Available capital budget: €{_budget:,.0f}\n"
|
||||
f"- Preferred horizon: {_h_min}–{_h_max} days\n"
|
||||
f"- Max capital per position: €{_max_pos:,.0f} (25% of budget)\n"
|
||||
f"⚠️ Patterns whose horizon_days is outside [{_h_min}, {_h_max}] should receive a penalty"
|
||||
f" in the R/R pillar (poor timing fit). Size trade suggestions within the budget cap.\n"
|
||||
)
|
||||
|
||||
user = f"""GLOBAL CONTEXT:
|
||||
- Geopolitical risk score: {geo_score.get('score', 50)}/100 ({geo_score.get('level', 'medium')})
|
||||
- Top risks: {geo_score.get('top_risks', [])}
|
||||
{temporal_section_sc}
|
||||
{_trade_mandate_sc}
|
||||
{macro_section}
|
||||
{_fred_sc_section}
|
||||
{_pd_sc_section}
|
||||
@@ -1411,7 +1426,20 @@ Additional rules:
|
||||
portfolio_section = f"\n{portfolio_context_block}\n" if portfolio_context_block else ""
|
||||
convergence_section = f"\n{convergence_block}\n" if convergence_block else ""
|
||||
|
||||
_sg_budget = _cycle_meta.get("trade_budget_eur", 5000)
|
||||
_sg_h_min = _cycle_meta.get("preferred_horizon_min", 30)
|
||||
_sg_h_max = _cycle_meta.get("preferred_horizon_max", 180)
|
||||
_sg_max_pos = round(_sg_budget * 0.25)
|
||||
_suggest_mandate = (
|
||||
f"\n## INVESTOR TRADE MANDATE\n"
|
||||
f"- Available capital budget: €{_sg_budget:,.0f} | Max per position: €{_sg_max_pos:,.0f}\n"
|
||||
f"- Target horizon: {_sg_h_min}–{_sg_h_max} days\n"
|
||||
f"⚠️ Only propose patterns whose horizon_days is within [{_sg_h_min}, {_sg_h_max}]."
|
||||
f" Patterns outside this window will be rejected. Size each trade so capital ≤ €{_sg_max_pos:,.0f}.\n"
|
||||
)
|
||||
|
||||
user = f"""You are a senior geopolitical and financial strategist, expert in options.
|
||||
{_suggest_mandate}
|
||||
{macro_block}{geo_block}{lessons_block}{reliability_block}{iv_block}
|
||||
{temporal_news_block}
|
||||
## Market prices (D-1 change)
|
||||
|
||||
@@ -255,6 +255,10 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
_market_session = "after_hours"
|
||||
_market_note = "After-hours US — prix indicatifs, liquidité réduite."
|
||||
|
||||
_budget_eur = float(get_config("trade_budget_eur") or "5000")
|
||||
_horizon_min = int(get_config("preferred_horizon_min") or "30")
|
||||
_horizon_max = int(get_config("preferred_horizon_max") or "180")
|
||||
|
||||
cycle_meta = {
|
||||
"current_cycle_ts": _now.isoformat(),
|
||||
"last_cycle_ts": _last_cycle_ts_str,
|
||||
@@ -265,6 +269,9 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
"is_weekend": _is_weekend,
|
||||
"market_session": _market_session,
|
||||
"market_note": _market_note,
|
||||
"trade_budget_eur": _budget_eur,
|
||||
"preferred_horizon_min": _horizon_min,
|
||||
"preferred_horizon_max": _horizon_max,
|
||||
}
|
||||
logger.info(
|
||||
f"[Cycle {run_id[:16]}] Cycle meta: delta={_delta_minutes:.0f}min depuis dernier cycle"
|
||||
|
||||
@@ -311,6 +311,9 @@ def init_db():
|
||||
"auto_cycle_similarity_threshold": "0.30",
|
||||
"min_ev_threshold": "0.0",
|
||||
"min_score_threshold": "0",
|
||||
"trade_budget_eur": "5000",
|
||||
"preferred_horizon_min": "30",
|
||||
"preferred_horizon_max": "180",
|
||||
"exit_defaults": json.dumps({
|
||||
"target_pct": 30.0,
|
||||
"stop_loss_pct": -50.0,
|
||||
|
||||
Reference in New Issue
Block a user