LMP Data Examples#
Walkthrough on how to query LMP data from PJM using gridstatus#
import gridstatus
import pandas as pd
iso = gridstatus.PJM()
Available Markets#
PJM has 3 LMP Markets you can query:
iso.markets
[<Markets.REAL_TIME_5_MIN: 'REAL_TIME_5_MIN'>,
<Markets.REAL_TIME_HOURLY: 'REAL_TIME_HOURLY'>,
<Markets.DAY_AHEAD_HOURLY: 'DAY_AHEAD_HOURLY'>]
Query LMPs for Hubs#
By default, the LMP methods will get data for the Hub nodes in PJM
df = iso.get_lmp(date="Jan 1, 2022", market="REAL_TIME_HOURLY")
df
Time | Market | Location | Location Name | Location Type | LMP | Energy | Congestion | Loss | |
---|---|---|---|---|---|---|---|---|---|
0 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 51217 | EASTERN HUB | HUB | 18.798216 | 18.91 | -0.038889 | -0.071229 |
1 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 51287 | WEST INT HUB | HUB | 18.821065 | 18.91 | 0.011945 | -0.099213 |
2 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 51288 | WESTERN HUB | HUB | 18.694305 | 18.91 | -0.005981 | -0.208048 |
3 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 4669664 | NEW JERSEY HUB | HUB | 18.826033 | 18.91 | -0.011720 | -0.070580 |
4 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 33092311 | CHICAGO GEN HUB | HUB | 18.661218 | 18.91 | 0.032487 | -0.279603 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
283 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 34497125 | AEP GEN HUB | HUB | 19.757741 | 19.69 | 0.418618 | -0.345877 |
284 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 34497127 | AEP-DAYTON HUB | HUB | 20.351982 | 19.69 | 0.603443 | 0.063539 |
285 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 34497151 | OHIO HUB | HUB | 20.523852 | 19.69 | 0.705424 | 0.133429 |
286 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 35010337 | DOMINION HUB | HUB | 19.111820 | 19.69 | -0.598878 | 0.025698 |
287 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 116013751 | ATSI GEN HUB | HUB | 20.403390 | 19.69 | 0.846534 | -0.128144 |
288 rows × 9 columns
Query by Date Range#
Frequently, we want to get data across multiple days. We can do that providing a start
and end
parameter
df = iso.get_lmp(
start="Dec 1, 2021",
end="Feb 1, 2022",
market="REAL_TIME_HOURLY",
location_type="HUB",
)
df
100%|██████████| 2/2 [00:13<00:00, 6.87s/it]
Time | Market | Location | Location Name | Location Type | LMP | Energy | Congestion | Loss | |
---|---|---|---|---|---|---|---|---|---|
0 | 2021-12-01 00:00:00-05:00 | REAL_TIME_HOURLY | 51217 | EASTERN HUB | HUB | 39.488020 | 90.34 | -51.079428 | 0.227448 |
1 | 2021-12-01 00:00:00-05:00 | REAL_TIME_HOURLY | 51287 | WEST INT HUB | HUB | 103.488181 | 90.34 | 14.034756 | -0.886576 |
2 | 2021-12-01 00:00:00-05:00 | REAL_TIME_HOURLY | 51288 | WESTERN HUB | HUB | 94.530357 | 90.34 | 5.212530 | -1.022173 |
3 | 2021-12-01 00:00:00-05:00 | REAL_TIME_HOURLY | 4669664 | NEW JERSEY HUB | HUB | 43.280667 | 90.34 | -45.547363 | -1.511971 |
4 | 2021-12-01 00:00:00-05:00 | REAL_TIME_HOURLY | 33092311 | CHICAGO GEN HUB | HUB | 93.695961 | 90.34 | 7.781744 | -4.425782 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
17851 | 2022-01-31 23:00:00-05:00 | REAL_TIME_HOURLY | 34497125 | AEP GEN HUB | HUB | 57.719079 | 174.60 | -103.599145 | -13.282610 |
17852 | 2022-01-31 23:00:00-05:00 | REAL_TIME_HOURLY | 34497127 | AEP-DAYTON HUB | HUB | 51.607433 | 174.60 | -112.049531 | -10.943869 |
17853 | 2022-01-31 23:00:00-05:00 | REAL_TIME_HOURLY | 34497151 | OHIO HUB | HUB | 46.798564 | 174.60 | -116.162118 | -11.640152 |
17854 | 2022-01-31 23:00:00-05:00 | REAL_TIME_HOURLY | 35010337 | DOMINION HUB | HUB | 76.087972 | 174.60 | -101.414320 | 2.901459 |
17855 | 2022-01-31 23:00:00-05:00 | REAL_TIME_HOURLY | 116013751 | ATSI GEN HUB | HUB | 75.254943 | 174.60 | -91.131780 | -8.214110 |
17856 rows × 9 columns
Query LMP All Nodes#
WARNING: There are over 10,000 unique nodes in PJM, so it’s recommended to either query for specific nodes id or use the location_type
parameter to reduce results. In the query below, you can see there are 300,000 rows for a single day.
df = iso.get_lmp(date="Jan 1, 2022", market="REAL_TIME_HOURLY", locations="ALL")
df
100%|██████████| 4/4 [00:26<00:00, 8.98s/it]
Time | Market | Location | Location Name | Location Type | LMP | Energy | Congestion | Loss | |
---|---|---|---|---|---|---|---|---|---|
0 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 1 | PJM-RTO | ZONE | 18.914703 | 18.91 | 0.000251 | 0.006118 |
1 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 3 | MID-ATL/APS | ZONE | 18.730764 | 18.91 | -0.024260 | -0.153309 |
2 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 48592 | ALDENE | LOAD | 18.980000 | 18.91 | 0.010000 | 0.060000 |
3 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 48593 | ALDENE | LOAD | 18.980000 | 18.91 | 0.010000 | 0.060000 |
4 | 2022-01-01 00:00:00-05:00 | REAL_TIME_HOURLY | 48594 | ATHENIA | LOAD | 19.160000 | 18.91 | 0.040000 | 0.210000 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
16867 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 2156112525 | STRAWTON | LOAD | 19.970000 | 19.69 | 0.690000 | -0.400000 |
16868 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 2156112528 | FREDRCKB | LOAD | 17.190000 | 19.69 | -1.860000 | -0.630000 |
16869 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 2156112529 | BOONECO | LOAD | 20.180000 | 19.69 | 0.520000 | -0.020000 |
16870 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 2156112530 | ENEWMARK | LOAD | 15.070000 | 19.69 | -4.810000 | 0.200000 |
16871 | 2022-01-01 23:00:00-05:00 | REAL_TIME_HOURLY | 2156112531 | ASHFIEPL | LOAD | 19.930000 | 19.69 | 0.120000 | 0.120000 |
316872 rows × 9 columns
Query by Location Type#
Ths following locations types are available:
iso.location_types
['ZONE',
'LOAD',
'GEN',
'AGGREGATE',
'INTERFACE',
'EXT',
'HUB',
'EHV',
'TIE',
'RESIDUAL_METERED_EDC']
df = iso.get_lmp(date="Oct 20, 2022", market="DAY_AHEAD_HOURLY", location_type="ZONE")
df
Time | Market | Location | Location Name | Location Type | LMP | Energy | Congestion | Loss | |
---|---|---|---|---|---|---|---|---|---|
0 | 2022-10-20 00:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 57.370640 | 54.72 | 2.153059 | 0.497581 |
1 | 2022-10-20 00:00:00-04:00 | DAY_AHEAD_HOURLY | 3 | MID-ATL/APS | ZONE | 60.727855 | 54.72 | 4.632658 | 1.375197 |
2 | 2022-10-20 00:00:00-04:00 | DAY_AHEAD_HOURLY | 51291 | AECO | ZONE | 42.342886 | 54.72 | -11.196601 | -1.180513 |
3 | 2022-10-20 00:00:00-04:00 | DAY_AHEAD_HOURLY | 51292 | BGE | ZONE | 67.669963 | 54.72 | 11.318235 | 1.631728 |
4 | 2022-10-20 00:00:00-04:00 | DAY_AHEAD_HOURLY | 51293 | DPL | ZONE | 43.324235 | 54.72 | -11.597814 | 0.202049 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
547 | 2022-10-20 23:00:00-04:00 | DAY_AHEAD_HOURLY | 37737283 | DUQ | ZONE | 60.057264 | 56.51 | 2.866517 | 0.680747 |
548 | 2022-10-20 23:00:00-04:00 | DAY_AHEAD_HOURLY | 116013753 | ATSI | ZONE | 60.784646 | 56.51 | 3.688361 | 0.586285 |
549 | 2022-10-20 23:00:00-04:00 | DAY_AHEAD_HOURLY | 124076095 | DEOK | ZONE | 59.636753 | 56.51 | 3.033894 | 0.092859 |
550 | 2022-10-20 23:00:00-04:00 | DAY_AHEAD_HOURLY | 970242670 | EKPC | ZONE | 60.897207 | 56.51 | 4.438691 | -0.051484 |
551 | 2022-10-20 23:00:00-04:00 | DAY_AHEAD_HOURLY | 1709725933 | OVEC | ZONE | 59.640000 | 56.51 | 3.250000 | -0.120000 |
552 rows × 9 columns
Query Real Time 5 Minute Market#
WARNING: The 5 minute market returns 12x as much data as the hourly markets. Additionally, PJM API also doesn’t allow server-side filtering to take place in most cases requiring gridstatus to download the data for all 10,000+ nodes. As a result, it is easy for Real Time 5 Minute market querys requiring download hundreds of millions 1 billion rows!
If you want to use the Real Time 5 Min market, that fastest queries will be for dates within 186 days of today (~6 months) and for specifc list of node ids.
# get last 2 weeks of data
today = pd.Timestamp.now().normalize()
start = today - pd.Timedelta(days=14)
df = iso.get_lmp(
start=start.date(), end=today, market="REAL_TIME_5_MIN", locations=iso.hub_node_ids
)
df
Time | Market | Location | Location Name | Location Type | LMP | Energy | Congestion | Loss | |
---|---|---|---|---|---|---|---|---|---|
0 | 2022-10-14 00:00:00-04:00 | REAL_TIME_5_MIN | 51217 | EASTERN HUB | HUB | 20.721253 | 164.48 | -142.712350 | -1.046397 |
1 | 2022-10-14 00:00:00-04:00 | REAL_TIME_5_MIN | 51287 | WEST INT HUB | HUB | 169.980500 | 164.48 | 6.829950 | -1.329450 |
2 | 2022-10-14 00:00:00-04:00 | REAL_TIME_5_MIN | 51288 | WESTERN HUB | HUB | 182.803712 | 164.48 | 18.450801 | -0.127089 |
3 | 2022-10-14 00:00:00-04:00 | REAL_TIME_5_MIN | 4669664 | NEW JERSEY HUB | HUB | 57.938125 | 164.48 | -103.119189 | -3.422686 |
4 | 2022-10-14 00:00:00-04:00 | REAL_TIME_5_MIN | 33092311 | CHICAGO GEN HUB | HUB | 191.714308 | 164.48 | 30.192231 | -2.957923 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
48379 | 2022-10-27 23:55:00-04:00 | REAL_TIME_5_MIN | 34497125 | AEP GEN HUB | HUB | 32.004211 | 29.41 | 3.137632 | -0.543421 |
48380 | 2022-10-27 23:55:00-04:00 | REAL_TIME_5_MIN | 34497127 | AEP-DAYTON HUB | HUB | 30.415964 | 29.41 | 1.140577 | -0.134613 |
48381 | 2022-10-27 23:55:00-04:00 | REAL_TIME_5_MIN | 34497151 | OHIO HUB | HUB | 29.709691 | 29.41 | 0.484335 | -0.184644 |
48382 | 2022-10-27 23:55:00-04:00 | REAL_TIME_5_MIN | 35010337 | DOMINION HUB | HUB | 33.407267 | 29.41 | 3.470406 | 0.526861 |
48383 | 2022-10-27 23:55:00-04:00 | REAL_TIME_5_MIN | 116013751 | ATSI GEN HUB | HUB | 29.916364 | 29.41 | 0.805000 | -0.298636 |
48384 rows × 9 columns
Get List of Node Ids#
Here are all pnodes ids in PJM. You can supply a list of these Ids to the LMP methods
iso.get_pnode_ids()
pnode_id | pnode_name | pnode_type | pnode_subtype | zone | voltage_level | effective_date | termination_date | |
---|---|---|---|---|---|---|---|---|
0 | 1 | PJM-RTO | AGGREGATE | ZONE | None | None | 2017-09-08T00:00:00 | 9999-12-31T00:00:00 |
1 | 3 | MID-ATL/APS | AGGREGATE | ZONE | None | None | 2017-09-08T00:00:00 | 9999-12-31T00:00:00 |
2 | 48592 | ALDENE 230 KV T-10 | BUS | LOAD | PSEG | 230 KV | 1998-04-01T00:00:00 | 9999-12-31T00:00:00 |
3 | 48593 | ALDENE 230 KV T-20 | BUS | LOAD | PSEG | 230 KV | 1998-04-01T00:00:00 | 9999-12-31T00:00:00 |
4 | 48594 | ATHENIA 26 KV AB GRP | BUS | LOAD | PSEG | 26 KV | 1998-04-01T00:00:00 | 9999-12-31T00:00:00 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
13426 | 2156113476 | FINLEY 34.5 KV MADSNFSP | BUS | GEN | ATSI | 34.5 KV | 2022-09-14T00:00:00 | 9999-12-31T00:00:00 |
13427 | 2156113479 | MIDWAYAP69 KV T2 | BUS | LOAD | AEP | 69 KV | 2022-09-14T00:00:00 | 9999-12-31T00:00:00 |
13428 | 2156113482 | ZOAR 69 KV LOAD2 | BUS | LOAD | DPL | 69 KV | 2022-09-14T00:00:00 | 9999-12-31T00:00:00 |
13429 | 2156113488 | BERGEN 13 KV CC12 | BUS | GEN | PSEG | 13 KV | 2022-09-14T00:00:00 | 9999-12-31T00:00:00 |
13430 | 2156113489 | PLAUDERV69 KV T-1 | BUS | LOAD | PSEG | 69 KV | 2022-09-14T00:00:00 | 9999-12-31T00:00:00 |
13431 rows × 8 columns
now, let’s query for the the the PJM-RTO aggregate now
df = iso.get_lmp(date="Oct 20, 2022", market="DAY_AHEAD_HOURLY", locations=[1])
df
Time | Market | Location | Location Name | Location Type | LMP | Energy | Congestion | Loss | |
---|---|---|---|---|---|---|---|---|---|
0 | 2022-10-20 00:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 57.370640 | 54.72 | 2.153059 | 0.497581 |
1 | 2022-10-20 01:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 53.118188 | 54.03 | -0.916510 | 0.004698 |
2 | 2022-10-20 02:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 52.357050 | 52.97 | -0.661017 | 0.048067 |
3 | 2022-10-20 03:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 51.968350 | 52.67 | -0.735021 | 0.033372 |
4 | 2022-10-20 04:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 58.270352 | 57.71 | 0.488189 | 0.072163 |
5 | 2022-10-20 05:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 78.918173 | 73.54 | 4.581979 | 0.796194 |
6 | 2022-10-20 06:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 111.482429 | 111.42 | -0.860157 | 0.922586 |
7 | 2022-10-20 07:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 141.522183 | 162.41 | -22.718360 | 1.830543 |
8 | 2022-10-20 08:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 92.742358 | 86.52 | 5.317530 | 0.904828 |
9 | 2022-10-20 09:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 78.046675 | 75.08 | 2.373309 | 0.593366 |
10 | 2022-10-20 10:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 71.461006 | 67.17 | 3.550270 | 0.740737 |
11 | 2022-10-20 11:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 67.391298 | 63.44 | 3.351851 | 0.599447 |
12 | 2022-10-20 12:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 59.898998 | 57.02 | 2.432226 | 0.446772 |
13 | 2022-10-20 13:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 57.047229 | 54.41 | 2.222160 | 0.415069 |
14 | 2022-10-20 14:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 55.750743 | 53.18 | 2.103888 | 0.466855 |
15 | 2022-10-20 15:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 56.004786 | 52.70 | 2.676527 | 0.628259 |
16 | 2022-10-20 16:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 59.055499 | 55.93 | 2.661120 | 0.464379 |
17 | 2022-10-20 17:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 74.196218 | 69.57 | 3.867521 | 0.758697 |
18 | 2022-10-20 18:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 106.760014 | 98.05 | 7.575480 | 1.134534 |
19 | 2022-10-20 19:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 107.722684 | 97.65 | 8.490467 | 1.582216 |
20 | 2022-10-20 20:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 83.804392 | 75.47 | 7.328402 | 1.005990 |
21 | 2022-10-20 21:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 73.693442 | 68.26 | 4.722441 | 0.711001 |
22 | 2022-10-20 22:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 64.478629 | 61.12 | 2.886036 | 0.472593 |
23 | 2022-10-20 23:00:00-04:00 | DAY_AHEAD_HOURLY | 1 | PJM-RTO | ZONE | 58.552146 | 56.51 | 1.602791 | 0.439355 |