Tutorial part 4¶
In part 3 we have learnt about portfolio states and how to use them in scenario analyses. Here we learn how to export them and how to combine several ones.
Example data¶
We start with a similar portfolio state as in the previous part:
[1]:
import portfolyo as pf
import pandas as pd
index = pd.date_range(
"2024-09-01", "2024-11-01", freq="15min", inclusive="left", tz="Europe/Berlin"
)
# Creating portfolio line with market prices (here: price-forward curve).
ts_prices = pf.dev.p_marketprices(index, avg=200)
prices = pf.PfLine({"p": ts_prices})
# Creating offtake portfolio line.
ts_offtake = -1 * pf.dev.w_offtake(index, avg=50)
offtake = pf.PfLine({"w": ts_offtake})
# Creating portfolio line with sourced volume.
ts_sourced_power1, ts_sourced_price1 = pf.dev.wp_sourced(
ts_offtake, "QS", 0.3, p_avg=120
)
sourced_quarters = pf.PfLine({"w": ts_sourced_power1, "p": ts_sourced_price1})
ts_sourced_power2, ts_sourced_price2 = pf.dev.wp_sourced(
ts_offtake, "MS", 0.2, p_avg=150
)
sourced_months = pf.PfLine({"w": ts_sourced_power2, "p": ts_sourced_price2})
sourced = pf.PfLine(
{"quarter_products": sourced_quarters, "month_products": sourced_months}
)
# Create the portfolio state.
pfs1 = pf.PfState(offtake, prices, sourced).asfreq("MS")
pfs1.print()
PfState object.
. Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin
. End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00
. Freq : <MonthBegin> (2 datapoints)
w q p r
MW MWh Eur/MWh Eur
──────── offtake
2024-09-01 00:00:00 +0200 -49.4 -35 593
2024-10-01 00:00:00 +0200 -54.7 -40 748
─●────── pnl_cost
│ 2024-09-01 00:00:00 +0200 49.4 35 593 147.61 5 253 964
│ 2024-10-01 00:00:00 +0200 54.7 40 748 163.85 6 676 561
├●───── sourced
││ 2024-09-01 00:00:00 +0200 28.9 20 844 123.03 2 564 413
││ 2024-10-01 00:00:00 +0200 26.0 19 389 132.10 2 561 236
│├───── quarter_products
││ 2024-09-01 00:00:00 +0200 13.8 9 943 103.24 1 026 519
││ 2024-10-01 00:00:00 +0200 11.1 8 261 118.15 976 055
│└───── month_products
│ 2024-09-01 00:00:00 +0200 15.1 10 901 141.07 1 537 894
│ 2024-10-01 00:00:00 +0200 14.9 11 128 142.45 1 585 180
└────── unsourced
2024-09-01 00:00:00 +0200 20.5 14 749 182.36 2 689 551
2024-10-01 00:00:00 +0200 28.7 21 358 192.68 4 115 325
Arithmatic¶
The final part about portfolio lines is the arithmatic that can be done with them.
Let’s create a second portfolio state:
[2]:
offtake2 = offtake * 2
sourced2 = pf.PfLine(pd.DataFrame({"w": 80, "p": 100}, index))
pfs2 = pf.PfState(offtake2, prices, sourced2).asfreq("MS")
pfs2.print()
PfState object.
. Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin
. End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00
. Freq : <MonthBegin> (2 datapoints)
w q p r
MW MWh Eur/MWh Eur
──────── offtake
2024-09-01 00:00:00 +0200 -98.9 -71 186
2024-10-01 00:00:00 +0200 -109.4 -81 495
─●────── pnl_cost
│ 2024-09-01 00:00:00 +0200 98.9 71 186 118.77 8 454 414
│ 2024-10-01 00:00:00 +0200 109.4 81 495 131.98 10 755 857
├────── sourced
│ 2024-09-01 00:00:00 +0200 80.0 57 600 100.00 5 760 000
│ 2024-10-01 00:00:00 +0200 80.0 59 600 100.00 5 960 000
└────── unsourced
2024-09-01 00:00:00 +0200 18.9 13 586 198.33 2 694 414
2024-10-01 00:00:00 +0200 29.4 21 895 219.04 4 795 857
Note that pfs1 and pfs2 have distinct unsourced prices at this month level, even though they were created using the same market prices on the quarter-hour level.
Addition and subtraction¶
We can add these two portfolio states:
[3]:
pfs1 + pfs2
c:\users\ruud.wijtvliet\ruud\python\dev\portfolyo\portfolyo\core\pfline\enable_arithmatic.py:82: PfLineFlattenedWarning: When adding a FlatPfLine and NestedPfLine, the NestedPfLine is flattened.
warnings.warn(
[3]:
PfState object.
. Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin
. End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00
. Freq : <MonthBegin> (2 datapoints)
w q p r
MW MWh Eur/MWh Eur
──────── offtake
2024-09-01 00:00:00 +0200 -148.3 -106 778
2024-10-01 00:00:00 +0200 -164.1 -122 243
─●────── pnl_cost
│ 2024-09-01 00:00:00 +0200 148.3 106 778 128.38 13 708 378
│ 2024-10-01 00:00:00 +0200 164.1 122 243 142.60 17 432 418
├────── sourced
│ 2024-09-01 00:00:00 +0200 108.9 78 444 106.12 8 324 413
│ 2024-10-01 00:00:00 +0200 106.0 78 989 107.88 8 521 236
└────── unsourced
2024-09-01 00:00:00 +0200 39.4 28 334 190.02 5 383 965
2024-10-01 00:00:00 +0200 58.1 43 254 206.02 8 911 182
Note that the individual components are added together. The volumes (offtake, sourced, unsourced) are summed; the prices (sourced and unsourced) are the energy-weighted averaged. (Or, put differently, the revenues are also summed, and the prices are calculated from the volume-total and renevue-total.)
Note also that the sourced volume of pfs1 has been flattened, i.e., the values of its children are lost. This is because pfs2 does not have any children. This behaviour is described here.
Likewise we can subtract them with pfs1 - pfs2:
[4]:
pfs1 - pfs2
c:\users\ruud.wijtvliet\ruud\python\dev\portfolyo\portfolyo\core\pfline\enable_arithmatic.py:82: PfLineFlattenedWarning: When adding a FlatPfLine and NestedPfLine, the NestedPfLine is flattened.
warnings.warn(
[4]:
PfState object.
. Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin
. End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00
. Freq : <MonthBegin> (2 datapoints)
w q p r
MW MWh Eur/MWh Eur
──────── offtake
2024-09-01 00:00:00 +0200 49.4 35 593
2024-10-01 00:00:00 +0200 54.7 40 748
─●────── pnl_cost
│ 2024-09-01 00:00:00 +0200 -49.4 -35 593 89.92 -3 200 450
│ 2024-10-01 00:00:00 +0200 -54.7 -40 748 100.11 -4 079 296
├────── sourced
│ 2024-09-01 00:00:00 +0200 -51.1 -36 756 86.94 -3 195 587
│ 2024-10-01 00:00:00 +0200 -54.0 -40 211 84.52 -3 398 764
└────── unsourced
2024-09-01 00:00:00 +0200 1.6 1 163 -4.18 -4 863
2024-10-01 00:00:00 +0200 -0.7 -537 1 267.81 -680 532
That was it for this tutorial!