Spaces:
Sleeping
Sleeping
File size: 5,719 Bytes
694c11f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | """Warm the runtime caches that ship inside data/metrics.db.
The deployed Space reads the committed database, cache tables included, so
whatever is warm at commit time is what production can serve. Until now that
set was incidental β it held whatever a developer happened to run locally,
which meant a missing production credential or a blocked endpoint stayed hidden
behind a cache entry that made the feature look healthy.
This makes the set deliberate. Run it before a deploy, then commit data/, and
the preflight will report exactly which tickers production can serve.
Two of these fetchers exist precisely because the Space cannot make the call
itself:
* price reaction β Yahoo's price-history endpoint refuses datacenter
addresses far more readily than its fundamentals endpoints
* adjusted EPS β needs ALPHAVANTAGE_API_KEY_1, which lives in the local
.env and must also be set as a Space secret for anything beyond the warmed
snapshot to work
Usage::
python scripts/warm_runtime_cache.py # every ingested ticker
python scripts/warm_runtime_cache.py AAPL NVDA
python scripts/warm_runtime_cache.py --refresh # ignore existing TTLs
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from dotenv import load_dotenv
load_dotenv()
def _known_tickers() -> list[str]:
import sqlite3
from storage.metrics_db import DB_PATH
if not DB_PATH.exists():
return []
with sqlite3.connect(DB_PATH) as conn:
return [row[0] for row in conn.execute(
"SELECT DISTINCT ticker FROM metrics ORDER BY ticker"
)]
def _warm_one(ticker: str, refresh: bool) -> list[tuple[str, str]]:
"""Return [(feature, outcome)] for one ticker."""
results: list[tuple[str, str]] = []
# ββ Trading multiples and peer comparison ββ
try:
from analytics.valuation import fetch_multiples
data, err = fetch_multiples(ticker)
results.append(("valuation", "ok" if data else f"FAILED: {err}"))
except Exception as exc:
results.append(("valuation", f"FAILED: {exc}"))
# ββ 8-K filing stream. Both windows are warmed: the timeline reads 18
# months, the earnings-event provenance reads 36. ββ
for months in (18, 36):
try:
from analytics.filing_events import fetch_events
events, err = fetch_events(ticker, months=months)
results.append((
f"filing_events:{months}m",
f"ok ({len(events)} filings)" if not err else f"FAILED: {err}",
))
except Exception as exc:
results.append((f"filing_events:{months}m", f"FAILED: {exc}"))
# ββ Balance-sheet ratios ββ
try:
from analytics.working_capital import compute as compute_wc
rows, err = compute_wc(ticker)
results.append((
"working_capital",
f"ok ({len(rows)} quarters)" if rows else f"FAILED: {err}",
))
except Exception as exc:
results.append(("working_capital", f"FAILED: {exc}"))
# ββ Adjusted EPS (Alpha Vantage) β also backs the surprise history ββ
quarters: list[dict] = []
try:
from dashboard.financials import _load_surprises
quarters, err = _load_surprises(ticker)
results.append((
"earnings/surprises",
f"ok ({len(quarters)} quarters)" if quarters else f"FAILED: {err}",
))
except ValueError:
results.append((
"earnings/surprises",
"FAILED: ALPHAVANTAGE_API_KEY_1 not set locally",
))
except Exception as exc:
results.append(("earnings/surprises", f"FAILED: {exc}"))
# ββ GAAP vs adjusted gap (needs the earnings payload above) ββ
try:
from analytics.eps_quality import compute as compute_eps
rows, err = compute_eps(ticker)
results.append((
"eps_quality",
f"ok ({len(rows)} quarters)" if rows else f"FAILED: {err}",
))
except Exception as exc:
results.append(("eps_quality", f"FAILED: {exc}"))
# ββ Post-earnings price moves ββ
try:
from analytics.price_reaction import compute as compute_reaction
dates = [q["reported_date"] for q in quarters if q.get("reported_date")]
if not dates:
results.append(("price_reaction", "skipped: no earnings dates"))
else:
returns, err = compute_reaction(ticker, dates, refresh=refresh)
results.append((
"price_reaction",
f"ok ({len(returns)} quarters)" if returns
else f"FAILED: {err or 'provider returned nothing'}",
))
except Exception as exc:
results.append(("price_reaction", f"FAILED: {exc}"))
return results
def main(argv: list[str]) -> int:
refresh = "--refresh" in argv
tickers = [a.upper() for a in argv if not a.startswith("--")] or _known_tickers()
if not tickers:
print("No ingested tickers found. Run ingest.py first.")
return 1
failures = 0
for ticker in tickers:
print(f"\n=== {ticker} ===")
for feature, outcome in _warm_one(ticker, refresh):
print(f" {feature:22s} {outcome}")
if outcome.startswith("FAILED"):
failures += 1
print(
f"\nWarmed {len(tickers)} ticker(s)."
+ (f" {failures} feature(s) could not be warmed." if failures else "")
)
print("Commit data/ so the Space serves this snapshot.")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
|