JavadBayazi commited on
Commit
3cee5b7
·
1 Parent(s): cc69238

Add ERCOT electricity market data integration

Browse files

- Add gridstatus dependency for fetching live ERCOT data
- Implement fetch_ercot_data() to pull Day-Ahead Hourly Market prices
- Replace sample data with real electricity prices ($/MWh)
- Add data source selector (Live ERCOT vs Custom Data)
- Update UI labels and context for electricity market forecasting
- Change forecast horizon from months to days
- Add forecast summary metrics with price statistics

Files changed (2) hide show
  1. app.py +86 -25
  2. requirements.txt +1 -0
app.py CHANGED
@@ -4,6 +4,8 @@ import torch
4
  from chronos import Chronos2Pipeline
5
  import matplotlib.pyplot as plt
6
  import numpy as np
 
 
7
 
8
  # Load the Chronos Pipeline model
9
  @st.cache_resource
@@ -17,27 +19,73 @@ def load_pipeline():
17
 
18
  pipeline = load_pipeline()
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  # Streamlit app interface
21
- st.title("Time Series Forecasting Demo with Chronos-2")
22
- st.write("This demo uses **Chronos-2**, Amazon's state-of-the-art pretrained model for zero-shot time series forecasting.")
23
-
24
- # Default time series data (comma-separated)
25
- default_data = """
26
- 112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141, 135, 125, 149, 170, 170, 158,
27
- 133, 114, 140, 145, 150, 178, 163, 172, 178, 199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218,
28
- 230, 242, 209, 191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201, 204, 188, 235,
29
- 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267, 269, 270, 315, 364, 347, 312, 274, 237, 278,
30
- 284, 277, 317, 313, 318, 374, 413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404,
31
- 347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337, 360, 342, 406, 396, 420, 472,
32
- 548, 559, 463, 407, 362, 405, 417, 391, 419, 461, 472, 535, 622, 606, 508, 461, 390, 432
 
 
 
 
33
  """
34
 
35
- # Input field for user-provided data
36
- user_input = st.text_area(
37
- "Enter time series data (comma-separated values):",
38
- default_data.strip()
 
39
  )
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  # Convert user input into a list of numbers
42
  def process_input(input_str):
43
  return [float(x.strip()) for x in input_str.split(",")]
@@ -48,16 +96,16 @@ except ValueError:
48
  st.error("Please make sure all values are numbers, separated by commas.")
49
  time_series_data = [] # Set empty data on error to prevent further processing
50
 
51
- # Select the number of months for forecasting
52
- prediction_length = st.slider("Select Forecast Horizon (Months)", min_value=1, max_value=64, value=12)
53
 
54
  # If data is valid, perform the forecast
55
  if time_series_data:
56
  # Create a DataFrame for Chronos-2
57
  context_df = pd.DataFrame({
58
- 'timestamp': pd.date_range(start='2020-01-01', periods=len(time_series_data), freq='ME'),
59
  'target': time_series_data,
60
- 'id': 'series_1'
61
  })
62
 
63
  # Make the forecast using Chronos-2 API
@@ -77,15 +125,28 @@ if time_series_data:
77
  high = pred_df["0.9"].values
78
 
79
  # Plot the historical and forecasted data
80
- plt.figure(figsize=(8, 4))
81
- plt.plot(time_series_data, color="royalblue", label="Historical data")
82
- plt.plot(forecast_index, median, color="tomato", label="Median forecast")
83
- plt.fill_between(forecast_index, low, high, color="tomato", alpha=0.3, label="80% prediction interval")
 
 
 
84
  plt.legend()
85
- plt.grid()
86
 
87
  # Show the plot in the Streamlit app
88
  st.pyplot(plt)
 
 
 
 
 
 
 
 
 
 
89
 
90
  # Note for comments, feedback, or questions
91
  st.write("### Notes")
 
4
  from chronos import Chronos2Pipeline
5
  import matplotlib.pyplot as plt
6
  import numpy as np
7
+ from gridstatus import Ercot
8
+ from datetime import datetime, timedelta
9
 
10
  # Load the Chronos Pipeline model
11
  @st.cache_resource
 
19
 
20
  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=60):
25
+ """Fetch ERCOT day-ahead market prices for the last N days"""
26
+ try:
27
+ ercot = Ercot()
28
+ end_date = datetime.now()
29
+ start_date = end_date - timedelta(days=days_back)
30
+
31
+ # Get day-ahead hourly market settlement point prices
32
+ df = ercot.get_spp(
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))
45
+ except Exception as e:
46
+ st.warning(f"Could not fetch live ERCOT data: {e}. Using sample data instead.")
47
+ return None
48
+
49
  # Streamlit app interface
