fix: weekend-aware cycle — IVGate, pandas MultiIndex, ticker aliases, day/session in AI prompt
- auto_cycle.py: detect weekend/market session, build cycle_meta with day_of_week/is_weekend/market_note; IVGate skips iv_rank>=99 on weekends to avoid artificial weekend option premium cascade; inject portfolio context (open trades + price moves + concentration) before AI scoring; pass portfolio_context_block + run_id to both AI scorer and suggester - ai_analyzer.py: _build_temporal_news_block injects market session banner (WEEKEND warning, pre/after-market note, or open session label) so AI knows markets are closed and defers execution to Monday - iv_engine.py: add WHEAT/EUR/USD ticker aliases; skip saving IV snapshots on weekends to protect history; resolve aliases before slash-format conversion in _resolve_ticker - technical_indicators.py: fix pandas MultiIndex from yfinance>=0.2 (droplevel+squeeze); use period proportional to lookback instead of fixed period=1d - database.py: asset_class ticker-based fallback (_asset_class_from_ticker); one-time backfill migration for all NULL asset_class rows; ai_call_logs table + save/get helpers; normalize_ticker public function Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1069,6 +1069,45 @@ def _normalize_yf_ticker(ticker: str) -> str:
|
||||
return t
|
||||
|
||||
|
||||
# Common AI hallucinations / wrong ticker formats → canonical Yahoo Finance symbols
|
||||
TICKER_ALIASES: dict = {
|
||||
# Commodities
|
||||
"WHEAT": "ZW=F", "CORN_FUTURES": "ZC=F", "SOYBEANS": "ZS=F", "SOYBEAN": "ZS=F",
|
||||
"CRUDE": "CL=F", "OIL": "CL=F", "WTI": "CL=F", "BRENT": "BZ=F",
|
||||
"CRUDE OIL": "CL=F", "NATURAL GAS": "NG=F",
|
||||
"GOLD": "GC=F", "SILVER": "SI=F", "COPPER": "HG=F", "PLATINUM": "PL=F",
|
||||
"SUGAR": "SB=F", "COFFEE": "KC=F", "COCOA": "CC=F", "COTTON": "CT=F",
|
||||
# Forex — "/" format → yfinance format
|
||||
"EUR/USD": "EURUSD=X", "USD/EUR": "EURUSD=X",
|
||||
"USD/JPY": "USDJPY=X", "JPY/USD": "USDJPY=X",
|
||||
"GBP/USD": "GBPUSD=X", "USD/GBP": "GBPUSD=X",
|
||||
"USD/CHF": "USDCHF=X", "CHF/USD": "USDCHF=X",
|
||||
"AUD/USD": "AUDUSD=X", "USD/CAD": "USDCAD=X",
|
||||
# Indices
|
||||
"SP500": "^GSPC", "S&P500": "^GSPC", "S&P 500": "^GSPC",
|
||||
"NASDAQ": "QQQ", "NASDAQ100": "^NDX",
|
||||
"DOW": "DIA", "DOW JONES": "DIA",
|
||||
"RUSSELL2000": "IWM", "RUSSELL 2000": "IWM",
|
||||
}
|
||||
|
||||
|
||||
def normalize_ticker(ticker: str) -> str:
|
||||
"""Normalize AI-generated ticker strings to valid Yahoo Finance symbols."""
|
||||
if not ticker:
|
||||
return ticker
|
||||
t = ticker.strip()
|
||||
upper = t.upper()
|
||||
# Check alias map (case-insensitive)
|
||||
if upper in TICKER_ALIASES:
|
||||
return TICKER_ALIASES[upper]
|
||||
# Forex: "EUR/USD" style not caught above
|
||||
if "/" in t:
|
||||
parts = t.upper().split("/")
|
||||
if len(parts) == 2 and all(2 <= len(p) <= 4 for p in parts):
|
||||
return parts[0] + parts[1] + "=X"
|
||||
return t
|
||||
|
||||
|
||||
_TICKER_ASSET_CLASS: dict = {
|
||||
# Energy
|
||||
"CL=F": "energy", "BZ=F": "energy", "NG=F": "energy", "RB=F": "energy", "HO=F": "energy",
|
||||
|
||||
Reference in New Issue
Block a user