Short-run marginal costs (SRMC) =============================== This page shows how to do short-run marginal cost (SRMC) calculations on OHLC data. All examples below expects you to have an initialized instance of the client called ``eq``. Operations described here are available under ``eq.srmc.*``. **Requirements:** Use these operations for the following curves: * Either **gas** or **coal** curves with ``curve_type = OHLC`` .. important:: We recommend reading the section on :doc:`OHLC data <../userguide/ohlc>` before continuing. These operations run SRMC calculations on OHLC data, so it would help if you were familiar with Energy Quantified's take on closing prices. On calculations --------------- Energy Quantified supports SRMC calculations for **gas** and **coal**. We calculate short-run marginal costs on-the-fly from closing prices: * You can override all factors in our SRMC calculation, such as efficiency, carbon emission factor and conversion rates (except for currency conversion). * Results from SRMC calculations are in **€/MWh**. Currency conversion is using **reference rates** from the **European Central Bank (ECB)**. * We use the **trading date** for the contract when deciding the **currency conversion rate** to use. * Some countries, such as the UK, has an **additional tax** (18 GBP/t as of this writing). It is supported in our implementation and is converted to EUR/t and added to the EUA price when provided. * Gas contracts are traded with the assumption of effectiveness in **higher-heating value**, but the power market uses **lower-heating value**. We support this conversion. **Note:** We use settlement prices in the OHLC calculations. When returning OHLC data for SRMC, only the ``settlement`` field is set. More details, such as the formulas used, are available in the SRMC article on Energy Quantified's `Knowledge base `_ (login required). Load SRMC --------- Method references: :py:meth:`eq.srmc.load_front() ` and :py:meth:`eq.srmc.load_delivery() ` Calculating historical short-run marginal costs is very similar to `loading historical OHLC data <../userguide/ohlc.html#load-ohlc-data>`__. However, because SRMC calculations require you to either specify a **front** contract or a **specific** contract, we have split ``load()`` into two methods. The difference between ``load_front()`` and ``load_delivery()`` is that the first requires a **front** parameter and the second requires a **delivery** parameter. For a continuous front contract ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To calculate SRMC for the coal API2 front contract, specify the **curve**, **begin**, **end**, **period** and **front**: >>> from datetime import date >>> from energyquantified.metadata import ContractPeriod >>> srmc_coal = eq.srmc.load_front( >>> 'Futures Coal API-2 USD/t ICE OHLC', >>> begin=date(2020, 12, 1), # or begin='2020-01-01' >>> end=date(2020, 12, 30), # or end='2020-01-06' >>> period=ContractPeriod.MONTH, >>> front=1, >>> ) The response is an :py:class:`SRMC ` object. It has a curve, a contract (specifying that it is a front-month contract), an ``SRMCOptions`` object with all factors used in the calculation, and a list of OHLC objects: >>> srmc_coal , options=, ohlc=, , ...]> > For a specific contract ^^^^^^^^^^^^^^^^^^^^^^^ Similar to front contracts, you can get the SRMC for a specific contract by only changing the function to ``load_delivery()`` and swap out the **front** parameter with a **delivery** date: >>> from datetime import date >>> from energyquantified.metadata import ContractPeriod >>> srmc_coal = eq.srmc.load_delivery( # load_delivery() >>> 'Futures Coal API-2 USD/t ICE OHLC', >>> begin=date(2020, 12, 1), >>> end=date(2020, 12, 30), >>> period=ContractPeriod.MONTH, >>> delivery=date(2021, 3, 1), # March 2021 >>> ) The result is also very similar, except that the **contract** is now a ``SpecificContract`` while previously it was a ``ContinuousContract``: >>> srmc_coal , options=, ohlc=, , ...]> > You can extract any of these attributes: >>> srmc_coal.curve >>> srmc_coal.contract >>> srmc_coal.options >>> srmc_coal.ohlc [, open=, high=, low=, close=, settlement=40.96, volume=, open_interest=>, , open=, high=, low=, close=, settlement=41.63, volume=, open_interest=>, , open=, high=, low=, close=, settlement=41.06, volume=, open_interest=>, , open=, high=, low=, close=, settlement=42.34, volume=, open_interest=>, ... And, of course, you can convert the OHLC data to a ``pandas.DataFrame`` like this: >>> srmc_coal.ohlc.to_dataframe() traded period front delivery open high low close settlement volume open_interest 0 2020-12-01 month 3 2021-03-01 None None None None 40.96 None None 1 2020-12-02 month 3 2021-03-01 None None None None 41.63 None None 2 2020-12-03 month 3 2021-03-01 None None None None 41.06 None None 3 2020-12-04 month 3 2021-03-01 None None None None 42.34 None None ... Load as a time series --------------------- Method references: :py:meth:`eq.srmc.load_front_as_timeseries() ` and :py:meth:`eq.srmc.load_delivery_as_timeseries() ` This method works like :py:meth:`eq.srmc.load_front() ` and :py:meth:`eq.srmc.load_delivery() ` (see previous section) except that it returns a daily time series instead of OHLC data. For a continuous front contract ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To calculate SRMC for the coal API2 front contract, specify the **curve**, **begin**, **end**, **period** and **front**: >>> from datetime import date >>> from energyquantified.metadata import ContractPeriod >>> srmc_coal = eq.srmc.load_front_as_timeseries( >>> 'Futures Coal API-2 USD/t ICE OHLC', >>> begin=date(2020, 12, 1), # or begin='2020-01-01' >>> end=date(2020, 12, 30), # or end='2020-01-06' >>> period=ContractPeriod.MONTH, >>> front=1, >>> ) The response is an :py:class:`SRMC ` object. It has a curve, a contract (specifying that it is a front-month contract), an ``SRMCOptions`` object with all factors used in the calculation, and a ``timeseries``: >>> srmc_coal , options=, timeseries=, curve="None", begin="2020-12-01 00:00:00+01:00", end="2020-12-16 00:00:00+01:00"> > You can extract the timeseries easily: >>> timeseries = srmc_coal.timeseries >>> for (date, value) in timeseries: >>> print(date, value) 2020-12-01 00:00:00+01:00 41.06 2020-12-02 00:00:00+01:00 41.68 2020-12-03 00:00:00+01:00 41.09 2020-12-04 00:00:00+01:00 42.41 2020-12-05 00:00:00+01:00 None 2020-12-06 00:00:00+01:00 None 2020-12-07 00:00:00+01:00 41.92 2020-12-08 00:00:00+01:00 41.95 ... Notice that there are empty values during the weekend (5 December and 6 December). That is because there are no trades during these days. For a specific contract ^^^^^^^^^^^^^^^^^^^^^^^ To calculate SRMC for a specific coal API2 contract, such as the May 2021-contract, specify the **curve**, **begin**, **end**, **period** and **delivery** date: >>> from datetime import date >>> from energyquantified.metadata import ContractPeriod >>> srmc_coal = eq.srmc.load_delivery_as_timeseries( >>> 'Futures Coal API-2 USD/t ICE OHLC', >>> begin=date(2020, 12, 1), >>> end=date(2020, 12, 30), >>> period=ContractPeriod.MONTH, >>> delivery=date(2021, 3, 1), # March 2021 >>> ) The response is an :py:class:`SRMC ` object. It has a curve, a contract (specifying that it is the March 2021-contract), an ``SRMCOptions`` object with all factors used in the calculation, and a ``timeseries``: >>> srmc_coal , options=, timeseries=, curve="None", begin="2020-12-01 00:00:00+01:00", end="2020-12-16 00:00:00+01:00"> > You can convert the time series to a ``pandas.DataFrame`` easily: >>> srmc_coal.timeseries.to_dataframe() Futures Coal API-2 USD/t ICE OHLC month 2021-03-01 settlement date 2020-12-01 00:00:00+01:00 40.96 2020-12-02 00:00:00+01:00 41.63 2020-12-03 00:00:00+01:00 41.06 2020-12-04 00:00:00+01:00 42.34 2020-12-05 00:00:00+01:00 NaN 2020-12-06 00:00:00+01:00 NaN 2020-12-07 00:00:00+01:00 41.83 2020-12-08 00:00:00+01:00 41.90 ... Load for a trading day ---------------------- Method reference: :py:meth:`eq.srmc.latest() ` This method loads all contracts for a trading day (the latest trading day by default) and calculates the SRMC for each of them. You may also specify an optional **date** parameter to load data for the latest trading day up to and including the given date: >>> from datetime import date >>> srmc_coal = eq.srmc.latest( >>> 'Futures Coal API-2 USD/t ICE OHLC', >>> date=date(2020, 12, 14) # Optionally set a date >>> ) The response will contain a list of all OHLC objects from the latest available trading day. The response will be almost the same as for ``load_front()`` and ``load_delivery()``, except that we don't have a ``contract`` set: >>> srmc_coal , ohlc=, , , ...]> > >>> srmc.coal.ohlc [, open=, high=, low=, close=, settlement=44.15, volume=, open_interest=>, , open=, high=, low=, close=, settlement=44.07, volume=, open_interest=>, , open=, high=, low=, close=, settlement=43.94, volume=, open_interest=>, , open=, high=, low=, close=, settlement=44.05, volume=, open_interest=>, , open=, high=, low=, close=, settlement=43.79, volume=, open_interest=>, , open=, high=, low=, close=, settlement=43.68, volume=, open_interest=>, , open=, high=, low=, close=, settlement=43.78, volume=, open_interest=>, , open=, high=, low=, close=, settlement=44.04, volume=, open_interest=>, , open=, high=, low=, close=, settlement=44.43, volume=, open_interest=>, ... Load as a forward curve ----------------------- Method reference: :py:meth:`eq.srmc.latest_as_periods() ` Loads all contracts for a trading day (the latest trading day by default), sorts them and merges them into a single period-based series (like a forward curve): >>> from datetime import date >>> srmc_coal = eq.srmc.latest_as_periods( >>> 'Futures Coal API-2 USD/t ICE OHLC', >>> date=date(2020, 12, 14) # Optionally set a date >>> ) Use the ``time_zone`` parameter to convert the data to the given timezone: >>> from energyquantified.time import UTC >>> >>> srmc_coal = eq.srmc.latest_as_periods( >>> 'Futures Coal API-2 USD/t ICE OHLC', >>> time_zone=UTC >>> ) The response is an SRMC object with a period-based series set: >>> srmc_coal , periodseries=, curve="Futures Coal API-2 USD/t ICE OHLC", begin="2021-01-01 00:00:00+01:00", end="2027-01-01 00:00:00+01:00"> > You can convert the period-based series to a time series or to a ``pandas.DataFrame`` in your preferred resolution: >>> # Convert to a daily time series >>> from energyquantified.time import Frequency >>> srmc_coal.periodseries.to_timeseries(frequency=Frequency.P1D) , curve="Futures Coal API-2 USD/t ICE OHLC", begin="2021-01-01 00:00:00+01:00", end="2027-01-01 00:00:00+01:00"> >>> # Convert to a pandas.DataFrame in daily resolution >>> srmc_coal.periodseries.to_dataframe(frequency=Frequency.P1D) Futures Coal API-2 USD/t ICE OHLC date 2021-01-01 00:00:00+01:00 44.15 2021-01-02 00:00:00+01:00 44.15 2021-01-03 00:00:00+01:00 44.15 2021-01-04 00:00:00+01:00 44.15 2021-01-05 00:00:00+01:00 44.15 ... ... 2026-12-27 00:00:00+01:00 47.16 2026-12-28 00:00:00+01:00 47.16 2026-12-29 00:00:00+01:00 47.16 2026-12-30 00:00:00+01:00 47.16 2026-12-31 00:00:00+01:00 47.16 [2191 rows x 1 columns] Override SRMC factors --------------------- All method described above has options you may set to override any the following factors used in the SRMC calculation: * ``efficiency``: The efficiency of the fuel * ``carbon_emissions``: The carbon emission factor * ``gas_therm_to_mwh``: Conversion factor from pence/therm to GBP/MWh * ``api2_tonne_to_mwh``: Conversion from coal API2 tonnes to megawatt-hours * ``carbon_tax_area``: Set an :py:class:`Area ` to apply local tax rules. Typically used for Great Britain's carbon tax. Just set the factor you would like to change when using the SRMC functions: >>> from datetime import date >>> from energyquantified.metadata import ContractPeriod >>> srmc_coal = eq.srmc.load_front( >>> 'Futures Coal API-2 USD/t ICE OHLC', >>> begin=date(2020, 12, 1), >>> end=date(2020, 12, 30), >>> period=ContractPeriod.MONTH, >>> front=1, >>> efficiency=0.2, # Not very efficient, eh? >>> carbon_emissions=0.35 # A little more than the default carbon emission >>> ) The overridden factors are now visible in the response's ``SRMCOptions``: >>> srmc_coal , ohlc=... >