Skip to content

Commit

Permalink
Wavgfix (#62)
Browse files Browse the repository at this point in the history
* initial commit

* small fix

* stash for the weekend

* Fixed wavg to handle surplus values.

* Re-instated 'Europe/Berlin' as default for tz in standardize. For now.

* small fix in docs

* docs and better unit handling

* Kind available at project root

* fixed init tests (?)

* new release

* fixed for pyton 3.9 too
  • Loading branch information
rwijtvliet authored Dec 12, 2023
1 parent fc70808 commit 3987b88
Show file tree
Hide file tree
Showing 21 changed files with 1,062 additions and 377 deletions.
2 changes: 1 addition & 1 deletion LICENCE
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7 changes: 5 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ NB: this package is under active development and the API will change without pri

.. code-block:: bash
pip install portfolyo==x.x.x
pip install portfolyo==x.y.z
# or, in pyproject.toml
portfolyo = "x.y.z"
Documentation
Expand All @@ -66,7 +69,7 @@ the commit hooks.

.. code-block:: bash
poetry install --with=dev,test
poetry install --with dev,test
pre-commit install
Feature branches are merged into the ``develop`` branch via pull request.
Expand Down
73 changes: 34 additions & 39 deletions docs/core/pfline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,25 @@ Kind

An important characteristic of a portfolio line is its "kind". The property ``PfLine.kind`` has a value from the ``portfolyo.Kind`` enumeration and tells us the type of information it contains:

* ``Kind.VOLUME``: "volume-only" portfolio line.
* 🟨 ``Kind.VOLUME``: "volume-only" portfolio line.

This is a portfolio line that only contains volume information.

As an example, consider the expected/projected development of offtake volume of a customer or customer group.

The volume in each timestamp can be retrieved by the user in units of energy (e.g., MWh) or in units of power (e.g., MW).

* ``Kind.PRICE``: "price-only" portfolio line.
* 🟩 ``Kind.PRICE``: "price-only" portfolio line.

This is a portfolio line which only contains price information.

For example, the forward price curve for a certain market area, or the fixed offtake price that a customer is paying for a certain delivery period.

* ``Kind.REVENUE``: "revenue-only" portfolio line.
* 🟦 ``Kind.REVENUE``: "revenue-only" portfolio line.

For example, the payoff of a financially-settled put option, which has a monetary value (e.g., in Eur) without an associated volume being delivered.

* ``Kind.COMPLETE``
* 🟫 ``Kind.COMPLETE``

This a portfolio line that contains volume, price and revenue information.

Expand Down Expand Up @@ -72,7 +72,7 @@ To initialise a volume-only / price-only / revenue-only portfolio line, we must
DataFrame or dictionary of timeseries...
========================================

or any other ``Mapping`` from (string) key values to ``pandas.Series``.
...or any other ``Mapping`` from (string) key values to ``pandas.Series``.

The keys (or dataframe column names) must each be one of the following: ``w`` (power), ``q`` (energy), ``p`` (price), ``r`` (revenue). Depending on the keys, the ``.kind`` of the portfolio line is determined.

Expand Down Expand Up @@ -107,7 +107,7 @@ Under the condition that a valid ``pint`` unit is present, we may also provide a
Dictionary of portfolio lines...
================================

or any other ``Mapping`` from (string) key values to ``PfLine`` objects.
...or any other ``Mapping`` from (string) key values to ``PfLine`` objects.

The keys are used as the children names:

Expand Down Expand Up @@ -383,15 +383,14 @@ Addition and subtraction
* Even if the both operands have the same kind, they must both be nested or both be flat. E.g., a flat price can be added to a flat price-only portfolio line, but not to a nested price-only portfolio line. Two nested price-only portfolio lines can be added.

================================================= =============== ============== ================ =================
\ Kind of portfolio line
\ Kind of portfolio line (`pfl.Kind`)
------------------------------------------------- -----------------------------------------------------------------
\ 🟨 🟩 🟦 🟫
\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE``
\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE``
================================================= =============== ============== ================ =================
``PfLine`` ± volume 🟨 e_ ❌ ❌ ❌
``PfLine`` ± price ❌ 🟩 e_ ❌ ❌
``PfLine`` ± revenue ❌ ❌ 🟦 e_ ❌
``PfLine`` ± complete ❌ ❌ ❌ 🟫 e_
``pfl`` ± volume 🟨 e_ ❌ ❌ ❌
``pfl`` ± price ❌ 🟩 e_ ❌ ❌
``pfl`` ± revenue ❌ ❌ 🟦 e_ ❌
``pfl`` ± complete ❌ ❌ ❌ 🟫 e_
================================================= =============== ============== ================ =================

Notes:
Expand Down Expand Up @@ -495,14 +494,13 @@ We can scale a portfolio line by multiplication with / division by a dimensionle
Negation is implemented as multiplication with -1.

================================================= =============== ============== ================ =================
\ Kind of portfolio line
\ Kind of portfolio line (`pfl.Kind`)
------------------------------------------------- -----------------------------------------------------------------
\ 🟨 🟩 🟦 🟫
\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE``
\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE``
================================================= =============== ============== ================ =================
``-PfLine`` (negation) 🟨 🟩 🟦 🟫
``PfLine * dimensionless`` 🟨 🟩 🟦 🟫
``PfLine / dimensionless`` 🟨 🟩 🟦 🟫
``-pfl`` (negation) 🟨 🟩 🟦 🟫
``pfl * dimensionless`` 🟨 🟩 🟦 🟫
``pfl / dimensionless`` 🟨 🟩 🟦 🟫
================================================= =============== ============== ================ =================

For example:
Expand Down Expand Up @@ -534,14 +532,13 @@ We can calculate the ratio of two portfolyo lines by dividing them.


================================================= =============== ============== ================ =================
\ Kind of portfolio line
\ Kind of portfolio line (`pfl.Kind`)
------------------------------------------------- -----------------------------------------------------------------
\ 🟨 🟩 🟦 🟫
\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE``
\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE``
================================================= =============== ============== ================ =================
``PfLine / volume`` 2f_ ❌ (❌) ❌
``PfLine / price`` ❌ 2f_ (❌) ❌
``PfLine / revenue`` ❌ ❌ 2f_ ❌
``pfl / volume`` ⬛️ 2f_ ❌ (❌) ❌
``pfl / price`` ⬛️ 2f_ (❌) ❌
``pfl / revenue`` ❌ ❌ ⬛️ 2f_ ❌
================================================= =============== ============== ================ =================

Notes:
Expand All @@ -552,7 +549,7 @@ Notes:
Both operands must be flat.

(❌)
This operation is allowed but does not result in ratio. It is described in the section changekind_ below.
This operation is allowed but does not result in a ratio. It is described in the section changekind_ below.

For example:

Expand Down Expand Up @@ -593,15 +590,14 @@ We can turn one kind of portfolio line into another kind, by multiplying with or
* To combine two portfolio lines into a complete portfolio line, see the section :ref:`union`, below.

================================================= =============== ============== ================ =================
\ Kind of portfolio line
\ Kind of portfolio line (`pfl.Kind`)
------------------------------------------------- -----------------------------------------------------------------
\ 🟨 🟩 🟦 🟫
\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE``
\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE``
================================================= =============== ============== ================ =================
``PfLine * volume`` ❌ 🟦 `≥1f`_ ❌ ❌
``PfLine * price`` 🟦 `≥1f`_ ❌ ❌ ❌
``PfLine / volume`` (❌) ❌ 🟩 `≥1f`_ ❌
``PfLine / price`` ❌ (❌) 🟨 `≥1f`_ ❌
``pfl * volume`` ❌ 🟦 `≥1f`_ ❌ ❌
``pfl * price`` 🟦 `≥1f`_ ❌ ❌ ❌
``pfl / volume`` (❌) ❌ 🟩 `≥1f`_ ❌
``pfl / price`` ❌ (❌) 🟨 `≥1f`_ ❌
================================================= =============== ============== ================ =================

Notes:
Expand Down Expand Up @@ -642,14 +638,13 @@ We can combine portfolio lines of distinct kind into a complete portfolio line.
* Both operands must be flat. If necessary, first ``.flatten()`` a nested portfolio line.

================================================= =============== ============== ================ =================
\ Kind of portfolio line
\ Kind of portfolio line (`pfl.Kind`)
------------------------------------------------- -----------------------------------------------------------------
\ 🟨 🟩 🟦 🟫
\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE``
\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE``
================================================= =============== ============== ================ =================
``PfLine | volume`` ❌ 🟫 `2f⠀`_ 🟫 `2f⠀`_ ❌
``PfLine | price`` 🟫 `2f⠀`_ ❌ 🟫 `2f⠀`_ ❌
``PfLine | revenue`` 🟫 `2f⠀`_ 🟫 `2f⠀`_ ❌ ❌
``pfl | volume`` ❌ 🟫 `2f⠀`_ 🟫 `2f⠀`_ ❌
``pfl | price`` 🟫 `2f⠀`_ ❌ 🟫 `2f⠀`_ ❌
``pfl | revenue`` 🟫 `2f⠀`_ 🟫 `2f⠀`_ ❌ ❌
================================================= =============== ============== ================ =================


Expand Down
Binary file modified docs/savefig/fig_hedge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/savefig/fig_offtake.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions docs/specialized_topics/resampling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Yearly resolution w q p r t
2024-01-01 00:00:00+01:00 0.113843 1000.0 30.0 30000.0 7.98
========================= ======== ====== ======= ======= ====

If we resample these values to a higher-frequency timeseries (e.g. quarteryearly), then the values of the summable dimensions (``q`` and ``r``) become smaller, as their values need to be "spread" over the resulting rows. If nothing more is known about how the energy is consumed, we assume that the consumption rate is constant throughout the period. This means we have to distribute the values over the new rows, **in proportion to their duration**. (Because the 3rd and 4th quarter have more days than the 1st and 2nd quarter, they get a larger fraction of the original value.)
If we resample these values to a shorter-frequency timeseries (e.g. quarteryearly), then the values of the summable dimensions (``q`` and ``r``) become smaller, as their values need to be "spread" over the resulting rows. If nothing more is known about how the energy is consumed, we assume that the consumption rate is constant throughout the period. This means we have to distribute the values over the new rows, **in proportion to their duration**. (Because the 3rd and 4th quarter have more days than the 1st and 2nd quarter, they get a larger fraction of the original value.)

The values of the averagable dimensions (``w`` and ``t``) are **unchanged**, i.e., they are simply copies of the original value. Also the value of the derived quantity ``p`` turns out to be unchanged. The resulting values are therefore:

Expand Down Expand Up @@ -87,7 +87,7 @@ Quarterly resolution w q p r t
2024-10-01 00:00:00+02:00 0.144862 320.0 30.80 9856.0 3.2
========================= ======== ====== ======= ======= ====

If we resample to a lower-frequency timeseries (e.g. yearly), we need to **sum** the values of the summable dimensions ``q`` and ``r`` (the duration does not need to be considered).
If we resample to a longer-frequency timeseries (e.g. yearly), we need to **sum** the values of the summable dimensions ``q`` and ``r`` (the duration does not need to be considered).

For the time-averagable dimensions (``w`` and ``t``), the **average** of the individual values must be calculated, **weighted with the duration** of each row. (Alternatively, for the power ``w``: this is always ``q/duration`` and can always be calculated from these values after *they* are downsampled.)

Expand All @@ -102,7 +102,7 @@ Downsampled to yearly resolution w q p r t
2024-01-01 00:00:00+01:00 0.113843 1000.0 30.0 30000.0 7.98
================================ ======== ====== ======= ======= ====

(Note that the 'simple row-average' of the power, temperature, and price give us incorrect values.)
Note that the 'simple row-average' of the power, temperature, and price would give us incorrect values.

--------------------------------
Downsampling example, price-only
Expand Down Expand Up @@ -131,10 +131,10 @@ Downsampled to yearly resolution p
2024-01-01 00:00:00+01:00 28.78
==================================== =======

The reason for the higher price in the previous example, is that, there, it is weighted with the *energy* in each period. We had more energy in the expensive quarters, and less in the cheaper ones, which results in a higher price for the entire year.
The reason for the higher price in the previous example, is that, there, the price is weighted with the *energy* in each period. We had more energy in the expensive quarters, and less in the cheaper ones, which results in a higher price for the entire year.

-----------------------------
Resampling with ``portfolyo``
-----------------------------

When changing the frequency of a ``PfLine`` or ``PfState`` object, the considerations above are automatically taken into account. If you are in the situation of having to change the frequency of a ``pandas.Series`` or ``DataFrame`` with a ``DatetimeIndex``, however, the relevant functions are also available at the ``portfolyo.tools.changefreq`` module.
When changing the frequency of a ``PfLine`` or ``PfState`` object, the considerations above are automatically taken into account. If you are in the situation of having to change the frequency of a ``pandas.Series`` or ``DataFrame`` with a ``DatetimeIndex``, however, the relevant functions are also available at the ``portfolyo.tools.changefreq`` module.
7 changes: 6 additions & 1 deletion portfolyo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@
from .tools.freq import FREQUENCIES
from .tools.standardize import frame as standardize
from .tools.tzone import force_agnostic, force_aware
from .tools.unit import Q_
from .tools.unit import Q_, ureg, Unit
from .tools.wavg import general as wavg

VOLUME = Kind.VOLUME
PRICE = Kind.PRICE
REVENUE = Kind.REVENUE
COMPLETE = Kind.COMPLETE

extendpandas.apply()
suppresswarnings.apply()

Expand Down
1 change: 1 addition & 0 deletions portfolyo/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
assert_index_equal,
assert_indices_compatible,
assert_series_equal,
assert_value_equal,
)
Loading

0 comments on commit 3987b88

Please sign in to comment.