Skip to content

Commit

Permalink
Remove get_lmp() function
Browse files Browse the repository at this point in the history
  • Loading branch information
ajdonnison committed Oct 20, 2017
1 parent 946698a commit 22323c6
Show file tree
Hide file tree
Showing 19 changed files with 4 additions and 862 deletions.
3 changes: 0 additions & 3 deletions pyiso/aeso.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@ def get_load(self, latest=False, yesterday=False, start_at=False, end_at=False,
else:
LOGGER.warn('No valid options were supplied.')

def get_lmp(self, latest=False, yesterday=False, start_at=False, end_at=False, **kwargs):
pass

def _get_latest_report(self, request_type):
"""
Requests the latest AESO Market Report and parses it into one of several pyiso timeseries formats.
Expand Down
21 changes: 4 additions & 17 deletions pyiso/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,25 +116,12 @@ def get_trade(self, latest=False, yesterday=False, start_at=False, end_at=False,

def get_lmp(self, latest=False, yesterday=False, start_at=False, end_at=False, **kwargs):
"""
Scrape and parse location marginal price data.
To request a specific LMP node, include kwarg `node_id`.
:param bool latest: If True, only get LMP at the one most recent available time point.
Available for all regions.
:param bool yesterday: If True, get LMP for every time point yesterday.
Not available for all regions.
:param datetime start_at: If the datetime is naive, it is assummed to be in the timezone of the Balancing Authority. The timestamp of all returned data points will be greater than or equal to this value.
If using, must provide both ``start_at`` and ``end_at`` parameters.
Not available for all regions.
:param datetime end_at: If the datetime is naive, it is assummed to be in the timezone of the Balancing Authority. The timestamp of all returned data points will be less than or equal to this value.
If using, must provide both ``start_at`` and ``end_at`` parameters.
Not available for all regions.
:return: List of dicts, each with keys ``[ba_name, timestamp, freq, market, lmp, lmp_type]``.
Timestamps are in UTC.
:rtype: list
Locational Marginal Price (LMP) is no longer considered a useful measure in reducing
carbon emissions. As such the get_lmp function has been removed. Please see
http://watttime.org/lmp for details.
"""
raise NotImplementedError('Derived classes must implement the get_lmp method.')
raise NotImplementedError('The get_lmp function is no longer supported as part of pyISO. See http://watttime.org/lmp.')

def handle_options(self, **kwargs):
"""
Expand Down
24 changes: 0 additions & 24 deletions pyiso/caiso.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,30 +202,6 @@ def get_lmp_loc(self):

return return_list

def get_lmp(self, node_id='SLAP_PGP2-APND', **kwargs):
"""
Returns a dictionary with keys of datetime.datetime objects
Values holds $/MW float
for final LMP price (i.e., LMP_TYPE Energy)
"""
if not isinstance(node_id, list):
node_id = [node_id]

if len(node_id) > 10:
# CAISO will not accept more than 10 node_ids
# to do, if less than 10 node_ids, only get requested node ids
node_list = node_id
node_id = 'ALL'

df = self.get_lmp_as_dataframe(node_id, **kwargs)
df = self._standardize_lmp_dataframe(df)

# drop non-requested nodes
if node_id == 'ALL':
df = df[df['node_id'].isin(node_list)]

return df.to_dict(orient='records')

def _standardize_lmp_dataframe(self, df):
if df.empty:
return df
Expand Down
87 changes: 0 additions & 87 deletions pyiso/ercot.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,90 +251,3 @@ def _parse_rtm_times(self, df):
df.drop(['SCEDTimestamp', 'RepeatedHourFlag'], axis=1, inplace=True)
df.rename(columns={'LMP': 'lmp', 'SettlementPoint': 'node_id'}, inplace=True)
return df

def format_lmp(self, df):
if 'SCEDTimestamp' in df.columns:
df = self._parse_rtm_times(df)
else:
df = self._parse_dam_times(df)

df.index = df.index.tz_convert('utc')

df['freq'] = self.options['freq']
df['ba_name'] = 'ERCOT'
df['market'] = self.options['market']
df['lmp_type'] = 'prc'

df.sort_index(inplace=True)
df['timestamp'] = df.index
return df

def get_lmp(self, node_id='HB_HUBAVG', **kwargs):
self.handle_options(data='lmp', node_id=node_id, **kwargs)

if self.options['market'] == self.MARKET_CHOICES.fivemin:
report_name = 'rt5m_lmp'
elif self.options['market'] == self.MARKET_CHOICES.dam:
report_name = 'dam_hrly_lmp'
elif self.options['market'] == self.MARKET_CHOICES.hourly:
raise NotImplementedError('ERCOT does not produce realtime hourly prices?')

self.now = datetime.now(pytz.utc)

if 'start_at' in self.options:
# get start and end days in local time
tz = pytz.timezone(self.TZ_NAME)
start = tz.normalize(self.options['start_at'])
end = tz.normalize(self.options['end_at'])

pieces = []
if self.options['market'] == self.MARKET_CHOICES.fivemin:
# set up periods of length 5 min
fivemin_periods = int((end-start).total_seconds()/(60*5)) + 1
p_list = [end - timedelta(minutes=5*x) for x in range(fivemin_periods)]

# warn if this could take a long time
if len(p_list) > 5:
LOGGER.warn('Making %d data requests (one for each 5min period), this could take a while' % len(p_list))

# make request for each period
for period in p_list:
try:
report = self._request_report(report_name, date=period)
pieces.append(report)
except ValueError:
pass

else:
start = datetime(start.year, start.month, start.day, tzinfo=start.tzinfo)
days_list = [end - timedelta(days=x) for x in range((end-start).days + 1)]
for day in days_list:
try:
report = self._request_report(report_name, day)
pieces.append(report)
except ValueError:
pass

# combine pieces, if any
if len(pieces) > 0:
report = pd.concat(pieces)
else:
LOGGER.warn('No ERCOT LMP found for %s' % self.options)
return []
else:
report = self._request_report(report_name, self.now)
if report is None:
report = self._request_report(report_name, self.now - timedelta(days=1))
df = self.format_lmp(report)

# strip uneeded times
df = self.slice_times(df)

# strip out unwanted nodes
if node_id:
if not isinstance(node_id, list):
node_id = [node_id]
reg = re.compile('|'.join(node_id))
df = df.ix[df['node_id'].str.contains(reg)]

return df.to_dict(orient='records')
4 changes: 0 additions & 4 deletions pyiso/ieso.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,6 @@ def get_trade(self, latest=False, yesterday=False, start_at=None, end_at=None, *
LOGGER.warn('No valid options were supplied.')
return trade_ts

def get_lmp(self, latest=False, yesterday=False, start_at=None, end_at=None, **kwargs):
raise RuntimeError('The IESO does not use locational marginal pricing. See '
'https://www.oeb.ca/oeb/_Documents/MSP/MSP_CMSC_Report_201612.pdf for details.')

def _get_report_range(self, result_ts, report_handler, parser_format, range_start, range_end):
"""
:param list result_ts: The timeseries which results which data will be appended to.
Expand Down
31 changes: 0 additions & 31 deletions pyiso/isone.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,37 +261,6 @@ def _parse_json(self, json):

return df

def get_lmp(self, node_id='INTERNALHUB', latest=True, start_at=False, end_at=False, **kwargs):
# set args
self.handle_options(data='lmp', latest=latest,
start_at=start_at, end_at=end_at, node_id=node_id, **kwargs)
# get location id
try:
locationid = self.locations[node_id.upper()]
except KeyError:
raise ValueError('No LMP data available for location %s' % node_id)

# set up storage
raw_data = []
# collect raw data
for endpoint in self.request_endpoints(locationid):
# carry out request
data = self.fetch_data(endpoint, self.auth)

# pull out data
try:
raw_data += self.parse_json_lmp_data(data)
except ValueError as e:
LOGGER.warn(e)
continue

# parse and slice
df = self._parse_json(raw_data)
df = self.slice_times(df)

# return
return df.to_dict(orient='record')

def get_morningreport(self, day=None):
"""
Retrieve the morning report
Expand Down
20 changes: 0 additions & 20 deletions pyiso/miso.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,23 +328,3 @@ def get_historical_lmp(self):
df['ba_name'] = 'MISO'

return df

def get_lmp(self, node_id='ILLINOIS.HUB', latest=True, **kwargs):
""" ILLINOIS.HUB is central """
self.handle_options(latest=latest, **kwargs)

if self.options['latest']:
df = self.get_realtime_lmp(**kwargs)

else:
df = self.get_historical_lmp()
df = self.slice_times(df)
df.reset_index(inplace=True)

# strip out unwated nodes
if node_id:
if not isinstance(node_id, list):
node_id = [node_id]
reg = re.compile('|'.join(node_id))
df = df.ix[df['node_id'].str.contains(reg)]
return df.to_dict(orient='records')
3 changes: 0 additions & 3 deletions pyiso/nbpower.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ def get_trade(self, latest=False, yesterday=False, start_at=False, end_at=False,
category=UserWarning)
return None

def get_lmp(self, latest=False, yesterday=False, start_at=False, end_at=False, **kwargs):
pass

def handle_options(self, **kwargs):
super(NBPowerClient, self).handle_options(**kwargs)
self.local_start_at = self.options['start_at'].astimezone(self.atlantic_tz) \
Expand Down
3 changes: 0 additions & 3 deletions pyiso/nspower.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ def get_trade(self, latest=False, yesterday=False, start_at=False, end_at=False,
# There's not enough information to derive trade as specified by the pyiso BaseClient.
pass

def get_lmp(self, latest=False, yesterday=False, start_at=False, end_at=False, **kwargs):
pass

def _is_valid_date_range(self):
"""
Checks whether the start_at and end_at options provided are within the date boundaries for the given
Expand Down
30 changes: 0 additions & 30 deletions pyiso/nyiso.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,36 +108,6 @@ def get_generation(self, latest=False, start_at=False, end_at=False, **kwargs):
# serialize and return
return self.serialize_faster(df, extras=extras)

def get_lmp(self, node_id='CENTRL', latest=False, start_at=False, end_at=False, **kwargs):
# node CENTRL is relatively central and seems to have low congestion costs
if node_id and not isinstance(node_id, list):
node_id = [node_id]
self.handle_options(data='lmp', latest=latest, node_id=node_id,
start_at=start_at, end_at=end_at, **kwargs)

# get data
if self.options['forecast'] or self.options.get('market', None) == self.MARKET_CHOICES.dam:
# always include today
dates_list = self.dates() + [self.local_now().date()]

# get data
df = self.get_any('damlbmp', self.parse_lmp, dates_list=dates_list)
extras = {
'ba_name': self.NAME,
'freq': self.FREQUENCY_CHOICES.hourly,
'market': self.MARKET_CHOICES.dam,
}
else:
# get data
df = self.get_any('realtime', self.parse_lmp)
extras = {
'ba_name': self.NAME,
'freq': self.FREQUENCY_CHOICES.fivemin,
'market': self.MARKET_CHOICES.fivemin,
}
# serialize and return
return self.serialize_faster(df, extras=extras)

def get_any(self, label, parser, dates_list=None):
# set up storage
pieces = []
Expand Down
3 changes: 0 additions & 3 deletions pyiso/pei.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ def get_load(self, latest=False, yesterday=False, start_at=False, end_at=False,
def get_trade(self, latest=False, yesterday=False, start_at=False, end_at=False, **kwargs):
pass

def get_lmp(self, latest=False, yesterday=False, start_at=False, end_at=False, **kwargs):
pass

def get_latest_load(self):
"""
Requests the JSON backing PEI's public "Wind Energy" page (http://www.gov.pe.ca/windenergy/chart.php)
Expand Down
36 changes: 0 additions & 36 deletions pyiso/pjm.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,39 +494,3 @@ def get_generation(self, latest=False, **kwargs):

# return
return data

def get_lmp(self, node_id='APS', latest=False, **kwargs):
""" Allegheny Power Systems is APS"""
self.handle_options(data='lmp', latest=latest, **kwargs)

# standardize node_id
if not isinstance(node_id, list):
node_id = [node_id]

if self.options['market'] == self.MARKET_CHOICES.fivemin:
if set(node_id).issubset(self.zonal_aggregate_nodes.keys()):
# get high precision LMP
(ts, df) = self.fetch_edata_point('ZonalAggregateLmp', None, None)
df = self.parse_datasnapshot_df(ts, df)
else:
df = self.fetch_oasis_data()

else:
# translate names to id numbers
node_names = []
for node in node_id:
if node in self.zonal_aggregate_nodes.keys():
node_names.append(self.zonal_aggregate_nodes[node])
else:
node_names.append(node)

# if getting from dataminer method, setup parameters
format_str = '%Y-%m-%dT%H:%M:%SZ' # "1998-04-01T05:00:00Z"
params = {'startDate': self.options['start_at'].strftime(format_str),
'endDate': self.options['end_at'].strftime(format_str),
'pnodeList': node_names}
df = self.fetch_dataminer_df(self.options['endpoint'], params=params)

df = self.slice_times(df)

return df.to_dict(orient='records')
3 changes: 0 additions & 3 deletions pyiso/sask.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ def get_load(self, latest=False, yesterday=False, start_at=False, end_at=False,
def get_trade(self, latest=False, yesterday=False, start_at=False, end_at=False, **kwargs):
pass

def get_lmp(self, latest=False, yesterday=False, start_at=False, end_at=False, **kwargs):
pass

def get_latest_load(self):
"""
Requests the "Current System Load" JSON from Sask Power's public data feeds and returns it in pyiso load format.
Expand Down
15 changes: 0 additions & 15 deletions pyiso/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,4 @@ def get_trade(ba_name, **kwargs):
# return
return data

@shared_task
def get_lmp(ba_name, node_list, **kwargs):
# get data
c = client_factory(ba_name)
data = c.get_lmp(node_list, **kwargs)

# log
if len(data) == 0:
msg = '%s: No lmp data at %s with args %s' % (ba_name, datetime.utcnow().isoformat(),
kwargs)
logger.warn(msg)

# return
return data


16 changes: 0 additions & 16 deletions tests/integration/integration_test_isone.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,3 @@ def test_lmp_past_json_format(self):
self.assertIn('BeginDate', data['FiveMinLmps']['FiveMinLmp'][0].keys())
self.assertIn('LmpTotal', data['FiveMinLmps']['FiveMinLmp'][0].keys())

def test_get_lmp_hist(self):
start_at = datetime(2017, 1, 1, 1, 0, 0, 0,
tzinfo=pytz.timezone('US/Eastern')).astimezone(pytz.utc)
end_at = start_at + timedelta(minutes=55)

prices = self.c.get_lmp('NEMASSBOST', latest=False, start_at=start_at, end_at=end_at)
self.assertEqual(len(prices), 11)
self.assertGreaterEqual(prices[0]['timestamp'], start_at)
self.assertLessEqual(prices[0]['timestamp'], start_at + timedelta(minutes=5))
self.assertEqual(prices[0]['lmp'], 36.72)

def test_get_lmp_latest(self):
prices = self.c.get_lmp('NEMASSBOST')
self.assertEqual(len(prices), 1)
self.assertLess(prices[0]['lmp'], 1500)
self.assertGreater(prices[0]['lmp'], -300)
Loading

0 comments on commit 22323c6

Please sign in to comment.