← back to kingkpink__metalstats

Function bodies 642 total

All specs Real LLM only Function bodies
Separator function · typescript · L8-L26 (19 LOC)
components/ui/separator.tsx
function Separator({
  className,
  orientation = "horizontal",
  decorative = true,
  ...props
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
  return (
    <SeparatorPrimitive.Root
      data-slot="separator"
      decorative={decorative}
      orientation={orientation}
      className={cn(
        "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
        className
      )}
      {...props}
    />
  )
}
UserMenu function · typescript · L8-L100 (93 LOC)
components/UserMenu.tsx
export default function UserMenu() {
  const { data: session, status } = useSession();
  const [open, setOpen] = useState(false);
  const menuRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    function handleClickOutside(e: MouseEvent) {
      if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
        setOpen(false);
      }
    }
    if (open) {
      document.addEventListener('mousedown', handleClickOutside);
      return () => document.removeEventListener('mousedown', handleClickOutside);
    }
  }, [open]);

  if (status === 'loading') {
    return (
      <div className="w-8 h-8 rounded-full bg-slate-100 dark:bg-zinc-800 flex items-center justify-center">
        <Loader2 className="w-3.5 h-3.5 text-slate-400 dark:text-zinc-500 animate-spin" />
      </div>
    );
  }

  if (!session?.user) {
    return null;
  }

  const initials = (session.user.name || session.user.email || '?')
    .split(' ')
    .map((w) => w[0])
    .join('')
    .slice(0, 2)
   
handleClickOutside function · typescript · L14-L18 (5 LOC)
components/UserMenu.tsx
    function handleClickOutside(e: MouseEvent) {
      if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
        setOpen(false);
      }
    }
