aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNavan Chauhan <navanchauhan@gmail.com>2025-04-27 22:35:39 -0600
committerNavan Chauhan <navanchauhan@gmail.com>2025-04-27 22:35:39 -0600
commitb3654e46026f278799fe45070ae4d41567e030f3 (patch)
tree821a596fcb16016cece84e4bc013498f64d67cd0
parent67fc7ee54c658020294a7f048afeea304118075d (diff)
process bid based on market
-rw-r--r--server/services/process_bids.py51
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