{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial part 4\n", "\n", "In [part 3](part3.ipynb) 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.\n", "\n", "## Example data\n", "\n", "We start with a similar portfolio state as in the previous part:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PfState object.\n", ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", ". Freq : (2 datapoints)\n", " w q p r\n", " MW MWh Eur/MWh Eur\n", "\u001b[1m\u001b[37m──────── offtake\n", " \u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 -49.4 -35 593 \n", " \u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 -54.7 -40 748 \n", "\u001b[1m\u001b[37m─\u001b[1m\u001b[33m●\u001b[1m\u001b[37m────── pnl_cost\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 49.4 35 593 147.61 5 253 964\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 54.7 40 748 163.85 6 676 561\n", " \u001b[1m\u001b[33m├\u001b[1m\u001b[36m●\u001b[1m\u001b[33m───── sourced\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 28.9 20 844 123.03 2 564 413\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 26.0 19 389 132.10 2 561 236\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m├───── quarter_products\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-09-01 00:00:00 +0200 13.8 9 943 103.24 1 026 519\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 11.1 8 261 118.15 976 055\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m└───── month_products\n", " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-09-01 00:00:00 +0200 15.1 10 901 141.07 1 537 894\n", " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 14.9 11 128 142.45 1 585 180\n", " \u001b[1m\u001b[33m└────── unsourced\n", " \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 20.5 14 749 182.36 2 689 551\n", " \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 28.7 21 358 192.68 4 115 325\n" ] } ], "source": [ "import portfolyo as pf\n", "import pandas as pd\n", "\n", "index = pd.date_range(\n", " \"2024-09-01\", \"2024-11-01\", freq=\"15min\", inclusive=\"left\", tz=\"Europe/Berlin\"\n", ")\n", "# Creating portfolio line with market prices (here: price-forward curve).\n", "ts_prices = pf.dev.p_marketprices(index, avg=200)\n", "prices = pf.PfLine({\"p\": ts_prices})\n", "\n", "\n", "# Creating offtake portfolio line.\n", "ts_offtake = -1 * pf.dev.w_offtake(index, avg=50)\n", "offtake = pf.PfLine({\"w\": ts_offtake})\n", "\n", "# Creating portfolio line with sourced volume.\n", "ts_sourced_power1, ts_sourced_price1 = pf.dev.wp_sourced(\n", " ts_offtake, \"QS\", 0.3, p_avg=120\n", ")\n", "sourced_quarters = pf.PfLine({\"w\": ts_sourced_power1, \"p\": ts_sourced_price1})\n", "ts_sourced_power2, ts_sourced_price2 = pf.dev.wp_sourced(\n", " ts_offtake, \"MS\", 0.2, p_avg=150\n", ")\n", "sourced_months = pf.PfLine({\"w\": ts_sourced_power2, \"p\": ts_sourced_price2})\n", "sourced = pf.PfLine(\n", " {\"quarter_products\": sourced_quarters, \"month_products\": sourced_months}\n", ")\n", "\n", "# Create the portfolio state.\n", "pfs1 = pf.PfState(offtake, prices, sourced).asfreq(\"MS\")\n", "\n", "pfs1.print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arithmatic\n", "\n", "The final part about portfolio lines is the arithmatic that can be done with them.\n", "\n", "Let's create a second portfolio state:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PfState object.\n", ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", ". Freq : (2 datapoints)\n", " w q p r\n", " MW MWh Eur/MWh Eur\n", "\u001b[1m\u001b[37m──────── offtake\n", " \u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 -98.9 -71 186 \n", " \u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 -109.4 -81 495 \n", "\u001b[1m\u001b[37m─\u001b[1m\u001b[33m●\u001b[1m\u001b[37m────── pnl_cost\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 98.9 71 186 118.77 8 454 414\n", " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 109.4 81 495 131.98 10 755 857\n", " \u001b[1m\u001b[33m├────── sourced\n", " \u001b[1m\u001b[33m│ \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 80.0 57 600 100.00 5 760 000\n", " \u001b[1m\u001b[33m│ \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 80.0 59 600 100.00 5 960 000\n", " \u001b[1m\u001b[33m└────── unsourced\n", " \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 18.9 13 586 198.33 2 694 414\n", " \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 29.4 21 895 219.04 4 795 857\n" ] } ], "source": [ "offtake2 = offtake * 2\n", "sourced2 = pf.PfLine(pd.DataFrame({\"w\": 80, \"p\": 100}, index))\n", "pfs2 = pf.PfState(offtake2, prices, sourced2).asfreq(\"MS\")\n", "pfs2.print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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.\n", "\n", "### Addition and subtraction\n", "\n", "We can add these two portfolio states:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "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.\n", " warnings.warn(\n" ] }, { "data": { "text/plain": [ "PfState object.\n", ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", ". Freq : (2 datapoints)\n", " w q p r\n", " MW MWh Eur/MWh Eur\n", "──────── offtake\n", " 2024-09-01 00:00:00 +0200 -148.3 -106 778 \n", " 2024-10-01 00:00:00 +0200 -164.1 -122 243 \n", "─●────── pnl_cost\n", " │ 2024-09-01 00:00:00 +0200 148.3 106 778 128.38 13 708 378\n", " │ 2024-10-01 00:00:00 +0200 164.1 122 243 142.60 17 432 418\n", " ├────── sourced\n", " │ 2024-09-01 00:00:00 +0200 108.9 78 444 106.12 8 324 413\n", " │ 2024-10-01 00:00:00 +0200 106.0 78 989 107.88 8 521 236\n", " └────── unsourced\n", " 2024-09-01 00:00:00 +0200 39.4 28 334 190.02 5 383 965\n", " 2024-10-01 00:00:00 +0200 58.1 43 254 206.02 8 911 182" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pfs1 + pfs2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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.)\n", "\n", "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](../core/pfline.rst#Arithmatic).\n", "\n", "Likewise we can subtract them with ``pfs1 - pfs2``:\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "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.\n", " warnings.warn(\n" ] }, { "data": { "text/plain": [ "PfState object.\n", ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", ". Freq : (2 datapoints)\n", " w q p r\n", " MW MWh Eur/MWh Eur\n", "──────── offtake\n", " 2024-09-01 00:00:00 +0200 49.4 35 593 \n", " 2024-10-01 00:00:00 +0200 54.7 40 748 \n", "─●────── pnl_cost\n", " │ 2024-09-01 00:00:00 +0200 -49.4 -35 593 89.92 -3 200 450\n", " │ 2024-10-01 00:00:00 +0200 -54.7 -40 748 100.11 -4 079 296\n", " ├────── sourced\n", " │ 2024-09-01 00:00:00 +0200 -51.1 -36 756 86.94 -3 195 587\n", " │ 2024-10-01 00:00:00 +0200 -54.0 -40 211 84.52 -3 398 764\n", " └────── unsourced\n", " 2024-09-01 00:00:00 +0200 1.6 1 163 -4.18 -4 863\n", " 2024-10-01 00:00:00 +0200 -0.7 -537 1 267.81 -680 532" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pfs1 - pfs2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That was it for this tutorial!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.8.13 ('pf38')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.13" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "642a4be8010ca5d45039b988c1d8379a91572488c4d23a0b88e966c6713c7e45" } } }, "nbformat": 4, "nbformat_minor": 2 }