VolumeOIChart function · typescript · L53-L363 (311 LOC)
components/VolumeOIChart.tsx
export default function VolumeOIChart({ 
  data: initialData, 
  symbol = 'GC', 
  displayName = 'Gold',
  color = '#fbbf24'
}: VolumeOIChartProps) {
  const { theme } = useTheme();
  const isDark = theme === 'dark';
  const [metric, setMetric] = useState<'volume' | 'oi' | 'both'>('both');
  const [data, setData] = useState<HistoricalDataPoint[]>(initialData || sampleData);
  const [isLoading, setIsLoading] = useState(!initialData);
  const chartRef = useRef<HTMLDivElement>(null);

  // Fetch historical data from API if no data provided
  useEffect(() => {
    if (initialData) {
      setData(initialData);
      setIsLoading(false);
      return;
    }

    const fetchHistory = async () => {
      try {
        const response = await fetch(`/api/bulletin/history?symbol=${symbol}&days=30`);
        if (response.ok) {
          const result = await response.json();
          if (result.history && result.history.length > 0) {
            setData(result.history);
          }
        }
    
get_db_connection function · python · L41-L61 (21 LOC)
forecast.py
def get_db_connection(retries: int = 3, delay: float = 2.0):
    """Get a psycopg2 connection from DATABASE_URL with retry logic for Neon serverless."""
    import time
    url = os.environ.get("DATABASE_URL_UNPOOLED") or os.environ.get("DATABASE_URL")
    if not url:
        raise RuntimeError("DATABASE_URL not set")
    is_pooled = "-pooler" in (url or "")
    for attempt in range(1, retries + 1):
        try:
            kwargs = dict(connect_timeout=10)
            if not is_pooled:
                kwargs["options"] = "-c statement_timeout=30000"
            conn = psycopg2.connect(url, **kwargs)
            return conn
        except psycopg2.OperationalError as e:
            if attempt < retries:
                print(f"    DB connection attempt {attempt}/{retries} failed, retrying in {delay}s...")
                time.sleep(delay)
                delay *= 2
            else:
                raise
_fetch_yahoo_history function · python · L86-L140 (55 LOC)
forecast.py
def _fetch_yahoo_history(symbol: str, days: int = 365) -> pd.DataFrame | None:
    """Fetch historical daily price data from Yahoo Finance as a fallback."""
    import requests as req

    yf_symbol = YAHOO_SYMBOLS.get(symbol)
    if not yf_symbol:
        return None

    try:
        # Yahoo Finance chart API: free, no key needed
        period1 = int((datetime.now() - timedelta(days=days)).timestamp())
        period2 = int(datetime.now().timestamp())
        url = (
            f"https://query1.finance.yahoo.com/v8/finance/chart/{yf_symbol}"
            f"?period1={period1}&period2={period2}&interval=1d"
        )
        resp = req.get(url, headers={"User-Agent": "Mozilla/5.0"}, timeout=15)
        if resp.status_code != 200:
            return None

        data = resp.json()
        result = data.get("chart", {}).get("result", [])
        if not result:
            return None

        timestamps = result[0].get("timestamp", [])
        indicators = result[0].get("indicators", {
_fetch_yahoo_chart_price function · python · L143-L183 (41 LOC)
forecast.py
def _fetch_yahoo_chart_price(ticker: str) -> float | None:
    """Fetch the latest price for any Yahoo Finance ticker.

    Uses the chart API with 1-day range / 1-minute interval to get
    the most recent trade price.
    """
    import requests as req

    try:
        url = (
            f"https://query1.finance.yahoo.com/v8/finance/chart/{ticker}"
            f"?range=1d&interval=1m"
        )
        resp = req.get(url, headers={"User-Agent": "Mozilla/5.0"}, timeout=10)
        if resp.status_code != 200:
            return None

        data = resp.json()
        result = data.get("chart", {}).get("result", [])
        if not result:
            return None

        meta = result[0].get("meta", {})

        price = meta.get("regularMarketPrice")
        if price and float(price) > 0:
            return float(price)

        # Fallback: last close from intraday data
        indicators = result[0].get("indicators", {}).get("quote", [{}])[0]
        closes = indicators.get("close",
Open data scored by Repobility · https://repobility.com
_fetch_yahoo_realtime_price function · python · L186-L209 (24 LOC)
forecast.py
def _fetch_yahoo_realtime_price(symbol: str) -> float | None:
    """Fetch the latest real-time spot price for a COMEX metal symbol.

    Strategy:
    1. Try the physical-metal ETF (spot-tracking) and convert share price
       to per-ounce spot using the oz-per-share factor.
    2. Fall back to COMEX futures if the ETF is unavailable.
    """
    # ── Try spot ETF first ──
    etf_ticker, oz_per_share = SPOT_SOURCES.get(symbol, ("", 1.0))
    if etf_ticker:
        etf_price = _fetch_yahoo_chart_price(etf_ticker)
        if etf_price and etf_price > 0:
            spot = etf_price / oz_per_share
            return round(spot, 2)

    # ── Fallback to COMEX futures ──
    futures_ticker = YAHOO_SYMBOLS.get(symbol)
    if futures_ticker:
        futures_price = _fetch_yahoo_chart_price(futures_ticker)
        if futures_price and futures_price > 0:
            return round(futures_price, 2)

    return None
_load_local_json function · python · L212-L221 (10 LOC)
forecast.py
def _load_local_json(filename: str) -> dict | list | None:
    """Load a JSON file from the public directory."""
    path = os.path.join(BASE_DIR, filename)
    if os.path.exists(path):
        try:
            with open(path) as f:
                return json.load(f)
        except (json.JSONDecodeError, IOError):
            return None
    return None
_build_local_inventory_df function · python · L224-L245 (22 LOC)
forecast.py
def _build_local_inventory_df(metal: str) -> pd.DataFrame:
    """Build inventory DataFrame from local data.json."""
    data = _load_local_json("data.json")
    if not data:
        return pd.DataFrame()
    metal_key = metal.lower()
    metal_data = data.get(metal_key, {})
    if not metal_data:
        return pd.DataFrame()
    rows = []
    date_str = data.get("last_updated", "")
    date = pd.to_datetime(date_str, errors="coerce") if date_str else pd.Timestamp.now()
    reg = metal_data.get("registered", 0)
    elig = metal_data.get("eligible", 0)
    total = metal_data.get("total", reg + elig)
    rows.append({"date": date, "registered": reg, "eligible": elig, "total": total})
    df = pd.DataFrame(rows)
    df["date"] = pd.to_datetime(df["date"])
    df.set_index("date", inplace=True)
    for c in ["registered", "eligible", "total"]:
        df[c] = pd.to_numeric(df[c], errors="coerce")
    return df
_build_local_delivery_df function · python · L248-L271 (24 LOC)
forecast.py
def _build_local_delivery_df(metal: str) -> pd.DataFrame:
    """Build delivery DataFrame from local delivery.json."""
    data = _load_local_json("delivery.json")
    if not data:
        return pd.DataFrame()
    metals_data = data.get("metals", {})
    metal_data = metals_data.get(metal, {})
    if not metal_data:
        return pd.DataFrame()
    date_str = data.get("report_date", "")
    date = pd.to_datetime(date_str, errors="coerce") if date_str else pd.Timestamp.now()
    rows = [{
        "date": date,
        "settlement_price": metal_data.get("settlement_price", 0),
        "daily_issued": metal_data.get("daily_issued", 0),
        "daily_stopped": metal_data.get("daily_stopped", 0),
        "month_to_date": metal_data.get("month_to_date", 0),
    }]
    df = pd.DataFrame(rows)
    df["date"] = pd.to_datetime(df["date"])
    df.set_index("date", inplace=True)
    for c in ["settlement_price", "daily_issued", "daily_stopped", "month_to_date"]:
        df[c] = pd.to_numeric(df
_build_local_oi_df function · python · L274-L297 (24 LOC)
forecast.py
def _build_local_oi_df(metal: str) -> pd.DataFrame:
    """Build open interest DataFrame from local volume_summary.json."""
    data = _load_local_json("volume_summary.json")
    if not data:
        return pd.DataFrame()
    symbol = METALS[metal]["symbol"]
    products = data.get("products", [])
    for p in products:
        if p.get("symbol") == symbol:
            date_str = data.get("trade_date", "")
            date = pd.to_datetime(date_str, errors="coerce") if date_str else pd.Timestamp.now()
            rows = [{
                "date": date,
                "open_interest": p.get("open_interest", 0),
                "oi_change": p.get("oi_change", 0),
                "total_volume": p.get("total_volume", 0),
            }]
            df = pd.DataFrame(rows)
            df["date"] = pd.to_datetime(df["date"])
            df.set_index("date", inplace=True)
            for c in ["open_interest", "oi_change", "total_volume"]:
                df[c] = pd.to_numeric(df[c], errors=
_build_local_risk_df function · python · L300-L326 (27 LOC)
forecast.py
def _build_local_risk_df(metal: str) -> pd.DataFrame:
    """Build risk DataFrame from local analysis_summary.json."""
    data = _load_local_json("analysis_summary.json")
    if not data:
        return pd.DataFrame()
    metal_key = metal.lower()
    metal_data = data.get(metal_key, {})
    risk = metal_data.get("risk_score", {})
    if not risk:
        return pd.DataFrame()
    date_str = data.get("generated_at", "")
    date = pd.to_datetime(date_str, errors="coerce") if date_str else pd.Timestamp.now()
    rows = [{
        "date": date,
        "composite_score": risk.get("composite_score", 50),
        "coverage_risk": risk.get("coverage_risk", 50),
        "paper_physical_risk": risk.get("paper_physical_risk", 50),
        "inventory_trend_risk": risk.get("inventory_trend_risk", 50),
        "delivery_velocity_risk": risk.get("delivery_velocity_risk", 50),
        "market_activity_risk": risk.get("market_activity_risk", 50),
    }]
    df = pd.DataFrame(rows)
    df["date"] = 
fetch_all_data function · python · L329-L500 (172 LOC)
forecast.py
def fetch_all_data(metal: str, days: int = 365) -> dict:
    """Fetch all historical data for a single metal from the database,
    falling back to Yahoo Finance + local JSON files on DB failure."""
    symbol = METALS[metal]["symbol"]

    bulletin_rows = []
    inventory_rows = []
    delivery_rows = []
    oi_rows = []
    pp_rows = []
    risk_rows = []
    db_ok = False

    try:
        conn = get_db_connection()
        try:
            cur = conn.cursor()

            cur.execute("""
                SELECT date, front_month_settle, total_volume, total_open_interest, total_oi_change
                FROM bulletin_snapshots
                WHERE symbol = %s AND date >= CURRENT_DATE - %s
                ORDER BY date ASC
            """, (symbol, days))
            bulletin_rows = cur.fetchall()

            cur.execute("""
                SELECT report_date, registered, eligible, total
                FROM metal_snapshots
                WHERE metal = %s AND report_date >= CURRENT
compute_trend_signals function · python · L507-L644 (138 LOC)
forecast.py
def compute_trend_signals(prices: pd.DataFrame) -> dict:
    """Compute SMA/EMA crossovers, Bollinger Bands, RSI, MACD."""
    result = {
        "score": 50,
        "details": "Insufficient price data",
        "indicators": {},
    }
    if prices.empty or "settle" not in prices.columns:
        return result

    s = prices["settle"].dropna()
    if len(s) < 20:
        return result

    # ── Moving Averages ──────────────────────────────────────────────────
    sma5 = s.rolling(5).mean()
    sma10 = s.rolling(10).mean()
    sma20 = s.rolling(20).mean()
    sma50 = s.rolling(min(50, len(s))).mean()
    ema12 = s.ewm(span=12, adjust=False).mean()
    ema26 = s.ewm(span=26, adjust=False).mean()

    latest = s.iloc[-1]
    latest_sma5 = sma5.iloc[-1] if not np.isnan(sma5.iloc[-1]) else latest
    latest_sma20 = sma20.iloc[-1] if not np.isnan(sma20.iloc[-1]) else latest
    latest_sma50 = sma50.iloc[-1] if not np.isnan(sma50.iloc[-1]) else latest

    # SMA crossover score: +1 for ea
Source: Repobility analyzer · https://repobility.com
compute_physical_signals function · python · L651-L857 (207 LOC)
forecast.py
def compute_physical_signals(
    inventory: pd.DataFrame,
    delivery: pd.DataFrame,
    oi: pd.DataFrame,
    pp: pd.DataFrame,
    metal_config: dict,
) -> dict:
    """Compute physical market stress signals: inventory drawdown,
    delivery acceleration, squeeze score, coverage erosion, eligible flow."""
    result = {
        "score": 50,
        "details": "Insufficient physical data",
        "signals": {},
    }

    signals = {}
    score_components = []

    # ── Inventory Drawdown Signal ────────────────────────────────────────
    if not inventory.empty and "registered" in inventory.columns and len(inventory) >= 10:
        reg = inventory["registered"].dropna()
        if len(reg) >= 10:
            # 5-day change
            change_5d = reg.diff(5)
            # Z-score vs 60-day distribution
            roll_mean = change_5d.rolling(min(60, len(change_5d))).mean()
            roll_std = change_5d.rolling(min(60, len(change_5d))).std()

            latest_change = change
run_arima_forecast function · python · L864-L933 (70 LOC)
forecast.py
def run_arima_forecast(prices: pd.DataFrame, horizons: list = None) -> dict:
    """Fit auto-ARIMA and produce point forecasts with confidence intervals."""
    if horizons is None:
        horizons = [5, 20]

    result = {
        "score": 50,
        "details": "Insufficient data for ARIMA",
        "forecasts": {},
    }

    if prices.empty or "settle" not in prices.columns:
        return result

    s = prices["settle"].dropna()
    if len(s) < 30:
        return result

    current_price = float(s.iloc[-1])

    try:
        import pmdarima as pm

        # Use log returns for stationarity
        log_prices = np.log(s.values.astype(float))

        model = pm.auto_arima(
            log_prices,
            start_p=0, max_p=3,
            start_q=0, max_q=3,
            d=None,  # auto-detect differencing
            max_d=2,
            seasonal=False,
            stepwise=True,
            suppress_warnings=True,
            error_action="ignore",
            trace=False,
   
compute_market_activity function · python · L940-L1009 (70 LOC)
forecast.py
def compute_market_activity(prices: pd.DataFrame, oi: pd.DataFrame) -> dict:
    """Analyze OI expansion, volume trends, speculative pressure."""
    result = {
        "score": 50,
        "details": "Insufficient market data",
        "metrics": {},
    }

    scores = []

    # ── OI trend ─────────────────────────────────────────────────────────
    oi_series = None
    if not prices.empty and "open_interest" in prices.columns:
        oi_series = prices["open_interest"].dropna()
    elif not oi.empty and "open_interest" in oi.columns:
        oi_series = oi["open_interest"].dropna()

    if oi_series is not None and len(oi_series) >= 10:
        oi_latest = oi_series.iloc[-1]
        oi_10d_ago = oi_series.iloc[-10] if len(oi_series) >= 10 else oi_series.iloc[0]
        oi_pct = ((oi_latest - oi_10d_ago) / oi_10d_ago * 100) if oi_10d_ago > 0 else 0

        # Rising OI = new money = directional (bullish if price rising too)
        oi_score = 50 + oi_pct * 2
        oi_score = max
run_correlation_analysis function · python · L1016-L1131 (116 LOC)
forecast.py
def run_correlation_analysis(prices: pd.DataFrame, data: dict) -> dict:
    """Compute Pearson/Spearman correlations and Granger causality tests
    between physical indicators and future price returns."""
    correlations = {}

    if prices.empty or "settle" not in prices.columns:
        return correlations

    s = prices["settle"].dropna()
    if len(s) < 30:
        return correlations

    # Forward returns at various horizons
    returns_5d = s.pct_change(5).shift(-5)  # 5-day forward return
    returns_10d = s.pct_change(10).shift(-10)

    inventory = data.get("inventory", pd.DataFrame())
    delivery = data.get("delivery", pd.DataFrame())

    # ── Inventory change vs future returns ───────────────────────────────
    if not inventory.empty and "registered" in inventory.columns:
        inv_change = inventory["registered"].pct_change(5)
        # Align on shared dates
        combined = pd.DataFrame({
            "inv_change": inv_change,
            "fwd_return_5d": returns
detect_anomalies function · python · L1138-L1184 (47 LOC)
forecast.py
def detect_anomalies(data: dict) -> list:
    """Flag z-score anomalies across all metrics."""
    anomalies = []

    series_checks = []

    # Inventory changes
    inv = data.get("inventory", pd.DataFrame())
    if not inv.empty and "registered" in inv.columns:
        series_checks.append(("registered_inventory_change", inv["registered"].diff()))

    # Delivery
    deliv = data.get("delivery", pd.DataFrame())
    if not deliv.empty and "daily_issued" in deliv.columns:
        series_checks.append(("daily_deliveries", deliv["daily_issued"]))

    # Volume
    prices = data.get("prices", pd.DataFrame())
    if not prices.empty and "volume" in prices.columns:
        series_checks.append(("trading_volume", prices["volume"]))

    # OI change
    if not prices.empty and "oi_change" in prices.columns:
        series_checks.append(("oi_change", prices["oi_change"]))

    for name, series in series_checks:
        s = series.dropna()
        if len(s) < 20:
            continue
        r
detect_regime function · python · L1187-L1218 (32 LOC)
forecast.py
def detect_regime(prices: pd.DataFrame) -> str:
    """Classify market regime based on volatility structure."""
    if prices.empty or "settle" not in prices.columns:
        return "UNKNOWN"

    s = prices["settle"].dropna()
    if len(s) < 30:
        return "UNKNOWN"

    returns = s.pct_change().dropna()
    if len(returns) < 20:
        return "UNKNOWN"

    vol_short = returns.rolling(5).std().iloc[-1]
    vol_long = returns.rolling(20).std().iloc[-1]

    if np.isnan(vol_short) or np.isnan(vol_long) or vol_long == 0:
        return "UNKNOWN"

    vol_ratio = vol_short / vol_long

    # ADX-like trend strength: absolute returns vs volatility
    abs_return_20 = abs(float(s.iloc[-1] / s.iloc[-20] - 1)) if len(s) >= 20 else 0
    # Annualized vol
    ann_vol = float(vol_long) * np.sqrt(252)

    if vol_ratio > 1.5:
        return "VOLATILE"
    elif abs_return_20 > ann_vol * 0.3:
        return "TRENDING"
    else:
        return "RANGING"
composite_forecast function · python · L1225-L1326 (102 LOC)
forecast.py
def composite_forecast(
    trend: dict,
    physical: dict,
    arima: dict,
    market: dict,
) -> dict:
    """Combine all signal categories into a single directional forecast.

    v1.2.0 tuning (Feb 20, 2026) based on 14-sample accuracy analysis:
      - Physical stress: best predictor (67% bullish, 100% bearish) → raised to 0.45
      - Trend momentum: informative when directional → kept at 0.25
      - ARIMA model: inverted accuracy (43% when bullish) → halved to 0.10
      - Market activity: no predictive value (50/50 both ways) → raised slightly
        to 0.20 but dampened toward 50 to reduce noise from extreme readings
      - Direction thresholds narrowed: 55/45 (was 60/40) to capture the 7 missed
        BULLISH calls in the 55-60 composite band
      - Confidence formula reweighted: physical agreement now weighted higher
    """
    weights = {
        "trend_momentum": 0.25,
        "physical_stress": 0.45,
        "arima_model": 0.10,
        "market_activity": 0.20,
  
run_forecast_for_metal function · python · L1333-L1438 (106 LOC)
forecast.py
def run_forecast_for_metal(metal: str) -> dict:
    """Run the full forecast pipeline for a single metal."""
    print(f"  Fetching data for {metal}...")
    data = fetch_all_data(metal, days=365)

    prices = data["prices"]
    symbol = METALS[metal]["symbol"]

    # Get the last DB settle price (used for ARIMA model training)
    db_price = 0.0
    if not prices.empty and "settle" in prices.columns:
        s = prices["settle"].dropna()
        if len(s) > 0:
            db_price = float(s.iloc[-1])

    # Fetch real-time FUTURES price from Yahoo Finance.
    # Must use futures (GC=F etc.) — not spot ETFs — because the frontend
    # compares forecast current_price against live futures from /api/futures.
    print(f"    Fetching real-time futures price from Yahoo Finance...")
    futures_ticker = YAHOO_SYMBOLS.get(symbol)
    realtime_price = _fetch_yahoo_chart_price(futures_ticker) if futures_ticker else None
    if realtime_price and realtime_price > 0:
        current_price = rou
Repobility · severity-and-effort ranking · https://repobility.com
_py function · python · L1441-L1453 (13 LOC)
forecast.py
def _py(val):
    """Convert numpy types to Python native for psycopg2."""
    if val is None:
        return None
    if isinstance(val, (np.integer,)):
        return int(val)
    if isinstance(val, (np.floating,)):
        return float(val)
    if isinstance(val, np.ndarray):
        return val.tolist()
    if isinstance(val, float) and (np.isnan(val) or np.isinf(val)):
        return None
    return val
update_forecast_history function · python · L1456-L1740 (285 LOC)
forecast.py
def update_forecast_history(output: dict, json_default):
    """Write forecast snapshots to DB, evaluate past accuracy, track prices."""
    today = datetime.now().strftime("%Y-%m-%d")

    try:
        conn = get_db_connection()
    except Exception as e:
        print(f"  DB connection failed for forecast history, writing local JSON only: {e}")
        _write_accuracy_json_backup(output)
        return

    try:
        cur = conn.cursor()

        # ── 1. Create tables if they don't exist ─────────────────────────
        cur.execute("""
            CREATE TABLE IF NOT EXISTS forecast_snapshots (
                id SERIAL PRIMARY KEY,
                metal VARCHAR(50) NOT NULL,
                forecast_date DATE NOT NULL,
                direction VARCHAR(20) NOT NULL,
                confidence INTEGER NOT NULL DEFAULT 0,
                composite_score DECIMAL(6, 2) NOT NULL DEFAULT 50,
                price_at_forecast DECIMAL(15, 4) NOT NULL DEFAULT 0,
                squeeze_pr
backfill_tracking_from_settlements function · python · L1743-L1871 (129 LOC)
forecast.py
def backfill_tracking_from_settlements(conn):
    """Backfill forecast_price_tracking and forecast_accuracy with official
    COMEX settlement (close) prices from bulletin_snapshots.

    For each forecast in forecast_snapshots, finds every settlement price
    that occurred on or after the forecast date and upserts a tracking row.
    Also re-evaluates forecast_accuracy using the settlement price closest
    to the eval horizon (5 trading days) for maximum reliability.
    """
    cur = conn.cursor()

    symbol_for_metal = {m: cfg["symbol"] for m, cfg in METALS.items()}

    # Get all forecasts (last 90 days to keep it bounded)
    cur.execute("""
        SELECT id, metal, forecast_date, direction, price_at_forecast
        FROM forecast_snapshots
        WHERE forecast_date >= CURRENT_DATE - 90
        ORDER BY forecast_date DESC
    """)
    forecasts = cur.fetchall()

    if not forecasts:
        print("  No forecast snapshots found for settlement backfill")
        cur.close()
 
_query_accuracy_from_db function · python · L1874-L1935 (62 LOC)
forecast.py
def _query_accuracy_from_db(conn) -> dict | None:
    """Pull the full accuracy summary + history from the DB for JSON backup."""
    try:
        cur = conn.cursor()
        cur.execute("""
            SELECT metal, forecast_date, direction, price_at_forecast,
                   eval_date, eval_horizon_days, price_at_eval,
                   price_change_pct, correct
            FROM forecast_accuracy
            WHERE forecast_date >= CURRENT_DATE - 90
            ORDER BY forecast_date DESC, metal
        """)
        rows = cur.fetchall()
        cur.close()

        if not rows:
            return None

        metals: dict = {}
        total_correct = 0
        total_evaluated = 0
        history = []

        for metal, fdate, direction, p_fore, e_date, horizon, p_eval, pct, correct in rows:
            if metal not in metals:
                metals[metal] = {"total_forecasts": 0, "correct": 0, "incorrect": 0, "pending": 0, "hit_rate": 0}
            metals[metal]["total_forecas
_write_accuracy_json_backup function · python · L1938-L1981 (44 LOC)
forecast.py
def _write_accuracy_json_backup(output: dict, db_accuracy: dict | None = None):
    """Write a local JSON backup of forecast history for API fallback."""
    history_path = os.path.join(BASE_DIR, "forecast_history.json")
    today = datetime.now().strftime("%Y-%m-%d")

    history = {"forecasts": [], "accuracy": {}}
    if os.path.exists(history_path):
        try:
            with open(history_path) as f:
                history = json.load(f)
        except (json.JSONDecodeError, IOError):
            history = {"forecasts": [], "accuracy": {}}

    if "forecasts" not in history:
        history["forecasts"] = []

    existing_dates = {e["date"] for e in history["forecasts"]}
    if today not in existing_dates:
        entry = {"date": today, "generated_at": output["generated_at"], "calls": {}}
        for metal, fc in output["metals"].items():
            entry["calls"][metal] = {
                "direction": fc.get("direction", "NEUTRAL"),
                "confidence": fc.get("conf
main function · python · L1984-L2064 (81 LOC)
forecast.py
def main():
    print("=" * 60)
    print("COMEX METALS PRICE FORECASTING ENGINE")
    print(f"Run time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 60)

    output = {
        "generated_at": datetime.now(tz=__import__('datetime').timezone.utc).isoformat(),
        "model_version": "1.2.0",
        "metals": {},
    }

    for metal in METALS:
        print(f"\n{'─' * 40}")
        print(f"Processing {metal}...")
        try:
            forecast = run_forecast_for_metal(metal)
            output["metals"][metal] = forecast
        except Exception as e:
            print(f"  ERROR forecasting {metal}: {e}")
            output["metals"][metal] = {
                "direction": "NEUTRAL",
                "confidence": 0,
                "composite_score": 50,
                "current_price": 0,
                "forecast_5d": None,
                "forecast_20d": None,
                "squeeze_probability": 0,
                "regime": "UNKNOWN",
                "sig
_fetch_yahoo_chart_price function · python · L85-L117 (33 LOC)
forecast_sd.py
def _fetch_yahoo_chart_price(ticker: str) -> float | None:
    """Fetch the latest price for a Yahoo Finance ticker via the chart API."""
    import requests as req

    try:
        url = (
            f"https://query1.finance.yahoo.com/v8/finance/chart/{ticker}"
            f"?range=1d&interval=1m"
        )
        resp = req.get(url, headers={"User-Agent": "Mozilla/5.0"}, timeout=10)
        if resp.status_code != 200:
            return None

        data = resp.json()
        result = data.get("chart", {}).get("result", [])
        if not result:
            return None

        meta = result[0].get("meta", {})
        price = meta.get("regularMarketPrice")
        if price and float(price) > 0:
            return float(price)

        indicators = result[0].get("indicators", {}).get("quote", [{}])[0]
        closes = indicators.get("close", [])
        if closes:
            for c in reversed(closes):
                if c is not None:
                    return float(c)
        
fetch_current_price function · python · L120-L153 (34 LOC)
forecast_sd.py
def fetch_current_price(metal: str) -> float:
    """Get the current futures price for a metal. Falls back to DB settlement."""
    symbol = METALS[metal]["symbol"]
    ticker = YAHOO_FUTURES.get(symbol)
    if ticker:
        price = _fetch_yahoo_chart_price(ticker)
        if price and price > 0:
            return round(price, 2)

    conn = get_db_connection()
    try:
        cur = conn.cursor()
        cur.execute("""
            SELECT settlement_price FROM open_interest_snapshots
            WHERE symbol = %s AND settlement_price IS NOT NULL
            ORDER BY report_date DESC LIMIT 1
        """, (symbol,))
        row = cur.fetchone()
        if row and row[0]:
            cur.close()
            return round(float(row[0]), 2)

        cur.execute("""
            SELECT front_month_settle FROM bulletin_snapshots
            WHERE symbol = %s AND front_month_settle IS NOT NULL
            ORDER BY date DESC LIMIT 1
        """, (symbol,))
        row = cur.fetchone()
       
Same scanner, your repo: https://repobility.com — Repobility
get_db_connection function · python · L160-L178 (19 LOC)
forecast_sd.py
def get_db_connection(retries: int = 3, delay: float = 2.0):
    import time
    url = os.environ.get("DATABASE_URL_UNPOOLED") or os.environ.get("DATABASE_URL")
    if not url:
        raise RuntimeError("DATABASE_URL not set")
    is_pooled = "-pooler" in (url or "")
    for attempt in range(1, retries + 1):
        try:
            kwargs = dict(connect_timeout=10)
            if not is_pooled:
                kwargs["options"] = "-c statement_timeout=30000"
            return psycopg2.connect(url, **kwargs)
        except psycopg2.OperationalError as e:
            if attempt < retries:
                print(f"    DB attempt {attempt}/{retries} failed, retrying in {delay}s...")
                time.sleep(delay)
                delay *= 2
            else:
                raise
fetch_sd_data function · python · L181-L253 (73 LOC)
forecast_sd.py
def fetch_sd_data(metal: str, days: int = 365) -> dict:
    """Fetch inventory, delivery, paper/physical, and OI data from NeonDB."""
    symbol = METALS[metal]["symbol"]
    conn = get_db_connection()
    try:
        cur = conn.cursor()

        cur.execute("""
            SELECT report_date, registered, eligible, total
            FROM metal_snapshots
            WHERE metal = %s AND report_date >= CURRENT_DATE - %s
            ORDER BY report_date ASC
        """, (metal, days))
        inv_rows = cur.fetchall()

        cur.execute("""
            SELECT report_date, daily_issued, daily_stopped, month_to_date
            FROM delivery_snapshots
            WHERE metal = %s AND report_date >= CURRENT_DATE - %s
            ORDER BY report_date ASC
        """, (metal, days))
        del_rows = cur.fetchall()

        cur.execute("""
            SELECT report_date, paper_physical_ratio, registered_inventory, open_interest
            FROM paper_physical_snapshots
            WHERE me
compute_supply_signals function · python · L260-L349 (90 LOC)
forecast_sd.py
def compute_supply_signals(inventory: pd.DataFrame, pp: pd.DataFrame) -> dict:
    """Compute inventory trend, eligible flow, and paper/physical signals."""
    signals = {}
    scores = []

    # ── Inventory Trend (15%) ─────────────────────────────────────────────
    if not inventory.empty and "registered" in inventory.columns:
        reg = inventory["registered"].dropna()
        if len(reg) >= 5:
            window = min(30, len(reg) - 1)
            pct_change = ((reg.iloc[-1] - reg.iloc[-window - 1]) / reg.iloc[-window - 1] * 100
                          if reg.iloc[-window - 1] > 0 else 0)

            z_window = min(60, len(reg))
            change_5d = reg.diff(5).dropna()
            if len(change_5d) >= 5:
                roll_mean = change_5d.rolling(z_window, min_periods=5).mean().iloc[-1]
                roll_std = change_5d.rolling(z_window, min_periods=5).std().iloc[-1]
                latest_change = change_5d.iloc[-1]
                z = (latest_change - roll_mean
compute_demand_signals function · python · L356-L463 (108 LOC)
forecast_sd.py
def compute_demand_signals(
    delivery: pd.DataFrame,
    monthly_agg: list,
    metal: str,
) -> dict:
    """Compute delivery velocity, MTD pace, and YTD momentum signals."""
    signals = {}
    scores = []
    now = datetime.now()
    current_month = MONTH_NAMES[now.month - 1]
    baseline = BASELINE_2025.get(metal, {})

    # ── Delivery Velocity (20%) ───────────────────────────────────────────
    if not delivery.empty and "daily_issued" in delivery.columns:
        issued = delivery["daily_issued"].dropna()
        if len(issued) >= 5:
            avg_20 = issued.rolling(window=20, min_periods=5).mean()
            latest = issued.iloc[-1]
            latest_avg = avg_20.iloc[-1] if not np.isnan(avg_20.iloc[-1]) else 1

            accel = latest / latest_avg if latest_avg > 0 else 1.0
            score = 50 + (accel - 1.0) * 30
            score = max(0, min(100, score))

            label = ("Surging" if accel > 1.5 else
                     "Elevated" if accel > 1.2 else
 
compute_coverage_pressure function · python · L470-L523 (54 LOC)
forecast_sd.py
def compute_coverage_pressure(
    inventory: pd.DataFrame,
    delivery: pd.DataFrame,
    metal_config: dict,
) -> dict:
    """Coverage erosion with level + 5d rate-of-change blend."""
    signals = {}
    scores = []

    if (not inventory.empty and not delivery.empty
            and "registered" in inventory.columns and "daily_issued" in delivery.columns):
        reg = inventory["registered"].dropna()
        issued = delivery["daily_issued"].dropna()
        contract_size = metal_config["contract_size"]

        if len(reg) >= 2 and len(issued) >= 5 and contract_size > 0:
            rolling_avg = issued.rolling(window=20, min_periods=5).mean()
            avg_aligned = rolling_avg.reindex(reg.index, method="ffill")
            cov_series = (reg / (avg_aligned * contract_size)).replace(
                [np.inf, -np.inf], np.nan
            ).dropna()

            if len(cov_series) >= 2:
                coverage_days = cov_series.iloc[-1]
                level_score = max(0, min
_fetch_settlement_history function · python · L539-L555 (17 LOC)
forecast_sd.py
def _fetch_settlement_history(metal: str, days: int = 60) -> list[float]:
    """Return recent settlement prices (oldest→newest) from bulletin_snapshots."""
    symbol = METALS[metal]["symbol"]
    conn = get_db_connection()
    try:
        cur = conn.cursor()
        cur.execute("""
            SELECT front_month_settle
            FROM bulletin_snapshots
            WHERE symbol = %s AND front_month_settle IS NOT NULL
            ORDER BY date ASC
        """, (symbol,))
        rows = cur.fetchall()
        cur.close()
        return [float(r[0]) for r in rows if r[0] and float(r[0]) > 0]
    finally:
        conn.close()
compute_sd_price_projection function · python · L558-L627 (70 LOC)
forecast_sd.py
def compute_sd_price_projection(
    metal: str,
    current_price: float,
    composite_score: float,
    confidence: int,
) -> dict:
    """
    Generate 5-day and 20-day price projections from S&D fundamentals.

    Unlike ARIMA (which extrapolates the time-series pattern), this method:
      - Derives *direction* from the S&D composite score
      - Sizes the *move magnitude* using the score's deviation from neutral
      - Scales *range width* using realized volatility blended with long-run
        defaults (to stabilise the estimate when settlement history is short)
      - Narrows bands when S&D signal confidence is higher
    """
    if current_price <= 0:
        return {"forecast_5d": None, "forecast_20d": None}

    default_annual = DEFAULT_ANNUAL_VOL.get(metal, 0.20)
    default_daily = default_annual / np.sqrt(TRADING_DAYS_PER_YEAR)

    prices = _fetch_settlement_history(metal)
    # Deduplicate consecutive identical prices (weekends / holidays)
    deduped = [prices[0]] 
composite_sd_forecast function · python · L634-L704 (71 LOC)
forecast_sd.py
def composite_sd_forecast(
    supply: dict,
    demand: dict,
    pressure: dict,
) -> dict:
    """Combine supply, demand, and pressure into a directional call."""
    all_scores = (
        supply.get("component_scores", [])
        + demand.get("component_scores", [])
        + pressure.get("component_scores", [])
    )

    if not all_scores:
        return {
            "direction": "NEUTRAL",
            "confidence": 0,
            "composite_score": 50,
            "supply_score": 50,
            "demand_score": 50,
            "pressure_score": 50,
            "signals": {},
            "key_drivers": ["Insufficient data"],
        }

    total_weight = sum(w for _, _, w in all_scores)
    composite = sum(s * w for _, s, w in all_scores) / total_weight if total_weight > 0 else 50
    composite = round(max(0, min(100, composite)), 1)

    # Wider neutral band for a model with fewer signals
    if composite >= 57:
        direction = "BULLISH"
    elif composite <= 43:
        
Open data scored by Repobility · https://repobility.com
run_sd_forecast_for_metal function · python · L711-L751 (41 LOC)
forecast_sd.py
def run_sd_forecast_for_metal(metal: str) -> dict:
    """Run the full S&D forecast pipeline for one metal."""
    print(f"  Fetching S&D data for {metal}...")
    data = fetch_sd_data(metal, days=365)

    print(f"    Inventory rows: {len(data['inventory'])}, Delivery rows: {len(data['delivery'])}")

    print(f"    Computing supply signals...")
    supply = compute_supply_signals(data["inventory"], data["pp"])

    print(f"    Computing demand signals...")
    demand = compute_demand_signals(data["delivery"], data["monthly_agg"], metal)

    print(f"    Computing coverage pressure...")
    pressure = compute_coverage_pressure(data["inventory"], data["delivery"], METALS[metal])

    print(f"    Building composite forecast...")
    forecast = composite_sd_forecast(supply, demand, pressure)

    print(f"    Fetching current futures price...")
    current_price = fetch_current_price(metal)
    forecast["current_price"] = current_price
    print(f"    Current price: ${current_price:,.2f}"
main function · python · L754-L816 (63 LOC)
forecast_sd.py
def main():
    print("=" * 60)
    print("COMEX SUPPLY & DEMAND FORECASTER (sd-1.0.0)")
    print(f"Run time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 60)

    output = {
        "generated_at": datetime.now(tz=timezone.utc).isoformat(),
        "model_version": "sd-1.0.0",
        "metals": {},
    }

    for metal in METALS:
        print(f"\n{'─' * 40}")
        try:
            output["metals"][metal] = run_sd_forecast_for_metal(metal)
        except Exception as e:
            print(f"  ERROR: {e}")
            output["metals"][metal] = {
                "direction": "NEUTRAL",
                "confidence": 0,
                "composite_score": 50,
                "current_price": 0,
                "forecast_5d": None,
                "forecast_20d": None,
                "supply_score": 50,
                "demand_score": 50,
                "pressure_score": 50,
                "signals": {},
                "key_drivers": [f"Forecast unavailable: {str(
_py function · python · L819-L830 (12 LOC)
forecast_sd.py
def _py(val):
    """Coerce numpy / pandas scalars to native Python types for psycopg2."""
    if val is None:
        return None
    if isinstance(val, (np.integer,)):
        return int(val)
    if isinstance(val, (np.floating,)):
        v = float(val)
        return None if (np.isnan(v) or np.isinf(v)) else v
    if isinstance(val, float) and (np.isnan(val) or np.isinf(val)):
        return None
    return val
update_sd_forecast_history function · python · L833-L1005 (173 LOC)
forecast_sd.py
def update_sd_forecast_history(output: dict, json_default):
    """Write S&D forecast snapshots to DB and evaluate past accuracy."""
    today = datetime.now().strftime("%Y-%m-%d")

    try:
        conn = get_db_connection()
    except Exception as e:
        print(f"  DB connection failed for S&D forecast history: {e}")
        return

    try:
        cur = conn.cursor()

        cur.execute("""
            CREATE TABLE IF NOT EXISTS forecast_sd_snapshots (
                id SERIAL PRIMARY KEY,
                metal VARCHAR(50) NOT NULL,
                forecast_date DATE NOT NULL,
                direction VARCHAR(20) NOT NULL,
                confidence INTEGER NOT NULL DEFAULT 0,
                composite_score DECIMAL(6, 2) NOT NULL DEFAULT 50,
                price_at_forecast DECIMAL(15, 4) NOT NULL DEFAULT 0,
                supply_score DECIMAL(6, 2) DEFAULT 50,
                demand_score DECIMAL(6, 2) DEFAULT 50,
                pressure_score DECIMAL(6, 2) DEFAULT 50,
 
hashApiKey function · typescript · L22-L24 (3 LOC)
lib/api-key.ts
export function hashApiKey(raw: string): string {
  return createHash('sha256').update(raw).digest('hex');
}
validateApiKey function · typescript · L33-L46 (14 LOC)
lib/api-key.ts
export async function validateApiKey(request: Request): Promise<ValidatedKey | null> {
  const raw = extractKey(request);
  if (!raw) return null;

  const hash = hashApiKey(raw);
  const key = await getApiKeyByHash(hash);
  if (!key) return null;

  return {
    keyId: key.id,
    userId: key.user_id,
    tier: key.tier as 'free' | 'paid',
  };
}
checkApiRateLimit function · typescript · L49-L52 (4 LOC)
lib/api-key.ts
export async function checkApiRateLimit(
  keyId: number,
  tier: 'free' | 'paid',
): Promise<{ error: string; retryAfter?: number } | null> {
trackUsage function · typescript · L76-L78 (3 LOC)
lib/api-key.ts
export async function trackUsage(keyId: number): Promise<void> {
  await incrementApiUsage(keyId);
}
Source: Repobility analyzer · https://repobility.com
extractKey function · typescript · L82-L100 (19 LOC)
lib/api-key.ts
function extractKey(request: Request): string | null {
  // 1. Authorization header: Bearer hms_...
  const authHeader = request.headers.get('authorization');
  if (authHeader?.startsWith('Bearer ')) {
    const token = authHeader.slice(7).trim();
    if (token.startsWith(API_KEY_PREFIX)) return token;
  }

  // 2. Query parameter: ?apikey=hms_...
  try {
    const url = new URL(request.url);
    const param = url.searchParams.get('apikey');
    if (param?.startsWith(API_KEY_PREFIX)) return param;
  } catch {
    // ignore URL parse errors
  }

  return null;
}
isAuthorized function · typescript · L7-L15 (9 LOC)
lib/auth.ts
export function isAuthorized(request: Request): boolean {
  const authHeader = request.headers.get('authorization');
  const cronSecret = process.env.CRON_SECRET;
  if (!cronSecret) return false;
  const expected = `Bearer ${cronSecret}`;
  // Constant-time comparison to prevent timing attacks
  if (authHeader === null || authHeader.length !== expected.length) return false;
  return timingSafeEqual(Buffer.from(authHeader), Buffer.from(expected));
}
calculatePaperPhysicalRatio function · typescript · L75-L102 (28 LOC)
lib/data.ts
export function calculatePaperPhysicalRatio(
  openInterest: number,
  contractSize: number,
  registeredInventory: number
): PaperPhysicalData {
  const openInterestOz = openInterest * contractSize;
  const ratio = registeredInventory > 0 ? openInterestOz / registeredInventory : 0;
  
  // Risk levels based on how many paper claims exist per unit of physical
  let riskLevel: PaperPhysicalData['riskLevel'];
  if (ratio <= 2) {
    riskLevel = 'LOW';
  } else if (ratio <= 5) {
    riskLevel = 'MODERATE';
  } else if (ratio <= 10) {
    riskLevel = 'HIGH';
  } else {
    riskLevel = 'EXTREME';
  }
  
  return {
    openInterest,
    openInterestOz,
    registeredInventory,
    ratio,
    riskLevel,
  };
}
‹ prevpage 6 / 13next ›