"""
daily_winners.py -- [2026-09-27] How every stock on each day's 9:28
top-30 list really did that day, whether the bot bought it or not.

Lists: trade1/sim/candidates/<date>.json (the 21 test days).
Data: Alpaca SIP (consolidated tape) -- daily bars for open / close /
previous close, 1-minute bars (9:30-16:00) for how far it ran and when.

Per stock:
  day_chg     close vs previous close (the "% change" Yahoo shows)
  open_close  close vs the 9:30 open  (what holding from the open made)
  open_high   best price vs the open  (the most you could have made from the open)
  best_run    biggest low-then-later-high move during the session
  high_time   when the day high printed (ET)
Writes daily_winners.csv and daily_winners.json next to this file.
"""
import csv
import gzip
import json
import sys
from datetime import datetime, timedelta
from pathlib import Path
from zoneinfo import ZoneInfo

HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE.parents[1]))
from alpaca_client import get_client

ET = ZoneInfo("America/New_York")
CANDS = Path("/var/www/screener/trade1/sim/candidates")


def minute_bars(client, symbols, day):
    p = HERE / "bars" / f"bars_{day}.json.gz"
    out = {}
    if p.exists():
        data = json.load(gzip.open(p, "rt"))["symbols"]
        for s in symbols:
            if s in data:
                out[s] = [(datetime.fromtimestamp(b[0], ET), b[1], b[2], b[3], b[4]) for b in data[s]["bars"]]
    d = datetime.fromisoformat(day).replace(tzinfo=ET)
    for s in symbols:
        if s not in out:
            raw = client.get_minute_bars(s, start=d.replace(hour=9, minute=30), end=d.replace(hour=16), limit=1000)
            out[s] = [(b.timestamp.astimezone(ET), float(b.open), float(b.high), float(b.low), float(b.close))
                      for b in raw]
    return out


def main():
    client = get_client()
    rows = []
    for f in sorted(CANDS.glob("*.json")):
        day = f.stem
        symbols = [c["symbol"] for c in json.load(open(f))]
        d = datetime.fromisoformat(day).replace(tzinfo=ET)
        daily = client.get_daily_bars_bulk(symbols, d - timedelta(days=10), d + timedelta(hours=20))
        mins = minute_bars(client, symbols, day)
        for s in symbols:
            db = daily.get(s, [])
            today = [b for b in db if b["t"].astimezone(ET).date() == d.date()]
            prev = [b for b in db if b["t"].astimezone(ET).date() < d.date()]
            mb = [b for b in mins.get(s, []) if "09:30" <= b[0].strftime("%H:%M") < "16:00"]
            if not today or not prev or not mb:
                continue
            t, pc = today[0], prev[-1]["c"]
            o = mb[0][1]
            hi_bar = max(mb, key=lambda b: b[2])
            run, low_so_far = 0.0, mb[0][3]
            for b in mb:
                low_so_far = min(low_so_far, b[3])
                run = max(run, b[2] / low_so_far - 1)
            rows.append({
                "date": day, "symbol": s, "prev_close": round(pc, 4), "open": round(o, 4),
                "high": round(t["h"], 4), "low": round(t["l"], 4), "close": round(t["c"], 4),
                "day_chg_pct": round((t["c"] / pc - 1) * 100, 2),
                "open_close_pct": round((t["c"] / o - 1) * 100, 2),
                "open_high_pct": round((hi_bar[2] / o - 1) * 100, 2),
                "best_run_pct": round(run * 100, 2),
                "high_time": hi_bar[0].strftime("%H:%M"),
            })
        print(day, len([r for r in rows if r["date"] == day]), "stocks", flush=True)
    with open(HERE / "daily_winners.csv", "w", newline="") as fh:
        w = csv.DictWriter(fh, fieldnames=list(rows[0]))
        w.writeheader()
        w.writerows(rows)
    json.dump(rows, open(HERE / "daily_winners.json", "w"))


if __name__ == "__main__":
    main()
