diff options
author | Navan Chauhan <navanchauhan@gmail.com> | 2025-04-27 22:35:39 -0600 |
---|---|---|
committer | Navan Chauhan <navanchauhan@gmail.com> | 2025-04-27 22:35:39 -0600 |
commit | b3654e46026f278799fe45070ae4d41567e030f3 (patch) | |
tree | 821a596fcb16016cece84e4bc013498f64d67cd0 | |
parent | 67fc7ee54c658020294a7f048afeea304118075d (diff) |
process bid based on market
-rw-r--r-- | server/services/process_bids.py | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/server/services/process_bids.py b/server/services/process_bids.py index 7e734f1..4ecbef9 100644 --- a/server/services/process_bids.py +++ b/server/services/process_bids.py @@ -3,14 +3,24 @@ from sqlalchemy.orm import Session from db import SessionLocal from models.bid import Bid from models.auth import User -from gridstatus import ISONE +from gridstatus import ISONE, NYISO, MISO from zoneinfo import ZoneInfo -NEW_ENGLAND_TZ = ZoneInfo("America/New_York") -iso = ISONE() +MARKET_ISOS = { + "ISONE": ISONE(), + "NYISO": NYISO(), + "MISO": MISO(), +} -def get_day_ahead_price(target_time: datetime) -> float: +MARKET_TIMEZONES = { + "ISONE": ZoneInfo("America/New_York"), + "NYISO": ZoneInfo("America/New_York"), + "MISO": ZoneInfo("America/Chicago"), +} + +def get_day_ahead_price(market: str, target_time: datetime) -> float: """Fetch the Day Ahead clearing price for the hour of target_time.""" + iso = MARKET_ISOS[market] df = iso.get_lmp(date=target_time.date(), market="DAY_AHEAD_HOURLY", locations="ALL") df = df.groupby("Interval Start")["LMP"].mean().reset_index() @@ -18,10 +28,11 @@ def get_day_ahead_price(target_time: datetime) -> float: if abs(row["Interval Start"] - target_time.replace(minute=0, second=0, microsecond=0)) < timedelta(minutes=30): return row["LMP"] - raise ValueError(f"No day ahead price found for {target_time}") + raise ValueError(f"No day ahead price found for {target_time} in {market}") -def get_real_time_prices(target_time: datetime) -> list[float]: +def get_real_time_prices(market: str, target_time: datetime) -> list[float]: """Fetch the Real Time 5-min prices during the hour of target_time.""" + iso = MARKET_ISOS[market] df = iso.get_lmp(date=target_time.date(), market="REAL_TIME_5_MIN", locations="ALL") df = df.groupby("Interval Start")["LMP"].mean().reset_index() @@ -39,30 +50,31 @@ def get_real_time_prices(target_time: datetime) -> list[float]: def process_bids(): db: Session = SessionLocal() - now = datetime.now(NEW_ENGLAND_TZ) + now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo("UTC")) # Step 1: Process Submitted bids submitted_bids = db.query(Bid).filter(Bid.status == "Submitted").all() for bid in submitted_bids: try: - target_time = bid.timestamp.astimezone(NEW_ENGLAND_TZ) + market = bid.market + market_tz = MARKET_TIMEZONES[market] + target_time = bid.timestamp.astimezone(market_tz) + now = now_utc.astimezone(market_tz) # Only process bids whose timestamp is already in the past if target_time > now: - print(f"Skipping future bid {bid.id} at {target_time}") + print(f"Skipping future bid {bid.id} at {target_time} ({market})") continue - print(f"Processing submitted bid {bid.id} for {target_time}") + print(f"Processing submitted bid {bid.id} for {target_time} ({market})") - day_ahead_price = get_day_ahead_price(target_time) + day_ahead_price = get_day_ahead_price(market, target_time) if bid.price >= day_ahead_price: - # Bid was accepted bid.status = "Executed" bid.pnl = None # Will be calculated later print(f"Bid {bid.id}: Executed (waiting for real-time PnL)") else: - # Bid rejected bid.status = "Fail" bid.pnl = None print(f"Bid {bid.id}: Failed (price too low)") @@ -76,24 +88,25 @@ def process_bids(): executed_bids = db.query(Bid).filter(Bid.status == "Executed").all() for bid in executed_bids: try: - target_time = bid.timestamp.astimezone(NEW_ENGLAND_TZ) + market = bid.market + market_tz = MARKET_TIMEZONES[market] + target_time = bid.timestamp.astimezone(market_tz) + now = now_utc.astimezone(market_tz) - # Only settle if the whole real-time period is over if now < target_time + timedelta(hours=1): print(f"Skipping bid {bid.id}, real-time window not complete yet") continue - print(f"Settling executed bid {bid.id} for {target_time}") + print(f"Settling executed bid {bid.id} for {target_time} ({market})") - real_time_prices = get_real_time_prices(target_time) + real_time_prices = get_real_time_prices(market, target_time) if not real_time_prices: print(f"No real-time prices available for bid {bid.id} yet") continue # Retry later avg_real_time_price = sum(real_time_prices) / len(real_time_prices) - - day_ahead_price = get_day_ahead_price(target_time) + day_ahead_price = get_day_ahead_price(market, target_time) pnl = (day_ahead_price - avg_real_time_price) * bid.quantity |