50
+ st.title("Electricity Market Price Forecasting with Chronos-2")
51
+ st.write("This demo uses **Chronos-2** to forecast electricity prices from ERCOT (Texas) market data.")
52
+
53
+ # Fetch default ERCOT data
54
+ with st.spinner("Fetching latest ERCOT electricity prices..."):
55
+ ercot_data = fetch_ercot_data()
56
+
57
+ # Fallback to sample data if fetching fails
58
+ default_data = ercot_data if ercot_data else """
59
+ 25.50, 24.80, 26.30, 23.90, 25.10, 27.20, 28.50, 26.70, 24.30, 23.80, 25.40, 26.10, 27.80, 29.20, 28.40,
60
+ 26.90, 25.30, 24.70, 26.50, 28.10, 29.60, 31.20, 30.50, 28.80, 27.10, 25.90, 27.30, 28.70, 30.20, 32.10,
61
+ 31.40, 29.70, 28.20, 26.80, 28.40, 29.80, 31.50, 33.20, 32.60, 30.90, 29.30, 27.80, 29.40, 30.90, 32.70,
62
+ 34.50, 33.80, 32.10, 30.50, 28.90, 30.50, 32.10, 33.90, 35.80, 35.10, 33.30, 31.60, 30.10, 31.70, 33.40,
63
+ 35.20, 37.10, 36.40, 34.60, 32.90, 31.30, 32.90, 34.60, 36.50, 38.40, 37.70, 35.80, 34.10, 32.50, 34.20,
64
+ 35.90, 37.80, 39.80, 39.10, 37.10, 35.40, 33.70, 35.40, 37.20, 39.20, 41.20, 40.50, 38.50, 36.70, 35.00,
65
+ 36.70, 38.50, 40.60, 42.60, 41.90, 39.90, 38.00, 36.30, 38.00, 39.90, 42.00, 44.10, 43.40, 41.30, 39.40
66
  """
67
 
68
+ # Data source selection
69
+ data_source = st.radio(
70
+ "Select Data Source:",
71
+ ["Live ERCOT Data (Last 180 Days)", "Custom Data"],
72
+ index=0
73
  )
74
 
75
+ # Input field for user-provided data
76
+ if data_source == "Custom Data":
77
+ user_input = st.text_area(
78
+ "Enter time series data (comma-separated values):",
79
+ ""
80
+ )
81
+ else:
82
+ user_input = st.text_area(
83
+ "ERCOT Day-Ahead Hourly Market Prices ($/MWh) - Daily Average:",
84
+ default_data.strip(),
85
+ height=150
86
+ )
87
+ st.info("💡 Live data from ERCOT's Day-Ahead Hourly Market - averaged across all settlement points per day")
88
+
89
  # Convert user input into a list of numbers
90
  def process_input(input_str):
91
  return [float(x.strip()) for x in input_str.split(",")]
 
96
  st.error("Please make sure all values are numbers, separated by commas.")
97
  time_series_data = [] # Set empty data on error to prevent further processing
98
 
99
+ # Select the number of days for forecasting
100
+ prediction_length = st.slider("Select Forecast Horizon (Days)", min_value=1, max_value=64, value=14)
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': pd.date_range(start='2024-01-01', periods=len(time_series_data), freq='D'),
107
  'target': time_series_data,
108
+ 'id': 'ercot_prices'
109
  })
110
 
111
  # Make the forecast using Chronos-2 API
 
125
  high = pred_df["0.9"].values
126
 
127
  # Plot the historical and forecasted data
128
+ plt.figure(figsize=(10, 5))
129
+ plt.plot(time_series_data, color="royalblue", label="Historical Prices")
130
+ plt.plot(forecast_index, median, color="tomato", label="Median Forecast")
131
+ plt.fill_between(forecast_index, low, high, color="tomato", alpha=0.3, label="80% Prediction Interval")
132
+ plt.xlabel("Days")
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)
140
+
141
+ # Display forecast statistics
142
+ st.write("### Forecast Summary")
143
+ col1, col2, col3 = st.columns(3)
144
+ with col1:
145
+ st.metric("Median Forecast", f"${median.mean():.2f}/MWh")
146
+ with col2:
147
+ st.metric("Low (10th percentile)", f"${low.mean():.2f}/MWh")
148
+ with col3:
149
+ st.metric("High (90th percentile)", f"${high.mean():.2f}/MWh")
150
 
151
  # Note for comments, feedback, or questions
152
  st.write("### Notes")
requirements.txt CHANGED
@@ -5,3 +5,4 @@ git+https://github.com/amazon-science/chronos-forecasting.git
5
  matplotlib
6
  pandas
7
  pyarrow
 
 
5
  matplotlib
6
  pandas
7
  pyarrow
8
+ gridstatus