Spaces:
Running
Running
Commit
·
da5122f
1
Parent(s):
2e328ec
Improve data fetching and add real date axes to plots
Browse files- Switch from get_spp to get_dam_spp for full year data access
- Now fetches up to 180 days of ERCOT Day-Ahead Market prices
- Add actual calendar dates to plot axes (historical and forecast)
- Update plot styling with better formatting and date rotation
- Verify data source returns DAY_AHEAD_HOURLY market data
- Update UI labels to reflect DAM SPP data source
app.py
CHANGED
|
@@ -21,24 +21,23 @@ pipeline = load_pipeline()
|
|
| 21 |
|
| 22 |
# Function to fetch ERCOT electricity price data
|
| 23 |
@st.cache_data(ttl=3600) # Cache for 1 hour
|
| 24 |
-
def fetch_ercot_data(days_back=
|
| 25 |
-
"""Fetch ERCOT day-ahead market prices for the
|
| 26 |
try:
|
| 27 |
ercot = Ercot()
|
| 28 |
-
|
| 29 |
-
start_date = end_date - timedelta(days=days_back)
|
| 30 |
|
| 31 |
-
# Get day-ahead
|
| 32 |
-
df = ercot.
|
| 33 |
-
date=start_date,
|
| 34 |
-
end=end_date,
|
| 35 |
-
market="DAY_AHEAD_HOURLY",
|
| 36 |
-
)
|
| 37 |
|
| 38 |
# Get average price per day across all locations
|
| 39 |
df['Date'] = pd.to_datetime(df['Interval Start']).dt.date
|
| 40 |
daily_prices = df.groupby('Date')['SPP'].mean()
|
| 41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
# Convert to comma-separated string
|
| 43 |
price_list = daily_prices.round(2).tolist()
|
| 44 |
return ", ".join(map(str, price_list))
|
|
@@ -84,7 +83,7 @@ else:
|
|
| 84 |
default_data.strip(),
|
| 85 |
height=150
|
| 86 |
)
|
| 87 |
-
st.info("💡 Live data from ERCOT's Day-Ahead
|
| 88 |
|
| 89 |
# Convert user input into a list of numbers
|
| 90 |
def process_input(input_str):
|
|
@@ -101,9 +100,14 @@ prediction_length = st.slider("Select Forecast Horizon (Days)", min_value=1, max
|
|
| 101 |
|
| 102 |
# If data is valid, perform the forecast
|
| 103 |
if time_series_data:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
# Create a DataFrame for Chronos-2
|
| 105 |
context_df = pd.DataFrame({
|
| 106 |
-
'timestamp':
|
| 107 |
'target': time_series_data,
|
| 108 |
'id': 'ercot_prices'
|
| 109 |
})
|
|
@@ -118,22 +122,24 @@ if time_series_data:
|
|
| 118 |
target="target",
|
| 119 |
)
|
| 120 |
|
| 121 |
-
# Prepare forecast data for plotting
|
| 122 |
-
|
| 123 |
median = pred_df["predictions"].values
|
| 124 |
low = pred_df["0.1"].values
|
| 125 |
high = pred_df["0.9"].values
|
| 126 |
|
| 127 |
-
# Plot the historical and forecasted data
|
| 128 |
-
plt.figure(figsize=(
|
| 129 |
-
plt.plot(time_series_data, color="royalblue", label="Historical Prices")
|
| 130 |
-
plt.plot(
|
| 131 |
-
plt.fill_between(
|
| 132 |
-
plt.xlabel("
|
| 133 |
plt.ylabel("Price ($/MWh)")
|
| 134 |
plt.title("ERCOT Electricity Price Forecast")
|
| 135 |
plt.legend()
|
| 136 |
plt.grid(alpha=0.3)
|
|
|
|
|
|
|
| 137 |
|
| 138 |
# Show the plot in the Streamlit app
|
| 139 |
st.pyplot(plt)
|
|
|
|
| 21 |
|
| 22 |
# Function to fetch ERCOT electricity price data
|
| 23 |
@st.cache_data(ttl=3600) # Cache for 1 hour
|
| 24 |
+
def fetch_ercot_data(days_back=180):
|
| 25 |
+
"""Fetch ERCOT day-ahead market prices for the current year"""
|
| 26 |
try:
|
| 27 |
ercot = Ercot()
|
| 28 |
+
current_year = datetime.now().year
|
|
|
|
| 29 |
|
| 30 |
+
# Get day-ahead market settlement point prices for the year
|
| 31 |
+
df = ercot.get_dam_spp(year=current_year)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
# Get average price per day across all locations
|
| 34 |
df['Date'] = pd.to_datetime(df['Interval Start']).dt.date
|
| 35 |
daily_prices = df.groupby('Date')['SPP'].mean()
|
| 36 |
|
| 37 |
+
# Get the last N days
|
| 38 |
+
if len(daily_prices) > days_back:
|
| 39 |
+
daily_prices = daily_prices.tail(days_back)
|
| 40 |
+
|
| 41 |
# Convert to comma-separated string
|
| 42 |
price_list = daily_prices.round(2).tolist()
|
| 43 |
return ", ".join(map(str, price_list))
|
|
|
|
| 83 |
default_data.strip(),
|
| 84 |
height=150
|
| 85 |
)
|
| 86 |
+
st.info("💡 Live data from ERCOT's Day-Ahead Market (DAM SPP) - averaged across all settlement points per day")
|
| 87 |
|
| 88 |
# Convert user input into a list of numbers
|
| 89 |
def process_input(input_str):
|
|
|
|
| 100 |
|
| 101 |
# If data is valid, perform the forecast
|
| 102 |
if time_series_data:
|
| 103 |
+
# Create timestamps starting from today going backwards
|
| 104 |
+
end_date = datetime.now()
|
| 105 |
+
start_date = end_date - timedelta(days=len(time_series_data) - 1)
|
| 106 |
+
historical_dates = pd.date_range(start=start_date, periods=len(time_series_data), freq='D')
|
| 107 |
+
|
| 108 |
# Create a DataFrame for Chronos-2
|
| 109 |
context_df = pd.DataFrame({
|
| 110 |
+
'timestamp': historical_dates,
|
| 111 |
'target': time_series_data,
|
| 112 |
'id': 'ercot_prices'
|
| 113 |
})
|
|
|
|
| 122 |
target="target",
|
| 123 |
)
|
| 124 |
|
| 125 |
+
# Prepare forecast data for plotting with actual dates
|
| 126 |
+
forecast_dates = pd.date_range(start=end_date + timedelta(days=1), periods=prediction_length, freq='D')
|
| 127 |
median = pred_df["predictions"].values
|
| 128 |
low = pred_df["0.1"].values
|
| 129 |
high = pred_df["0.9"].values
|
| 130 |
|
| 131 |
+
# Plot the historical and forecasted data with dates
|
| 132 |
+
plt.figure(figsize=(12, 6))
|
| 133 |
+
plt.plot(historical_dates, time_series_data, color="royalblue", label="Historical Prices", linewidth=2)
|
| 134 |
+
plt.plot(forecast_dates, median, color="tomato", label="Median Forecast", linewidth=2)
|
| 135 |
+
plt.fill_between(forecast_dates, low, high, color="tomato", alpha=0.3, label="80% Prediction Interval")
|
| 136 |
+
plt.xlabel("Date")
|
| 137 |
plt.ylabel("Price ($/MWh)")
|
| 138 |
plt.title("ERCOT Electricity Price Forecast")
|
| 139 |
plt.legend()
|
| 140 |
plt.grid(alpha=0.3)
|
| 141 |
+
plt.xticks(rotation=45)
|
| 142 |
+
plt.tight_layout()
|
| 143 |
|
| 144 |
# Show the plot in the Streamlit app
|
| 145 |
st.pyplot(plt)
|