""" Swing Quant Engine — Central Configuration All tunable parameters, universe definitions, and thresholds. """ import os from pathlib import Path from dotenv import load_dotenv # ── Paths ── BASE_DIR = Path(__file__).parent DATA_DIR = BASE_DIR / "data" PARQUET_DIR = DATA_DIR / "parquet" DB_PATH = DATA_DIR / "quant.db" # Ensure dirs exist DATA_DIR.mkdir(exist_ok=True) PARQUET_DIR.mkdir(exist_ok=True) # Load env from portfolio_website if local .env doesn't exist _local_env = BASE_DIR / ".env" _portfolio_env = BASE_DIR.parent / "portfolio_website" / ".env" if _local_env.exists(): load_dotenv(_local_env) elif _portfolio_env.exists(): load_dotenv(_portfolio_env) # ── API Keys ── OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini") PERPLEXITY_API_KEY = os.getenv("PERPLEXITY_API_KEY", "") FINNHUB_API_KEY = os.getenv("FINNHUB_API_KEY", "") # ── Stock Universe ── # Indian blue-chips (NSE) — top Nifty 50 + select mid-caps INDIA_UNIVERSE = [ "RELIANCE.NS", "TCS.NS", "HDFCBANK.NS", "INFY.NS", "ICICIBANK.NS", "HINDUNILVR.NS", "BHARTIARTL.NS", "SBIN.NS", "ITC.NS", "KOTAKBANK.NS", "LT.NS", "AXISBANK.NS", "BAJFINANCE.NS", "ASIANPAINT.NS", "MARUTI.NS", "HCLTECH.NS", "WIPRO.NS", "SUNPHARMA.NS", "TITAN.NS", "ULTRACEMCO.NS", "ONGC.NS", "NTPC.NS", "POWERGRID.NS", "TATAMOTORS.NS", "TATASTEEL.NS", "ADANIENT.NS", "ADANIPORTS.NS", "COALINDIA.NS", "JSWSTEEL.NS", "M&M.NS", "BAJAJ-AUTO.NS", "TECHM.NS", "HEROMOTOCO.NS", "DRREDDY.NS", "CIPLA.NS", "DIVISLAB.NS", "APOLLOHOSP.NS", "EICHERMOT.NS", "BPCL.NS", "GRASIM.NS", "TATACONSUM.NS", "NESTLEIND.NS", "BRITANNIA.NS", "INDUSINDBK.NS", "HINDALCO.NS", "SBILIFE.NS", "HDFCLIFE.NS", "BAJAJFINSV.NS", "SHREECEM.NS", "PIDILITIND.NS", ] # US blue-chips — S&P 100 subset US_UNIVERSE = [ "AAPL", "MSFT", "GOOGL", "AMZN", "NVDA", "META", "TSLA", "BRK-B", "UNH", "JNJ", "V", "XOM", "JPM", "PG", "MA", "HD", "CVX", "MRK", "ABBV", "LLY", "PEP", "KO", "COST", "AVGO", "WMT", "MCD", "CSCO", "ACN", "TMO", "ABT", "DHR", "NEE", "LIN", "PM", "TXN", "UNP", "RTX", "HON", "LOW", "AMGN", "COP", "QCOM", "ORCL", "GS", "BAC", "CAT", "SBUX", "AXP", "PFE", "AMD", ] # Combined default universe DEFAULT_UNIVERSE = INDIA_UNIVERSE + US_UNIVERSE # ── Technical Signal Thresholds ── SIGNAL_PARAMS = { # RSI "rsi_oversold": 30, "rsi_overbought": 75, "rsi_bullish_zone": (45, 76), # Tightened momentum sweet spot # MACD "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, # Bollinger Bands "bb_period": 20, "bb_std": 2.0, # Moving Averages "sma_short": 20, "sma_medium": 50, "sma_long": 200, "ema_fast": 9, "ema_slow": 21, # Volume "volume_spike_threshold": 2.0, # Increased to 2.0x avg volume for higher conviction "volume_sma_period": 20, # ADX (trend strength) "adx_trending": 25, # ADX > 25 = trending market # ATR "atr_period": 14, # Breakout "breakout_lookback": 20, # days to look for resistance "breakout_volume_confirm": 1.3, # min volume multiplier for confirmation } # ── Risk Parameters ── RISK_PARAMS = { "max_position_pct": 5.0, # Max 5% of portfolio in one position "max_sector_pct": 15.0, # Reduced to 15% for better diversification "max_drawdown_pct": 15.0, # Kill switch at 15% portfolio drawdown "min_liquidity_inr": 5_00_00_000, # ₹5Cr daily volume for India "min_liquidity_usd": 10_000_000, # $10M daily volume for US "max_atr_pct": 5.0, # Skip stocks with ATR% > 5% "max_correlation": 0.85, # Reject if corr > 0.85 with existing "kelly_fraction": 0.25, # Use 25% of Kelly optimal (conservative) } # ── Alpha Scoring Weights ── ALPHA_WEIGHTS = { "momentum": 0.35, "volume_breakout": 0.20, "sentiment": 0.20, "regime_fit": 0.15, "fundamental": 0.10, } # ── Scan Schedule ── SCAN_INTERVAL_HOURS = 4 # Re-scan every 4 hours during market hours # ── Market Hours (for scheduling) ── MARKET_HOURS = { "india": {"open": "09:15", "close": "15:30", "tz": "Asia/Kolkata"}, "us": {"open": "09:30", "close": "16:00", "tz": "America/New_York"}, } # ── Backtest Defaults ── BACKTEST_PARAMS = { "in_sample_months": 12,#6 "out_sample_months": 3,#1 "commission_india_pct": 0.1, "commission_us_pct": 0.05, "slippage_pct": 0.05, "initial_capital": 10_00_000, # ₹10L or $10K equivalent } # ── Logging ── import logging LOG_FORMAT = "%(asctime)s [%(levelname)s] %(name)s: %(message)s" logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)