aboutsummaryrefslogtreecommitdiff
path: root/server/api/market.py
diff options
context:
space:
mode:
Diffstat (limited to 'server/api/market.py')
-rw-r--r--server/api/market.py73
1 files changed, 46 insertions, 27 deletions
diff --git a/server/api/market.py b/server/api/market.py
index 5102f03..a1f25ec 100644
--- a/server/api/market.py
+++ b/server/api/market.py
@@ -1,30 +1,45 @@
-from fastapi import APIRouter
+from fastapi import APIRouter, Query, HTTPException
from models.market import MarketData
-from gridstatus import ISONE
+from gridstatus import ISONE, CAISO, Ercot, MISO, NYISO, PJM
from datetime import datetime, timedelta
-from typing import List
+from typing import List, Dict, Type
router = APIRouter()
-# Keeping the scope of this api to just one market right now
-iso = ISONE()
+MARKET_CLASSES: Dict[str, Type] = {
+ "ISONE": ISONE,
+ # "CAISO": CAISO,
+ # "ERCOT": Ercot,
+ "MISO": MISO,
+ "NYISO": NYISO,
+ # "PJM": PJM,
+}
# In-memory cache
-_cached_day_ahead: List[MarketData] = []
-_cache_timestamp: datetime | None = None
-_cached_real_time: List[MarketData] = []
-_cache_real_time_timestamp: datetime | None = None
+_cached_day_ahead: Dict[str, List[MarketData]] = {}
+_cached_day_ahead_timestamp: Dict[str, datetime] = {}
+_cached_real_time: Dict[str, List[MarketData]] = {}
+_cached_real_time_timestamp: Dict[str, datetime] = {}
-# TODO: Error Handling
-@router.get("/day-ahead", response_model=list[MarketData])
-def get_day_ahead_data():
- global _cached_day_ahead, _cache_timestamp
+def get_iso_instance(market: str):
+ market = market.upper()
+ if market not in MARKET_CLASSES:
+ raise HTTPException(status_code=400, detail=f"Unsupported market '{market}'. Supported: {list(MARKET_CLASSES.keys())}")
+ return MARKET_CLASSES[market]()
+@router.get("/day-ahead", response_model=List[MarketData])
+def get_day_ahead_data(market: str = Query("ISONE")):
now = datetime.utcnow()
- if _cache_timestamp is None or now - _cache_timestamp > timedelta(hours=1):
+ market = market.upper()
+
+ if (market not in _cached_day_ahead_timestamp or
+ now - _cached_day_ahead_timestamp[market] > timedelta(hours=1)):
+
+ iso = get_iso_instance(market)
df = iso.get_lmp(date=datetime.now().date(), market="DAY_AHEAD_HOURLY", locations="ALL")
- grouped = (df.groupby("Interval Start")[["LMP", "Energy", "Congestion", "Loss"]].mean().reset_index())
- _cached_day_ahead = [
+ grouped = df.groupby("Interval Start")[["LMP", "Energy", "Congestion", "Loss"]].mean().reset_index()
+
+ _cached_day_ahead[market] = [
MarketData(
timestamp=row["Interval Start"],
lmp=row["LMP"],
@@ -34,19 +49,23 @@ def get_day_ahead_data():
)
for _, row in grouped.iterrows()
]
- _cache_timestamp = now
-
- return _cached_day_ahead
+ _cached_day_ahead_timestamp[market] = now
-@router.get("/real-time", response_model=list[MarketData])
-def get_real_time_data():
- global _cached_real_time, _cache_real_time_timestamp
+ return _cached_day_ahead[market]
+@router.get("/real-time", response_model=List[MarketData])
+def get_real_time_data(market: str = Query("ISONE")):
now = datetime.utcnow()
- if _cache_real_time_timestamp is None or now - _cache_real_time_timestamp > timedelta(minutes=5):
+ market = market.upper()
+
+ if (market not in _cached_real_time_timestamp or
+ now - _cached_real_time_timestamp[market] > timedelta(minutes=5)):
+
+ iso = get_iso_instance(market)
df = iso.get_lmp(date="today", market="REAL_TIME_5_MIN", locations="ALL")
- grouped = (df.groupby("Interval Start")[["LMP", "Energy", "Congestion", "Loss"]].mean().reset_index())
- _cached_real_time = [
+ grouped = df.groupby("Interval Start")[["LMP", "Energy", "Congestion", "Loss"]].mean().reset_index()
+
+ _cached_real_time[market] = [
MarketData(
timestamp=row["Interval Start"],
lmp=row["LMP"],
@@ -56,6 +75,6 @@ def get_real_time_data():
)
for _, row in grouped.iterrows()
]
- _cache_real_time_timestamp = now
+ _cached_real_time_timestamp[market] = now
- return _cached_real_time
+ return _cached_real_time[market]