aboutsummaryrefslogtreecommitdiff
path: root/server/services/get_data.py
blob: 1b446c6cbcf96a1a1e3eaa1e0ef72be0d756e9f2 (plain)
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
from datetime import datetime, timedelta, UTC
from sqlalchemy.orm import Session
from db import SessionLocal
from models.market import MarketDataDB
from gridstatus import ISONE, MISO, NYISO
from typing import Dict, Type

MARKET_CLASSES: Dict[str, Type] = {
    "ISONE": ISONE,
    "MISO": MISO,
    "NYISO": NYISO,
}

def get_iso_instance(market: str):
    market = market.upper()
    if market not in MARKET_CLASSES:
        raise ValueError(f"Unsupported market '{market}'. Supported: {list(MARKET_CLASSES.keys())}")
    return MARKET_CLASSES[market]()

def update_market_data():
    db: Session = SessionLocal()

    for market_name in MARKET_CLASSES.keys():
        print(f"Processing {market_name}")
        iso = get_iso_instance(market_name)

        # --- Real-Time Data (5 min) ---
        last_realtime = db.query(MarketDataDB)\
            .filter(MarketDataDB.market == market_name, MarketDataDB.type == "REALTIME")\
            .order_by(MarketDataDB.timestamp.desc())\
            .first()

        if not last_realtime or (datetime.now(UTC) - last_realtime.timestamp.replace(tzinfo=UTC) > timedelta(minutes=5)):
            print(f"Getting realtime data for {market_name}")
            df = iso.get_lmp(date="latest", market="REAL_TIME_5_MIN", locations="ALL")
            df["Interval Start"] = df["Interval Start"].dt.tz_convert('UTC')
            grouped = df.groupby("Interval Start")[["LMP", "Energy", "Congestion", "Loss"]].mean().reset_index()

            for _, row in grouped.iterrows():
                if last_realtime and row["Interval Start"] <= last_realtime.timestamp.replace(tzinfo=UTC):
                    continue  # Skip old data
                entry = MarketDataDB(
                    timestamp=row["Interval Start"],
                    lmp=row["LMP"],
                    energy=row["Energy"],
                    congestion=row["Congestion"],
                    loss=row["Loss"],
                    market=market_name,
                    type="REALTIME",
                )
                db.add(entry)

        # --- Day-Ahead Hourly Data (1 hour) ---
        last_dayahead = db.query(MarketDataDB)\
            .filter(MarketDataDB.market == market_name, MarketDataDB.type == "DAYAHEAD")\
            .order_by(MarketDataDB.timestamp.desc())\
            .first()

        if not last_dayahead or (datetime.now(UTC) - last_dayahead.timestamp.replace(tzinfo=UTC) > timedelta(hours=1)):
            print(f"Getting day-ahead data for {market_name}")
            now_utc = datetime.now(UTC)
            day_ahead_date = now_utc.date()
            if now_utc.hour >= 18:  # After 6PM UTC, markets usually publish next day's data
                day_ahead_date += timedelta(days=1)
            df = iso.get_lmp(date=day_ahead_date, market="DAY_AHEAD_HOURLY", locations="ALL")
            df["Interval Start"] = df["Interval Start"].dt.tz_convert('UTC')
            grouped = df.groupby("Interval Start")[["LMP", "Energy", "Congestion", "Loss"]].mean().reset_index()

            for _, row in grouped.iterrows():
                if last_dayahead and row["Interval Start"] <= last_dayahead.timestamp.replace(tzinfo=UTC):
                    continue
                entry = MarketDataDB(
                    timestamp=row["Interval Start"],
                    lmp=row["LMP"],
                    energy=row["Energy"],
                    congestion=row["Congestion"],
                    loss=row["Loss"],
                    market=market_name,
                    type="DAYAHEAD",
                )
                db.add(entry)

    db.commit()
    db.close()

if __name__ == "__main__":
    update_market_data()