From 3c3444ade4f6fa1d9feea936546943be7164a28c Mon Sep 17 00:00:00 2001
From: terrenceshang <90186971+terrenceshang@users.noreply.github.com>
Date: Sat, 5 Aug 2023 13:51:28 +0200
Subject: [PATCH 1/2] Zenan Shang
---
Challenge - Copy.ipynb | 2798 +++++++++++++++++++++++++++++++++
Challenge.ipynb | 3326 ++++++++++++++++++++++++++++++++++++++++
solution_skeleton.py | 273 ++--
3 files changed, 6309 insertions(+), 88 deletions(-)
create mode 100644 Challenge - Copy.ipynb
create mode 100644 Challenge.ipynb
diff --git a/Challenge - Copy.ipynb b/Challenge - Copy.ipynb
new file mode 100644
index 0000000..66b5857
--- /dev/null
+++ b/Challenge - Copy.ipynb
@@ -0,0 +1,2798 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "---Python script Start--- 2023-08-05 13:43:56.409716\n"
+ ]
+ }
+ ],
+ "source": [
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import datetime\n",
+ "import plotly.express as px\n",
+ "from keras.models import Sequential\n",
+ "from keras.layers import LSTM, Dense, Dropout\n",
+ "from sklearn.preprocessing import MinMaxScaler\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "print(\"---Python script Start---\", str(datetime.datetime.now()))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " month_end | \n",
+ " Stock1 | \n",
+ " Stock10 | \n",
+ " Stock11 | \n",
+ " Stock14 | \n",
+ " Stock16 | \n",
+ " Stock18 | \n",
+ " Stock19 | \n",
+ " Stock20 | \n",
+ " Stock21 | \n",
+ " ... | \n",
+ " Stock78 | \n",
+ " Stock79 | \n",
+ " Stock80 | \n",
+ " Stock81 | \n",
+ " Stock84 | \n",
+ " Stock85 | \n",
+ " Stock86 | \n",
+ " Stock87 | \n",
+ " Stock88 | \n",
+ " Stock9 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 2010-01-31 | \n",
+ " 0.042603 | \n",
+ " -0.076059 | \n",
+ " -0.149741 | \n",
+ " -0.031251 | \n",
+ " -0.053032 | \n",
+ " -0.113752 | \n",
+ " -0.071671 | \n",
+ " 0.005430 | \n",
+ " 0.005715 | \n",
+ " ... | \n",
+ " -0.028168 | \n",
+ " 0.017445 | \n",
+ " -0.100000 | \n",
+ " 0.018014 | \n",
+ " 0.044749 | \n",
+ " 0.016824 | \n",
+ " -0.111084 | \n",
+ " -0.035229 | \n",
+ " -0.033204 | \n",
+ " 0.030927 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2010-02-28 | \n",
+ " -0.015034 | \n",
+ " -0.100305 | \n",
+ " -0.023279 | \n",
+ " 0.002484 | \n",
+ " 0.077088 | \n",
+ " 0.010849 | \n",
+ " 0.022383 | \n",
+ " 0.095480 | \n",
+ " 0.067745 | \n",
+ " ... | \n",
+ " 0.082448 | \n",
+ " -0.106195 | \n",
+ " 0.066669 | \n",
+ " 0.000556 | \n",
+ " -0.010800 | \n",
+ " 0.006326 | \n",
+ " -0.026405 | \n",
+ " -0.013759 | \n",
+ " 0.095241 | \n",
+ " -0.010000 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 2010-03-31 | \n",
+ " 0.111545 | \n",
+ " 0.097933 | \n",
+ " 0.121501 | \n",
+ " 0.064357 | \n",
+ " 0.107439 | \n",
+ " 0.017883 | \n",
+ " 0.000892 | \n",
+ " 0.032425 | \n",
+ " 0.018012 | \n",
+ " ... | \n",
+ " 0.036357 | \n",
+ " 0.220049 | \n",
+ " 0.098957 | \n",
+ " 0.088889 | \n",
+ " 0.088630 | \n",
+ " 0.047296 | \n",
+ " 0.153527 | \n",
+ " 0.034416 | \n",
+ " 0.041795 | \n",
+ " 0.024809 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 2010-04-30 | \n",
+ " -0.040491 | \n",
+ " -0.034262 | \n",
+ " -0.032848 | \n",
+ " -0.030232 | \n",
+ " 0.022388 | \n",
+ " 0.085504 | \n",
+ " -0.007159 | \n",
+ " 0.052763 | \n",
+ " 0.017920 | \n",
+ " ... | \n",
+ " 0.040579 | \n",
+ " 0.004259 | \n",
+ " -0.052133 | \n",
+ " 0.005099 | \n",
+ " -0.016164 | \n",
+ " 0.012845 | \n",
+ " -0.004702 | \n",
+ " 0.019786 | \n",
+ " 0.042046 | \n",
+ " 0.030303 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 2010-05-31 | \n",
+ " -0.069359 | \n",
+ " -0.073188 | \n",
+ " 0.004349 | \n",
+ " 0.010792 | \n",
+ " -0.025548 | \n",
+ " -0.001887 | \n",
+ " -0.012534 | \n",
+ " 0.068973 | \n",
+ " -0.026794 | \n",
+ " ... | \n",
+ " -0.025069 | \n",
+ " -0.062221 | \n",
+ " 0.004332 | \n",
+ " -0.023857 | \n",
+ " -0.085645 | \n",
+ " -0.041085 | \n",
+ " -0.083320 | \n",
+ " 0.095238 | \n",
+ " -0.124253 | \n",
+ " -0.010784 | \n",
+ "
\n",
+ " \n",
+ " | ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " | 87 | \n",
+ " 2017-04-30 | \n",
+ " 0.057631 | \n",
+ " 0.089651 | \n",
+ " -0.090908 | \n",
+ " -0.045544 | \n",
+ " 0.033207 | \n",
+ " -0.003331 | \n",
+ " 0.036885 | \n",
+ " -0.017510 | \n",
+ " 0.097012 | \n",
+ " ... | \n",
+ " 0.039548 | \n",
+ " 0.009388 | \n",
+ " 0.096569 | \n",
+ " 0.086140 | \n",
+ " 0.097051 | \n",
+ " 0.036655 | \n",
+ " -0.059447 | \n",
+ " -0.005197 | \n",
+ " -0.111087 | \n",
+ " 0.044074 | \n",
+ "
\n",
+ " \n",
+ " | 88 | \n",
+ " 2017-05-31 | \n",
+ " -0.013557 | \n",
+ " -0.027089 | \n",
+ " -0.050713 | \n",
+ " -0.052443 | \n",
+ " -0.132316 | \n",
+ " -0.013774 | \n",
+ " -0.071147 | \n",
+ " -0.045192 | \n",
+ " -0.031881 | \n",
+ " ... | \n",
+ " -0.042451 | \n",
+ " -0.032799 | \n",
+ " 0.069729 | \n",
+ " -0.018660 | \n",
+ " -0.054422 | \n",
+ " 0.071153 | \n",
+ " -0.083055 | \n",
+ " 0.092917 | \n",
+ " -0.039052 | \n",
+ " -0.031945 | \n",
+ "
\n",
+ " \n",
+ " | 89 | \n",
+ " 2017-06-30 | \n",
+ " -0.022060 | \n",
+ " -0.098539 | \n",
+ " -0.016556 | \n",
+ " 0.005218 | \n",
+ " -0.008810 | \n",
+ " -0.125433 | \n",
+ " -0.028937 | \n",
+ " 0.069444 | \n",
+ " -0.055806 | \n",
+ " ... | \n",
+ " -0.001562 | \n",
+ " -0.055437 | \n",
+ " -0.062808 | \n",
+ " -0.019475 | \n",
+ " 0.034172 | \n",
+ " -0.077723 | \n",
+ " -0.002616 | \n",
+ " 0.020783 | \n",
+ " 0.038300 | \n",
+ " 0.011196 | \n",
+ "
\n",
+ " \n",
+ " | 90 | \n",
+ " 2017-07-31 | \n",
+ " 0.036795 | \n",
+ " 0.002527 | \n",
+ " 0.059680 | \n",
+ " 0.074563 | \n",
+ " 0.135041 | \n",
+ " 0.056864 | \n",
+ " 0.038476 | \n",
+ " 0.109808 | \n",
+ " 0.023922 | \n",
+ " ... | \n",
+ " 0.096860 | \n",
+ " 0.089980 | \n",
+ " 0.142830 | \n",
+ " 0.001359 | \n",
+ " 0.005916 | \n",
+ " 0.064159 | \n",
+ " 0.234903 | \n",
+ " 0.084005 | \n",
+ " 0.112443 | \n",
+ " 0.027391 | \n",
+ "
\n",
+ " \n",
+ " | 91 | \n",
+ " 2017-08-31 | \n",
+ " 0.032189 | \n",
+ " 0.001031 | \n",
+ " 0.101082 | \n",
+ " 0.008990 | \n",
+ " 0.010417 | \n",
+ " -0.035204 | \n",
+ " 0.112929 | \n",
+ " 0.046901 | \n",
+ " 0.082138 | \n",
+ " ... | \n",
+ " 0.073335 | \n",
+ " 0.083564 | \n",
+ " 0.011163 | \n",
+ " 0.016842 | \n",
+ " 0.026141 | \n",
+ " 0.022422 | \n",
+ " 0.116454 | \n",
+ " 0.019769 | \n",
+ " 0.171767 | \n",
+ " -0.005104 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
92 rows × 55 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " month_end Stock1 Stock10 Stock11 Stock14 Stock16 Stock18 \n",
+ "0 2010-01-31 0.042603 -0.076059 -0.149741 -0.031251 -0.053032 -0.113752 \\\n",
+ "1 2010-02-28 -0.015034 -0.100305 -0.023279 0.002484 0.077088 0.010849 \n",
+ "2 2010-03-31 0.111545 0.097933 0.121501 0.064357 0.107439 0.017883 \n",
+ "3 2010-04-30 -0.040491 -0.034262 -0.032848 -0.030232 0.022388 0.085504 \n",
+ "4 2010-05-31 -0.069359 -0.073188 0.004349 0.010792 -0.025548 -0.001887 \n",
+ ".. ... ... ... ... ... ... ... \n",
+ "87 2017-04-30 0.057631 0.089651 -0.090908 -0.045544 0.033207 -0.003331 \n",
+ "88 2017-05-31 -0.013557 -0.027089 -0.050713 -0.052443 -0.132316 -0.013774 \n",
+ "89 2017-06-30 -0.022060 -0.098539 -0.016556 0.005218 -0.008810 -0.125433 \n",
+ "90 2017-07-31 0.036795 0.002527 0.059680 0.074563 0.135041 0.056864 \n",
+ "91 2017-08-31 0.032189 0.001031 0.101082 0.008990 0.010417 -0.035204 \n",
+ "\n",
+ " Stock19 Stock20 Stock21 ... Stock78 Stock79 Stock80 Stock81 \n",
+ "0 -0.071671 0.005430 0.005715 ... -0.028168 0.017445 -0.100000 0.018014 \\\n",
+ "1 0.022383 0.095480 0.067745 ... 0.082448 -0.106195 0.066669 0.000556 \n",
+ "2 0.000892 0.032425 0.018012 ... 0.036357 0.220049 0.098957 0.088889 \n",
+ "3 -0.007159 0.052763 0.017920 ... 0.040579 0.004259 -0.052133 0.005099 \n",
+ "4 -0.012534 0.068973 -0.026794 ... -0.025069 -0.062221 0.004332 -0.023857 \n",
+ ".. ... ... ... ... ... ... ... ... \n",
+ "87 0.036885 -0.017510 0.097012 ... 0.039548 0.009388 0.096569 0.086140 \n",
+ "88 -0.071147 -0.045192 -0.031881 ... -0.042451 -0.032799 0.069729 -0.018660 \n",
+ "89 -0.028937 0.069444 -0.055806 ... -0.001562 -0.055437 -0.062808 -0.019475 \n",
+ "90 0.038476 0.109808 0.023922 ... 0.096860 0.089980 0.142830 0.001359 \n",
+ "91 0.112929 0.046901 0.082138 ... 0.073335 0.083564 0.011163 0.016842 \n",
+ "\n",
+ " Stock84 Stock85 Stock86 Stock87 Stock88 Stock9 \n",
+ "0 0.044749 0.016824 -0.111084 -0.035229 -0.033204 0.030927 \n",
+ "1 -0.010800 0.006326 -0.026405 -0.013759 0.095241 -0.010000 \n",
+ "2 0.088630 0.047296 0.153527 0.034416 0.041795 0.024809 \n",
+ "3 -0.016164 0.012845 -0.004702 0.019786 0.042046 0.030303 \n",
+ "4 -0.085645 -0.041085 -0.083320 0.095238 -0.124253 -0.010784 \n",
+ ".. ... ... ... ... ... ... \n",
+ "87 0.097051 0.036655 -0.059447 -0.005197 -0.111087 0.044074 \n",
+ "88 -0.054422 0.071153 -0.083055 0.092917 -0.039052 -0.031945 \n",
+ "89 0.034172 -0.077723 -0.002616 0.020783 0.038300 0.011196 \n",
+ "90 0.005916 0.064159 0.234903 0.084005 0.112443 0.027391 \n",
+ "91 0.026141 0.022422 0.116454 0.019769 0.171767 -0.005104 \n",
+ "\n",
+ "[92 rows x 55 columns]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "df = pd.read_csv(\n",
+ " \"C:\\\\Users\\\\terre\\OneDrive - University of Cape Town\\\\Terrence\\\\Code\\\\prescient-coding-challenge-2023\\\\data\\\\returns_train.csv\"\n",
+ ")\n",
+ "display(df)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# data reads\n",
+ "df_returns_train = pd.read_csv(\"data/returns_train.csv\")\n",
+ "df_returns_test = pd.read_csv(\"data/returns_test.csv\")\n",
+ "df_returns_train[\"month_end\"] = pd.to_datetime(arg=df_returns_train[\"month_end\"]).apply(\n",
+ " lambda d: d.date()\n",
+ ")\n",
+ "df_returns_test[\"month_end\"] = pd.to_datetime(arg=df_returns_test[\"month_end\"]).apply(\n",
+ " lambda d: d.date()\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "['Stock1', 'Stock10', 'Stock11', 'Stock14', 'Stock16', 'Stock18', 'Stock19', 'Stock20', 'Stock21', 'Stock22', 'Stock26', 'Stock3', 'Stock30', 'Stock31', 'Stock33', 'Stock34', 'Stock35', 'Stock38', 'Stock39', 'Stock4', 'Stock40', 'Stock41', 'Stock43', 'Stock44', 'Stock46', 'Stock47', 'Stock49', 'Stock5', 'Stock50', 'Stock54', 'Stock56', 'Stock59', 'Stock6', 'Stock61', 'Stock63', 'Stock64', 'Stock66', 'Stock69', 'Stock7', 'Stock70', 'Stock73', 'Stock75', 'Stock76', 'Stock77', 'Stock78', 'Stock79', 'Stock80', 'Stock81', 'Stock84', 'Stock85', 'Stock86', 'Stock87', 'Stock88', 'Stock9']\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " Stock1 | \n",
+ " Stock10 | \n",
+ " Stock11 | \n",
+ " Stock14 | \n",
+ " Stock16 | \n",
+ " Stock18 | \n",
+ " Stock19 | \n",
+ " Stock20 | \n",
+ " Stock21 | \n",
+ " Stock22 | \n",
+ " ... | \n",
+ " Stock78 | \n",
+ " Stock79 | \n",
+ " Stock80 | \n",
+ " Stock81 | \n",
+ " Stock84 | \n",
+ " Stock85 | \n",
+ " Stock86 | \n",
+ " Stock87 | \n",
+ " Stock88 | \n",
+ " Stock9 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 0.042603 | \n",
+ " -0.076059 | \n",
+ " -0.149741 | \n",
+ " -0.031251 | \n",
+ " -0.053032 | \n",
+ " -0.113752 | \n",
+ " -0.071671 | \n",
+ " 0.005430 | \n",
+ " 0.005715 | \n",
+ " 0.001399 | \n",
+ " ... | \n",
+ " -0.028168 | \n",
+ " 0.017445 | \n",
+ " -0.100000 | \n",
+ " 0.018014 | \n",
+ " 0.044749 | \n",
+ " 0.016824 | \n",
+ " -0.111084 | \n",
+ " -0.035229 | \n",
+ " -0.033204 | \n",
+ " 0.030927 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " -0.015034 | \n",
+ " -0.100305 | \n",
+ " -0.023279 | \n",
+ " 0.002484 | \n",
+ " 0.077088 | \n",
+ " 0.010849 | \n",
+ " 0.022383 | \n",
+ " 0.095480 | \n",
+ " 0.067745 | \n",
+ " 0.082493 | \n",
+ " ... | \n",
+ " 0.082448 | \n",
+ " -0.106195 | \n",
+ " 0.066669 | \n",
+ " 0.000556 | \n",
+ " -0.010800 | \n",
+ " 0.006326 | \n",
+ " -0.026405 | \n",
+ " -0.013759 | \n",
+ " 0.095241 | \n",
+ " -0.010000 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 0.111545 | \n",
+ " 0.097933 | \n",
+ " 0.121501 | \n",
+ " 0.064357 | \n",
+ " 0.107439 | \n",
+ " 0.017883 | \n",
+ " 0.000892 | \n",
+ " 0.032425 | \n",
+ " 0.018012 | \n",
+ " 0.031663 | \n",
+ " ... | \n",
+ " 0.036357 | \n",
+ " 0.220049 | \n",
+ " 0.098957 | \n",
+ " 0.088889 | \n",
+ " 0.088630 | \n",
+ " 0.047296 | \n",
+ " 0.153527 | \n",
+ " 0.034416 | \n",
+ " 0.041795 | \n",
+ " 0.024809 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " -0.040491 | \n",
+ " -0.034262 | \n",
+ " -0.032848 | \n",
+ " -0.030232 | \n",
+ " 0.022388 | \n",
+ " 0.085504 | \n",
+ " -0.007159 | \n",
+ " 0.052763 | \n",
+ " 0.017920 | \n",
+ " 0.007674 | \n",
+ " ... | \n",
+ " 0.040579 | \n",
+ " 0.004259 | \n",
+ " -0.052133 | \n",
+ " 0.005099 | \n",
+ " -0.016164 | \n",
+ " 0.012845 | \n",
+ " -0.004702 | \n",
+ " 0.019786 | \n",
+ " 0.042046 | \n",
+ " 0.030303 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " -0.069359 | \n",
+ " -0.073188 | \n",
+ " 0.004349 | \n",
+ " 0.010792 | \n",
+ " -0.025548 | \n",
+ " -0.001887 | \n",
+ " -0.012534 | \n",
+ " 0.068973 | \n",
+ " -0.026794 | \n",
+ " -0.056697 | \n",
+ " ... | \n",
+ " -0.025069 | \n",
+ " -0.062221 | \n",
+ " 0.004332 | \n",
+ " -0.023857 | \n",
+ " -0.085645 | \n",
+ " -0.041085 | \n",
+ " -0.083320 | \n",
+ " 0.095238 | \n",
+ " -0.124253 | \n",
+ " -0.010784 | \n",
+ "
\n",
+ " \n",
+ " | ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " | 87 | \n",
+ " 0.057631 | \n",
+ " 0.089651 | \n",
+ " -0.090908 | \n",
+ " -0.045544 | \n",
+ " 0.033207 | \n",
+ " -0.003331 | \n",
+ " 0.036885 | \n",
+ " -0.017510 | \n",
+ " 0.097012 | \n",
+ " -0.000908 | \n",
+ " ... | \n",
+ " 0.039548 | \n",
+ " 0.009388 | \n",
+ " 0.096569 | \n",
+ " 0.086140 | \n",
+ " 0.097051 | \n",
+ " 0.036655 | \n",
+ " -0.059447 | \n",
+ " -0.005197 | \n",
+ " -0.111087 | \n",
+ " 0.044074 | \n",
+ "
\n",
+ " \n",
+ " | 88 | \n",
+ " -0.013557 | \n",
+ " -0.027089 | \n",
+ " -0.050713 | \n",
+ " -0.052443 | \n",
+ " -0.132316 | \n",
+ " -0.013774 | \n",
+ " -0.071147 | \n",
+ " -0.045192 | \n",
+ " -0.031881 | \n",
+ " -0.000167 | \n",
+ " ... | \n",
+ " -0.042451 | \n",
+ " -0.032799 | \n",
+ " 0.069729 | \n",
+ " -0.018660 | \n",
+ " -0.054422 | \n",
+ " 0.071153 | \n",
+ " -0.083055 | \n",
+ " 0.092917 | \n",
+ " -0.039052 | \n",
+ " -0.031945 | \n",
+ "
\n",
+ " \n",
+ " | 89 | \n",
+ " -0.022060 | \n",
+ " -0.098539 | \n",
+ " -0.016556 | \n",
+ " 0.005218 | \n",
+ " -0.008810 | \n",
+ " -0.125433 | \n",
+ " -0.028937 | \n",
+ " 0.069444 | \n",
+ " -0.055806 | \n",
+ " -0.002845 | \n",
+ " ... | \n",
+ " -0.001562 | \n",
+ " -0.055437 | \n",
+ " -0.062808 | \n",
+ " -0.019475 | \n",
+ " 0.034172 | \n",
+ " -0.077723 | \n",
+ " -0.002616 | \n",
+ " 0.020783 | \n",
+ " 0.038300 | \n",
+ " 0.011196 | \n",
+ "
\n",
+ " \n",
+ " | 90 | \n",
+ " 0.036795 | \n",
+ " 0.002527 | \n",
+ " 0.059680 | \n",
+ " 0.074563 | \n",
+ " 0.135041 | \n",
+ " 0.056864 | \n",
+ " 0.038476 | \n",
+ " 0.109808 | \n",
+ " 0.023922 | \n",
+ " 0.023766 | \n",
+ " ... | \n",
+ " 0.096860 | \n",
+ " 0.089980 | \n",
+ " 0.142830 | \n",
+ " 0.001359 | \n",
+ " 0.005916 | \n",
+ " 0.064159 | \n",
+ " 0.234903 | \n",
+ " 0.084005 | \n",
+ " 0.112443 | \n",
+ " 0.027391 | \n",
+ "
\n",
+ " \n",
+ " | 91 | \n",
+ " 0.032189 | \n",
+ " 0.001031 | \n",
+ " 0.101082 | \n",
+ " 0.008990 | \n",
+ " 0.010417 | \n",
+ " -0.035204 | \n",
+ " 0.112929 | \n",
+ " 0.046901 | \n",
+ " 0.082138 | \n",
+ " -0.010214 | \n",
+ " ... | \n",
+ " 0.073335 | \n",
+ " 0.083564 | \n",
+ " 0.011163 | \n",
+ " 0.016842 | \n",
+ " 0.026141 | \n",
+ " 0.022422 | \n",
+ " 0.116454 | \n",
+ " 0.019769 | \n",
+ " 0.171767 | \n",
+ " -0.005104 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
92 rows × 54 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Stock1 Stock10 Stock11 Stock14 Stock16 Stock18 Stock19 \n",
+ "0 0.042603 -0.076059 -0.149741 -0.031251 -0.053032 -0.113752 -0.071671 \\\n",
+ "1 -0.015034 -0.100305 -0.023279 0.002484 0.077088 0.010849 0.022383 \n",
+ "2 0.111545 0.097933 0.121501 0.064357 0.107439 0.017883 0.000892 \n",
+ "3 -0.040491 -0.034262 -0.032848 -0.030232 0.022388 0.085504 -0.007159 \n",
+ "4 -0.069359 -0.073188 0.004349 0.010792 -0.025548 -0.001887 -0.012534 \n",
+ ".. ... ... ... ... ... ... ... \n",
+ "87 0.057631 0.089651 -0.090908 -0.045544 0.033207 -0.003331 0.036885 \n",
+ "88 -0.013557 -0.027089 -0.050713 -0.052443 -0.132316 -0.013774 -0.071147 \n",
+ "89 -0.022060 -0.098539 -0.016556 0.005218 -0.008810 -0.125433 -0.028937 \n",
+ "90 0.036795 0.002527 0.059680 0.074563 0.135041 0.056864 0.038476 \n",
+ "91 0.032189 0.001031 0.101082 0.008990 0.010417 -0.035204 0.112929 \n",
+ "\n",
+ " Stock20 Stock21 Stock22 ... Stock78 Stock79 Stock80 Stock81 \n",
+ "0 0.005430 0.005715 0.001399 ... -0.028168 0.017445 -0.100000 0.018014 \\\n",
+ "1 0.095480 0.067745 0.082493 ... 0.082448 -0.106195 0.066669 0.000556 \n",
+ "2 0.032425 0.018012 0.031663 ... 0.036357 0.220049 0.098957 0.088889 \n",
+ "3 0.052763 0.017920 0.007674 ... 0.040579 0.004259 -0.052133 0.005099 \n",
+ "4 0.068973 -0.026794 -0.056697 ... -0.025069 -0.062221 0.004332 -0.023857 \n",
+ ".. ... ... ... ... ... ... ... ... \n",
+ "87 -0.017510 0.097012 -0.000908 ... 0.039548 0.009388 0.096569 0.086140 \n",
+ "88 -0.045192 -0.031881 -0.000167 ... -0.042451 -0.032799 0.069729 -0.018660 \n",
+ "89 0.069444 -0.055806 -0.002845 ... -0.001562 -0.055437 -0.062808 -0.019475 \n",
+ "90 0.109808 0.023922 0.023766 ... 0.096860 0.089980 0.142830 0.001359 \n",
+ "91 0.046901 0.082138 -0.010214 ... 0.073335 0.083564 0.011163 0.016842 \n",
+ "\n",
+ " Stock84 Stock85 Stock86 Stock87 Stock88 Stock9 \n",
+ "0 0.044749 0.016824 -0.111084 -0.035229 -0.033204 0.030927 \n",
+ "1 -0.010800 0.006326 -0.026405 -0.013759 0.095241 -0.010000 \n",
+ "2 0.088630 0.047296 0.153527 0.034416 0.041795 0.024809 \n",
+ "3 -0.016164 0.012845 -0.004702 0.019786 0.042046 0.030303 \n",
+ "4 -0.085645 -0.041085 -0.083320 0.095238 -0.124253 -0.010784 \n",
+ ".. ... ... ... ... ... ... \n",
+ "87 0.097051 0.036655 -0.059447 -0.005197 -0.111087 0.044074 \n",
+ "88 -0.054422 0.071153 -0.083055 0.092917 -0.039052 -0.031945 \n",
+ "89 0.034172 -0.077723 -0.002616 0.020783 0.038300 0.011196 \n",
+ "90 0.005916 0.064159 0.234903 0.084005 0.112443 0.027391 \n",
+ "91 0.026141 0.022422 0.116454 0.019769 0.171767 -0.005104 \n",
+ "\n",
+ "[92 rows x 54 columns]"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Ignoring the month_end from training set\n",
+ "\n",
+ "# Get column names as a list but ignore the first column\n",
+ "header_list = df.columns[1:].tolist()\n",
+ "print(header_list)\n",
+ "\n",
+ "\n",
+ "def process_dataframe(dataframe):\n",
+ " # Create a new dataframe without the 'month_end' column\n",
+ " new_dataframe = dataframe.drop([\"month_end\"], axis=1)\n",
+ " return new_dataframe\n",
+ "\n",
+ "\n",
+ "clean_df = process_dataframe(df_returns_train)\n",
+ "clean_df"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def equalise_weights(df: pd.DataFrame):\n",
+ " \"\"\"\n",
+ " Function to generate the equal weights, i.e. 1/p for each active stock within a month\n",
+ "\n",
+ " Args:\n",
+ " df: A return data frame. First column is month end and remaining columns are stocks\n",
+ "\n",
+ " Returns:\n",
+ " A dataframe of the same dimension but with values 1/p on active funds within a month\n",
+ "\n",
+ " \"\"\"\n",
+ "\n",
+ " # create df to house weights\n",
+ " n_length = len(df)\n",
+ " df_returns = df\n",
+ " df_weights = df_returns[:n_length].copy()\n",
+ " df_weights.set_index(\"month_end\", inplace=True)\n",
+ "\n",
+ " # list of stock names\n",
+ " list_stocks = list(df_returns.columns)\n",
+ " list_stocks.remove(\"month_end\")\n",
+ "\n",
+ " # assign 1/p\n",
+ " df_weights[list_stocks] = 1 / len(list_stocks)\n",
+ "\n",
+ " return df_weights"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/50\n",
+ "2/2 [==============================] - 10s 2s/step - loss: 0.2509 - val_loss: 0.2397\n",
+ "Epoch 2/50\n",
+ "2/2 [==============================] - 0s 105ms/step - loss: 0.2147 - val_loss: 0.2121\n",
+ "Epoch 3/50\n",
+ "2/2 [==============================] - 0s 117ms/step - loss: 0.1903 - val_loss: 0.1808\n",
+ "Epoch 4/50\n",
+ "2/2 [==============================] - 0s 96ms/step - loss: 0.1641 - val_loss: 0.1486\n",
+ "Epoch 5/50\n",
+ "2/2 [==============================] - 0s 96ms/step - loss: 0.1360 - val_loss: 0.1195\n",
+ "Epoch 6/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.1208 - val_loss: 0.0971\n",
+ "Epoch 7/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.1078 - val_loss: 0.0818\n",
+ "Epoch 8/50\n",
+ "2/2 [==============================] - 0s 112ms/step - loss: 0.0949 - val_loss: 0.0715\n",
+ "Epoch 9/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0883 - val_loss: 0.0639\n",
+ "Epoch 10/50\n",
+ "2/2 [==============================] - 0s 95ms/step - loss: 0.0831 - val_loss: 0.0575\n",
+ "Epoch 11/50\n",
+ "2/2 [==============================] - 0s 110ms/step - loss: 0.0875 - val_loss: 0.0530\n",
+ "Epoch 12/50\n",
+ "2/2 [==============================] - 0s 103ms/step - loss: 0.0811 - val_loss: 0.0515\n",
+ "Epoch 13/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0749 - val_loss: 0.0518\n",
+ "Epoch 14/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0713 - val_loss: 0.0506\n",
+ "Epoch 15/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0681 - val_loss: 0.0487\n",
+ "Epoch 16/50\n",
+ "2/2 [==============================] - 0s 98ms/step - loss: 0.0710 - val_loss: 0.0490\n",
+ "Epoch 17/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0638 - val_loss: 0.0493\n",
+ "Epoch 18/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0657 - val_loss: 0.0488\n",
+ "Epoch 19/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0716 - val_loss: 0.0481\n",
+ "Epoch 20/50\n",
+ "2/2 [==============================] - 0s 105ms/step - loss: 0.0637 - val_loss: 0.0471\n",
+ "Epoch 21/50\n",
+ "2/2 [==============================] - 0s 105ms/step - loss: 0.0627 - val_loss: 0.0468\n",
+ "Epoch 22/50\n",
+ "2/2 [==============================] - 0s 102ms/step - loss: 0.0602 - val_loss: 0.0474\n",
+ "Epoch 23/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0602 - val_loss: 0.0491\n",
+ "Epoch 24/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0628 - val_loss: 0.0494\n",
+ "Epoch 25/50\n",
+ "2/2 [==============================] - 0s 97ms/step - loss: 0.0612 - val_loss: 0.0483\n",
+ "Epoch 26/50\n",
+ "2/2 [==============================] - 0s 112ms/step - loss: 0.0612 - val_loss: 0.0471\n",
+ "Epoch 27/50\n",
+ "2/2 [==============================] - 0s 102ms/step - loss: 0.0645 - val_loss: 0.0476\n",
+ "Epoch 28/50\n",
+ "2/2 [==============================] - 0s 102ms/step - loss: 0.0639 - val_loss: 0.0469\n",
+ "Epoch 29/50\n",
+ "2/2 [==============================] - 0s 111ms/step - loss: 0.0590 - val_loss: 0.0468\n",
+ "Epoch 30/50\n",
+ "2/2 [==============================] - 0s 112ms/step - loss: 0.0622 - val_loss: 0.0467\n",
+ "Epoch 31/50\n",
+ "2/2 [==============================] - 0s 103ms/step - loss: 0.0599 - val_loss: 0.0466\n",
+ "Epoch 32/50\n",
+ "2/2 [==============================] - 0s 106ms/step - loss: 0.0624 - val_loss: 0.0470\n",
+ "Epoch 33/50\n",
+ "2/2 [==============================] - 0s 109ms/step - loss: 0.0562 - val_loss: 0.0482\n",
+ "Epoch 34/50\n",
+ "2/2 [==============================] - 0s 105ms/step - loss: 0.0608 - val_loss: 0.0503\n",
+ "Epoch 35/50\n",
+ "2/2 [==============================] - 0s 102ms/step - loss: 0.0577 - val_loss: 0.0526\n",
+ "Epoch 36/50\n",
+ "2/2 [==============================] - 0s 109ms/step - loss: 0.0533 - val_loss: 0.0491\n",
+ "Epoch 37/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0571 - val_loss: 0.0460\n",
+ "Epoch 38/50\n",
+ "2/2 [==============================] - 0s 107ms/step - loss: 0.0573 - val_loss: 0.0454\n",
+ "Epoch 39/50\n",
+ "2/2 [==============================] - 0s 106ms/step - loss: 0.0586 - val_loss: 0.0456\n",
+ "Epoch 40/50\n",
+ "2/2 [==============================] - 0s 97ms/step - loss: 0.0576 - val_loss: 0.0463\n",
+ "Epoch 41/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0551 - val_loss: 0.0471\n",
+ "Epoch 42/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0578 - val_loss: 0.0476\n",
+ "Epoch 43/50\n",
+ "2/2 [==============================] - 0s 97ms/step - loss: 0.0584 - val_loss: 0.0464\n",
+ "Epoch 44/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0577 - val_loss: 0.0451\n",
+ "Epoch 45/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0546 - val_loss: 0.0449\n",
+ "Epoch 46/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0561 - val_loss: 0.0454\n",
+ "Epoch 47/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0594 - val_loss: 0.0467\n",
+ "Epoch 48/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0540 - val_loss: 0.0466\n",
+ "Epoch 49/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0555 - val_loss: 0.0464\n",
+ "Epoch 50/50\n",
+ "2/2 [==============================] - 0s 93ms/step - loss: 0.0568 - val_loss: 0.0460\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Normalization\n",
+ "scaler = MinMaxScaler(feature_range=(0, 1))\n",
+ "scaled_data = scaler.fit_transform(clean_df.values)\n",
+ "\n",
+ "# Create a data structure with 60 time-steps and 1 output for each stock\n",
+ "lookback = 60\n",
+ "\n",
+ "X, y = [], []\n",
+ "for i in range(lookback, len(scaled_data)):\n",
+ " X.append(scaled_data[i - lookback : i])\n",
+ " y.append(scaled_data[i])\n",
+ "X, y = np.array(X), np.array(y)\n",
+ "\n",
+ "# Split the data into training and validation sets\n",
+ "X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)\n",
+ "\n",
+ "# Initialize the LSTM model\n",
+ "model = Sequential()\n",
+ "\n",
+ "model.add(\n",
+ " LSTM(\n",
+ " units=50,\n",
+ " return_sequences=True,\n",
+ " input_shape=(X_train.shape[1], X_train.shape[2]),\n",
+ " )\n",
+ ")\n",
+ "model.add(Dropout(0.2))\n",
+ "\n",
+ "model.add(LSTM(units=50, return_sequences=True))\n",
+ "model.add(Dropout(0.2))\n",
+ "\n",
+ "model.add(LSTM(units=50, return_sequences=True))\n",
+ "model.add(Dropout(0.2))\n",
+ "\n",
+ "model.add(LSTM(units=50))\n",
+ "model.add(Dropout(0.2))\n",
+ "\n",
+ "model.add(\n",
+ " Dense(units=clean_df.shape[1])\n",
+ ") # number of units in the output layer should be equal to the number of stocks\n",
+ "\n",
+ "# Compile and train the model\n",
+ "model.compile(optimizer=\"adam\", loss=\"mean_squared_error\")\n",
+ "model.fit(X_train, y_train, epochs=50, batch_size=20, validation_data=(X_val, y_val))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame):\n",
+ " \"\"\"\n",
+ " Function to generate stocks weight allocation for time t+1 using historic data. Initial weights generated as 1/p for active stock within a month\n",
+ "\n",
+ " Args:\n",
+ " df_train: The training set of returns. First column is month end and remaining columns are stocks\n",
+ " df_test: The testing set of returns. First column is month end and remaining columns are stocks\n",
+ "\n",
+ " Returns:\n",
+ " The returns dataframe and the weights\n",
+ " \"\"\"\n",
+ "\n",
+ " print(\n",
+ " \"---> training set spans\",\n",
+ " df_train[\"month_end\"].min(),\n",
+ " df_train[\"month_end\"].max(),\n",
+ " )\n",
+ " print(\n",
+ " \"---> training set spans\",\n",
+ " df_test[\"month_end\"].min(),\n",
+ " df_test[\"month_end\"].max(),\n",
+ " )\n",
+ "\n",
+ " # initialise data\n",
+ " n_train = len(df_train)\n",
+ " df_returns = pd.concat(objs=[df_train, df_test], ignore_index=True)\n",
+ "\n",
+ " df_weights = equalise_weights(\n",
+ " df_returns[:n_train]\n",
+ " ) # df to store weights and create initial\n",
+ "\n",
+ " # list of stock names\n",
+ " list_stocks = list(df_returns.columns)\n",
+ " list_stocks.remove(\"month_end\")\n",
+ "\n",
+ " # Only positive predicted stock are considered\n",
+ " # Higher volitility have higher weighting\n",
+ " # Higher prediction through my machine learning algorithm (LSTM) will have higher weighting\n",
+ " for i in range(len(df_test)):\n",
+ " df_latest = df_returns[(df_returns[\"month_end\"] < df_test.loc[i, \"month_end\"])]\n",
+ "\n",
+ " if len(df_latest) >= lookback:\n",
+ " latest_returns = df_latest[-lookback:][list_stocks].values\n",
+ " else:\n",
+ " continue\n",
+ "\n",
+ " # reshape the latest returns to be suitable for the LSTM model\n",
+ " latest_returns = np.reshape(latest_returns, (1, lookback, len(list_stocks)))\n",
+ "\n",
+ " # predict the future returns using the LSTM model\n",
+ " predicted_returns = model.predict(latest_returns)\n",
+ "\n",
+ " # Filter out the stocks with positive predicted returns\n",
+ " positive_returns_indices = np.where(predicted_returns[0] > 0)[0]\n",
+ " positive_returns = predicted_returns[0][positive_returns_indices]\n",
+ " positive_stock_names = np.array(list_stocks)[positive_returns_indices]\n",
+ "\n",
+ " # Apply exponential weighting to the positive returns\n",
+ " exp_returns = np.exp(positive_returns)\n",
+ "\n",
+ " # Calculate the recent volatility for each stock\n",
+ " volatilities = np.std(latest_returns[0], axis=0)\n",
+ "\n",
+ " # Scale the weights of each stock correspondto its recent volatility\n",
+ " volatility_scaled_weights = exp_returns * volatilities[positive_returns_indices]\n",
+ "\n",
+ " # Normalize the weights to sum to 1\n",
+ " weights = volatility_scaled_weights / np.sum(volatility_scaled_weights)\n",
+ "\n",
+ " # Create a new weight dataframe\n",
+ " weights_dict = dict(zip(positive_stock_names, weights))\n",
+ " weights_dict[\"month_end\"] = df_test.loc[i, \"month_end\"]\n",
+ " df_this = pd.DataFrame(data=[weights_dict], columns=df_weights.columns)\n",
+ " df_this = df_this.fillna(0) # fill NaNs for stocks that have been excluded\n",
+ "\n",
+ " # Append the weights to the df_weights dataframe\n",
+ " df_weights = pd.concat(objs=[df_weights, df_this], ignore_index=True)\n",
+ "\n",
+ " # 10% limit check\n",
+ " if len(\n",
+ " np.array(df_weights[list_stocks])[np.array(df_weights[list_stocks]) > 0.101]\n",
+ " ):\n",
+ " raise Exception(r\"---> 10% limit exceeded\")\n",
+ "\n",
+ " return df_returns, df_weights"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def plot_total_return(\n",
+ " df_returns: pd.DataFrame,\n",
+ " df_weights_index: pd.DataFrame,\n",
+ " df_weights_portfolio: pd.DataFrame,\n",
+ "):\n",
+ " \"\"\"\n",
+ " Function to generate the two total return indices.\n",
+ "\n",
+ " Args:\n",
+ " df_returns: Ascending date ordered combined training and test returns data.\n",
+ " df_weights_index: Index weights. Equally weighted\n",
+ " df_weights_index: Portfolio weights. Your portfolio should use equally weighted for the training date range. If blank will be ignored\n",
+ "\n",
+ " Returns:\n",
+ " A plot of the two total return indices and the total return indices as a dataframe\n",
+ " \"\"\"\n",
+ "\n",
+ " # list of stock names\n",
+ " list_stocks = list(df_returns.columns)\n",
+ " list_stocks.remove(\"month_end\")\n",
+ "\n",
+ " # replace nans with 0 in return array\n",
+ " ar_returns = np.array(df_returns[list_stocks])\n",
+ " np.nan_to_num(x=ar_returns, copy=False, nan=0)\n",
+ "\n",
+ " # calc index\n",
+ " ar_rtn_index = np.array(df_weights_index[list_stocks]) * ar_returns\n",
+ " ar_rtn_port = np.array(df_weights_portfolio[list_stocks]) * ar_returns\n",
+ "\n",
+ " v_rtn_index = np.sum(ar_rtn_index, axis=1)\n",
+ " v_rtn_port = np.sum(ar_rtn_port, axis=1)\n",
+ "\n",
+ " # add return series to dataframe\n",
+ " df_rtn = pd.DataFrame(data=df_returns[\"month_end\"], columns=[\"month_end\"])\n",
+ " df_rtn[\"index\"] = v_rtn_index\n",
+ " df_rtn[\"portfolio\"] = v_rtn_port\n",
+ " df_rtn\n",
+ "\n",
+ " # create total return\n",
+ " base_price = 100\n",
+ " df_rtn.sort_values(by=\"month_end\", inplace=True)\n",
+ " df_rtn[\"index_tr\"] = ((1 + df_rtn[\"index\"]).cumprod()) * base_price\n",
+ " df_rtn[\"portfolio_tr\"] = ((1 + df_rtn[\"portfolio\"]).cumprod()) * base_price\n",
+ " df_rtn\n",
+ "\n",
+ " df_rtn_long = df_rtn[[\"month_end\", \"index_tr\", \"portfolio_tr\"]].melt(\n",
+ " id_vars=\"month_end\", var_name=\"series\", value_name=\"Total Return\"\n",
+ " )\n",
+ "\n",
+ " # plot\n",
+ " fig1 = px.line(\n",
+ " data_frame=df_rtn_long, x=\"month_end\", y=\"Total Return\", color=\"series\"\n",
+ " )\n",
+ "\n",
+ " return fig1, df_rtn"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "---> training set spans 2010-01-31 2017-08-31\n",
+ "---> training set spans 2017-09-30 2022-09-30\n",
+ "1/1 [==============================] - 1s 1s/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 27ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 30ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 31ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 34ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 31ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 44ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 26ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 30ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 31ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 27ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 31ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 31ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.plotly.v1+json": {
+ "config": {
+ "plotlyServerURL": "https://plot.ly"
+ },
+ "data": [
+ {
+ "hovertemplate": "series=index_tr
month_end=%{x}
Total Return=%{y}",
+ "legendgroup": "index_tr",
+ "line": {
+ "color": "#636efa",
+ "dash": "solid"
+ },
+ "marker": {
+ "symbol": "circle"
+ },
+ "mode": "lines",
+ "name": "index_tr",
+ "orientation": "v",
+ "showlegend": true,
+ "type": "scatter",
+ "x": [
+ "2010-01-31",
+ "2010-02-28",
+ "2010-03-31",
+ "2010-04-30",
+ "2010-05-31",
+ "2010-06-30",
+ "2010-07-31",
+ "2010-08-31",
+ "2010-09-30",
+ "2010-10-31",
+ "2010-11-30",
+ "2010-12-31",
+ "2011-01-31",
+ "2011-02-28",
+ "2011-03-31",
+ "2011-04-30",
+ "2011-05-31",
+ "2011-06-30",
+ "2011-07-31",
+ "2011-08-31",
+ "2011-09-30",
+ "2011-10-31",
+ "2011-11-30",
+ "2011-12-31",
+ "2012-01-31",
+ "2012-02-29",
+ "2012-03-31",
+ "2012-04-30",
+ "2012-05-31",
+ "2012-06-30",
+ "2012-07-31",
+ "2012-08-31",
+ "2012-09-30",
+ "2012-10-31",
+ "2012-11-30",
+ "2012-12-31",
+ "2013-01-31",
+ "2013-02-28",
+ "2013-03-31",
+ "2013-04-30",
+ "2013-05-31",
+ "2013-06-30",
+ "2013-07-31",
+ "2013-08-31",
+ "2013-09-30",
+ "2013-10-31",
+ "2013-11-30",
+ "2013-12-31",
+ "2014-01-31",
+ "2014-02-28",
+ "2014-03-31",
+ "2014-04-30",
+ "2014-05-31",
+ "2014-06-30",
+ "2014-07-31",
+ "2014-08-31",
+ "2014-09-30",
+ "2014-10-31",
+ "2014-11-30",
+ "2014-12-31",
+ "2015-01-31",
+ "2015-02-28",
+ "2015-03-31",
+ "2015-04-30",
+ "2015-05-31",
+ "2015-06-30",
+ "2015-07-31",
+ "2015-08-31",
+ "2015-09-30",
+ "2015-10-31",
+ "2015-11-30",
+ "2015-12-31",
+ "2016-01-31",
+ "2016-02-29",
+ "2016-03-31",
+ "2016-04-30",
+ "2016-05-31",
+ "2016-06-30",
+ "2016-07-31",
+ "2016-08-31",
+ "2016-09-30",
+ "2016-10-31",
+ "2016-11-30",
+ "2016-12-31",
+ "2017-01-31",
+ "2017-02-28",
+ "2017-03-31",
+ "2017-04-30",
+ "2017-05-31",
+ "2017-06-30",
+ "2017-07-31",
+ "2017-08-31",
+ "2017-09-30",
+ "2017-10-31",
+ "2017-11-30",
+ "2017-12-31",
+ "2018-01-31",
+ "2018-02-28",
+ "2018-03-31",
+ "2018-04-30",
+ "2018-05-31",
+ "2018-06-30",
+ "2018-07-31",
+ "2018-08-31",
+ "2018-09-30",
+ "2018-10-31",
+ "2018-11-30",
+ "2018-12-31",
+ "2019-01-31",
+ "2019-02-28",
+ "2019-03-31",
+ "2019-04-30",
+ "2019-05-31",
+ "2019-06-30",
+ "2019-07-31",
+ "2019-08-31",
+ "2019-09-30",
+ "2019-10-31",
+ "2019-11-30",
+ "2019-12-31",
+ "2020-01-31",
+ "2020-02-29",
+ "2020-03-31",
+ "2020-04-30",
+ "2020-05-31",
+ "2020-06-30",
+ "2020-07-31",
+ "2020-08-31",
+ "2020-09-30",
+ "2020-10-31",
+ "2020-11-30",
+ "2020-12-31",
+ "2021-01-31",
+ "2021-02-28",
+ "2021-03-31",
+ "2021-04-30",
+ "2021-05-31",
+ "2021-06-30",
+ "2021-07-31",
+ "2021-08-31",
+ "2021-09-30",
+ "2021-10-31",
+ "2021-11-30",
+ "2021-12-31",
+ "2022-01-31",
+ "2022-02-28",
+ "2022-03-31",
+ "2022-04-30",
+ "2022-05-31",
+ "2022-06-30",
+ "2022-07-31",
+ "2022-08-31",
+ "2022-09-30"
+ ],
+ "xaxis": "x",
+ "y": [
+ 98.40422503465814,
+ 100.93798662242051,
+ 107.68288522534036,
+ 109.7995615285553,
+ 107.23242817648126,
+ 106.43966113566464,
+ 113.91349320384909,
+ 112.29508785565194,
+ 122.12549889316125,
+ 124.87638245152488,
+ 124.37504919099058,
+ 131.02440630172168,
+ 125.53974799975698,
+ 128.16916055886097,
+ 130.8873968980463,
+ 134.06376216689685,
+ 133.87076190339369,
+ 132.59760255874266,
+ 132.19487983933925,
+ 133.93330703110996,
+ 130.5237798699564,
+ 139.62267767903492,
+ 142.58187781542216,
+ 140.81510171281383,
+ 147.43151378288488,
+ 151.98680235958813,
+ 152.40074939942423,
+ 156.02418771795553,
+ 152.8161411497546,
+ 155.48775962326914,
+ 159.96753392766976,
+ 161.2555092837166,
+ 163.55646116844596,
+ 166.76092531656502,
+ 169.35948468015056,
+ 179.51302600735073,
+ 178.97405279416094,
+ 175.715694663543,
+ 177.78002433183755,
+ 173.6270905121469,
+ 179.05309265268664,
+ 174.40587342069082,
+ 177.70371255865953,
+ 180.45868512898545,
+ 190.13847786882747,
+ 199.8342118600708,
+ 195.61245975954753,
+ 198.21223347276447,
+ 192.83928084761467,
+ 199.0110446369025,
+ 209.28517002996813,
+ 216.99871696931413,
+ 215.54672594503234,
+ 221.47400674506645,
+ 229.30151970138036,
+ 231.71558423761155,
+ 223.30433148163613,
+ 230.03817391436593,
+ 237.31763181271953,
+ 238.0489478471065,
+ 253.40103532914986,
+ 257.65372033222815,
+ 250.32521657304318,
+ 261.0487471728084,
+ 244.49076503231,
+ 240.52762911874868,
+ 239.19767530915811,
+ 235.3547408233148,
+ 222.77135367139928,
+ 234.26747289033133,
+ 222.1090879667571,
+ 213.67839960700294,
+ 220.78695617407473,
+ 238.25962030287462,
+ 265.5875885745103,
+ 281.4830979229849,
+ 265.08963832048636,
+ 272.6053430199218,
+ 290.46865219314884,
+ 277.2773336280136,
+ 279.3254063118272,
+ 277.71860735593725,
+ 274.1748170835136,
+ 284.22745240063205,
+ 296.41653958631605,
+ 293.1716168419007,
+ 293.7023992516104,
+ 296.36419976912174,
+ 289.35664391915265,
+ 278.34458913811073,
+ 293.49195242698454,
+ 302.7447105318491,
+ 293.3548318464133,
+ 306.265024468535,
+ 316.34007571598295,
+ 320.6050708597117,
+ 319.8398684632358,
+ 314.3939885564841,
+ 299.3651563947235,
+ 311.75016932500927,
+ 286.5744449293349,
+ 284.51792257776367,
+ 296.12916505146376,
+ 296.143910254921,
+ 290.4436965043894,
+ 286.9509171356384,
+ 285.7353782660105,
+ 295.5481203141585,
+ 303.41923749726544,
+ 308.1306150282999,
+ 298.5647435963675,
+ 309.02289813595524,
+ 300.56226016303185,
+ 312.06482538817767,
+ 298.2095280041462,
+ 288.517714586796,
+ 289.2751273268798,
+ 302.77492930198224,
+ 296.15403611536595,
+ 301.300222213508,
+ 288.1274106750146,
+ 256.3501391424798,
+ 198.61104648895602,
+ 232.17876375277234,
+ 226.37299938748362,
+ 251.28070815857097,
+ 253.4386819534693,
+ 248.00730686110998,
+ 251.20981465197428,
+ 242.3029989334201,
+ 277.8151656727379,
+ 304.3408079639736,
+ 323.87054861742905,
+ 344.77548375050344,
+ 366.4195141948255,
+ 381.31140527510394,
+ 402.786450399951,
+ 391.0039272495355,
+ 405.4842305132651,
+ 429.09830839640495,
+ 428.2369585651376,
+ 437.4693282884787,
+ 444.0045333993229,
+ 476.727609087252,
+ 484.55475348051664,
+ 493.4639696855345,
+ 514.924562516531,
+ 488.9124266125262,
+ 482.9373630725979,
+ 440.5963276777227,
+ 459.5446640353366,
+ 452.01765890108527,
+ 450.7681381232569
+ ],
+ "yaxis": "y"
+ },
+ {
+ "hovertemplate": "series=portfolio_tr
month_end=%{x}
Total Return=%{y}",
+ "legendgroup": "portfolio_tr",
+ "line": {
+ "color": "#EF553B",
+ "dash": "solid"
+ },
+ "marker": {
+ "symbol": "circle"
+ },
+ "mode": "lines",
+ "name": "portfolio_tr",
+ "orientation": "v",
+ "showlegend": true,
+ "type": "scatter",
+ "x": [
+ "2010-01-31",
+ "2010-02-28",
+ "2010-03-31",
+ "2010-04-30",
+ "2010-05-31",
+ "2010-06-30",
+ "2010-07-31",
+ "2010-08-31",
+ "2010-09-30",
+ "2010-10-31",
+ "2010-11-30",
+ "2010-12-31",
+ "2011-01-31",
+ "2011-02-28",
+ "2011-03-31",
+ "2011-04-30",
+ "2011-05-31",
+ "2011-06-30",
+ "2011-07-31",
+ "2011-08-31",
+ "2011-09-30",
+ "2011-10-31",
+ "2011-11-30",
+ "2011-12-31",
+ "2012-01-31",
+ "2012-02-29",
+ "2012-03-31",
+ "2012-04-30",
+ "2012-05-31",
+ "2012-06-30",
+ "2012-07-31",
+ "2012-08-31",
+ "2012-09-30",
+ "2012-10-31",
+ "2012-11-30",
+ "2012-12-31",
+ "2013-01-31",
+ "2013-02-28",
+ "2013-03-31",
+ "2013-04-30",
+ "2013-05-31",
+ "2013-06-30",
+ "2013-07-31",
+ "2013-08-31",
+ "2013-09-30",
+ "2013-10-31",
+ "2013-11-30",
+ "2013-12-31",
+ "2014-01-31",
+ "2014-02-28",
+ "2014-03-31",
+ "2014-04-30",
+ "2014-05-31",
+ "2014-06-30",
+ "2014-07-31",
+ "2014-08-31",
+ "2014-09-30",
+ "2014-10-31",
+ "2014-11-30",
+ "2014-12-31",
+ "2015-01-31",
+ "2015-02-28",
+ "2015-03-31",
+ "2015-04-30",
+ "2015-05-31",
+ "2015-06-30",
+ "2015-07-31",
+ "2015-08-31",
+ "2015-09-30",
+ "2015-10-31",
+ "2015-11-30",
+ "2015-12-31",
+ "2016-01-31",
+ "2016-02-29",
+ "2016-03-31",
+ "2016-04-30",
+ "2016-05-31",
+ "2016-06-30",
+ "2016-07-31",
+ "2016-08-31",
+ "2016-09-30",
+ "2016-10-31",
+ "2016-11-30",
+ "2016-12-31",
+ "2017-01-31",
+ "2017-02-28",
+ "2017-03-31",
+ "2017-04-30",
+ "2017-05-31",
+ "2017-06-30",
+ "2017-07-31",
+ "2017-08-31",
+ "2017-09-30",
+ "2017-10-31",
+ "2017-11-30",
+ "2017-12-31",
+ "2018-01-31",
+ "2018-02-28",
+ "2018-03-31",
+ "2018-04-30",
+ "2018-05-31",
+ "2018-06-30",
+ "2018-07-31",
+ "2018-08-31",
+ "2018-09-30",
+ "2018-10-31",
+ "2018-11-30",
+ "2018-12-31",
+ "2019-01-31",
+ "2019-02-28",
+ "2019-03-31",
+ "2019-04-30",
+ "2019-05-31",
+ "2019-06-30",
+ "2019-07-31",
+ "2019-08-31",
+ "2019-09-30",
+ "2019-10-31",
+ "2019-11-30",
+ "2019-12-31",
+ "2020-01-31",
+ "2020-02-29",
+ "2020-03-31",
+ "2020-04-30",
+ "2020-05-31",
+ "2020-06-30",
+ "2020-07-31",
+ "2020-08-31",
+ "2020-09-30",
+ "2020-10-31",
+ "2020-11-30",
+ "2020-12-31",
+ "2021-01-31",
+ "2021-02-28",
+ "2021-03-31",
+ "2021-04-30",
+ "2021-05-31",
+ "2021-06-30",
+ "2021-07-31",
+ "2021-08-31",
+ "2021-09-30",
+ "2021-10-31",
+ "2021-11-30",
+ "2021-12-31",
+ "2022-01-31",
+ "2022-02-28",
+ "2022-03-31",
+ "2022-04-30",
+ "2022-05-31",
+ "2022-06-30",
+ "2022-07-31",
+ "2022-08-31",
+ "2022-09-30"
+ ],
+ "xaxis": "x",
+ "y": [
+ 98.40422503465814,
+ 100.93798662242051,
+ 107.68288522534036,
+ 109.7995615285553,
+ 107.23242817648126,
+ 106.43966113566464,
+ 113.91349320384909,
+ 112.29508785565194,
+ 122.12549889316125,
+ 124.87638245152488,
+ 124.37504919099058,
+ 131.02440630172168,
+ 125.53974799975698,
+ 128.16916055886097,
+ 130.8873968980463,
+ 134.06376216689685,
+ 133.87076190339369,
+ 132.59760255874266,
+ 132.19487983933925,
+ 133.93330703110996,
+ 130.5237798699564,
+ 139.62267767903492,
+ 142.58187781542216,
+ 140.81510171281383,
+ 147.43151378288488,
+ 151.98680235958813,
+ 152.40074939942423,
+ 156.02418771795553,
+ 152.8161411497546,
+ 155.48775962326914,
+ 159.96753392766976,
+ 161.2555092837166,
+ 163.55646116844596,
+ 166.76092531656502,
+ 169.35948468015056,
+ 179.51302600735073,
+ 178.97405279416094,
+ 175.715694663543,
+ 177.78002433183755,
+ 173.6270905121469,
+ 179.05309265268664,
+ 174.40587342069082,
+ 177.70371255865953,
+ 180.45868512898545,
+ 190.13847786882747,
+ 199.8342118600708,
+ 195.61245975954753,
+ 198.21223347276447,
+ 192.83928084761467,
+ 199.0110446369025,
+ 209.28517002996813,
+ 216.99871696931413,
+ 215.54672594503234,
+ 221.47400674506645,
+ 229.30151970138036,
+ 231.71558423761155,
+ 223.30433148163613,
+ 230.03817391436593,
+ 237.31763181271953,
+ 238.0489478471065,
+ 253.40103532914986,
+ 257.65372033222815,
+ 250.32521657304318,
+ 261.0487471728084,
+ 244.49076503231,
+ 240.52762911874868,
+ 239.19767530915811,
+ 235.3547408233148,
+ 222.77135367139928,
+ 234.26747289033133,
+ 222.1090879667571,
+ 213.67839960700294,
+ 220.78695617407473,
+ 238.25962030287462,
+ 265.5875885745103,
+ 281.4830979229849,
+ 265.08963832048636,
+ 272.6053430199218,
+ 290.46865219314884,
+ 277.2773336280136,
+ 279.3254063118272,
+ 277.71860735593725,
+ 274.1748170835136,
+ 284.22745240063205,
+ 296.41653958631605,
+ 293.1716168419007,
+ 293.7023992516104,
+ 296.36419976912174,
+ 289.35664391915265,
+ 278.34458913811073,
+ 293.49195242698454,
+ 302.7447105318491,
+ 291.81297808172434,
+ 309.10626996662864,
+ 317.93151464087606,
+ 316.6340106209101,
+ 315.6415940400645,
+ 306.9990052206068,
+ 288.99117695611534,
+ 297.8908567145109,
+ 271.40585926689664,
+ 270.4620400595724,
+ 285.3018763187234,
+ 283.9997975387666,
+ 282.3058534912338,
+ 282.8168081839594,
+ 278.16168529764997,
+ 291.8389991142531,
+ 300.6581473947394,
+ 311.92051019766234,
+ 301.82806882343345,
+ 306.22837025547545,
+ 300.3526848452781,
+ 316.38453460148776,
+ 304.12513571919254,
+ 300.04769585835874,
+ 296.0351715215138,
+ 310.85006622435736,
+ 302.69789270338794,
+ 310.1422986996012,
+ 297.82505214543795,
+ 269.1808516515679,
+ 210.10671693995008,
+ 253.26534288438398,
+ 247.6935163444137,
+ 281.9952379928254,
+ 289.24786169036423,
+ 281.9380660561305,
+ 278.33650157223,
+ 266.88642285113906,
+ 308.0500163369409,
+ 344.0453446329626,
+ 378.91887117526875,
+ 412.92074334641126,
+ 445.0244159795605,
+ 470.3391193740556,
+ 492.58036311326003,
+ 474.47257453624434,
+ 498.92778402772774,
+ 532.832242306276,
+ 536.4466618709841,
+ 549.1603759815245,
+ 562.5357729617074,
+ 622.2389260616599,
+ 634.3166868960342,
+ 638.2339235013269,
+ 658.1326681390495,
+ 616.1023879730394,
+ 607.1833690205967,
+ 552.4377707205268,
+ 577.9142474664799,
+ 559.3520550083838,
+ 546.2490099454914
+ ],
+ "yaxis": "y"
+ }
+ ],
+ "layout": {
+ "legend": {
+ "title": {
+ "text": "series"
+ },
+ "tracegroupgap": 0
+ },
+ "margin": {
+ "t": 60
+ },
+ "template": {
+ "data": {
+ "bar": [
+ {
+ "error_x": {
+ "color": "#2a3f5f"
+ },
+ "error_y": {
+ "color": "#2a3f5f"
+ },
+ "marker": {
+ "line": {
+ "color": "#E5ECF6",
+ "width": 0.5
+ },
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "bar"
+ }
+ ],
+ "barpolar": [
+ {
+ "marker": {
+ "line": {
+ "color": "#E5ECF6",
+ "width": 0.5
+ },
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "barpolar"
+ }
+ ],
+ "carpet": [
+ {
+ "aaxis": {
+ "endlinecolor": "#2a3f5f",
+ "gridcolor": "white",
+ "linecolor": "white",
+ "minorgridcolor": "white",
+ "startlinecolor": "#2a3f5f"
+ },
+ "baxis": {
+ "endlinecolor": "#2a3f5f",
+ "gridcolor": "white",
+ "linecolor": "white",
+ "minorgridcolor": "white",
+ "startlinecolor": "#2a3f5f"
+ },
+ "type": "carpet"
+ }
+ ],
+ "choropleth": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "choropleth"
+ }
+ ],
+ "contour": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "contour"
+ }
+ ],
+ "contourcarpet": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "contourcarpet"
+ }
+ ],
+ "heatmap": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "heatmap"
+ }
+ ],
+ "heatmapgl": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "heatmapgl"
+ }
+ ],
+ "histogram": [
+ {
+ "marker": {
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "histogram"
+ }
+ ],
+ "histogram2d": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "histogram2d"
+ }
+ ],
+ "histogram2dcontour": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "histogram2dcontour"
+ }
+ ],
+ "mesh3d": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "mesh3d"
+ }
+ ],
+ "parcoords": [
+ {
+ "line": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "parcoords"
+ }
+ ],
+ "pie": [
+ {
+ "automargin": true,
+ "type": "pie"
+ }
+ ],
+ "scatter": [
+ {
+ "fillpattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ },
+ "type": "scatter"
+ }
+ ],
+ "scatter3d": [
+ {
+ "line": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatter3d"
+ }
+ ],
+ "scattercarpet": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattercarpet"
+ }
+ ],
+ "scattergeo": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattergeo"
+ }
+ ],
+ "scattergl": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattergl"
+ }
+ ],
+ "scattermapbox": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattermapbox"
+ }
+ ],
+ "scatterpolar": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterpolar"
+ }
+ ],
+ "scatterpolargl": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterpolargl"
+ }
+ ],
+ "scatterternary": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterternary"
+ }
+ ],
+ "surface": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "surface"
+ }
+ ],
+ "table": [
+ {
+ "cells": {
+ "fill": {
+ "color": "#EBF0F8"
+ },
+ "line": {
+ "color": "white"
+ }
+ },
+ "header": {
+ "fill": {
+ "color": "#C8D4E3"
+ },
+ "line": {
+ "color": "white"
+ }
+ },
+ "type": "table"
+ }
+ ]
+ },
+ "layout": {
+ "annotationdefaults": {
+ "arrowcolor": "#2a3f5f",
+ "arrowhead": 0,
+ "arrowwidth": 1
+ },
+ "autotypenumbers": "strict",
+ "coloraxis": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "colorscale": {
+ "diverging": [
+ [
+ 0,
+ "#8e0152"
+ ],
+ [
+ 0.1,
+ "#c51b7d"
+ ],
+ [
+ 0.2,
+ "#de77ae"
+ ],
+ [
+ 0.3,
+ "#f1b6da"
+ ],
+ [
+ 0.4,
+ "#fde0ef"
+ ],
+ [
+ 0.5,
+ "#f7f7f7"
+ ],
+ [
+ 0.6,
+ "#e6f5d0"
+ ],
+ [
+ 0.7,
+ "#b8e186"
+ ],
+ [
+ 0.8,
+ "#7fbc41"
+ ],
+ [
+ 0.9,
+ "#4d9221"
+ ],
+ [
+ 1,
+ "#276419"
+ ]
+ ],
+ "sequential": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "sequentialminus": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ]
+ },
+ "colorway": [
+ "#636efa",
+ "#EF553B",
+ "#00cc96",
+ "#ab63fa",
+ "#FFA15A",
+ "#19d3f3",
+ "#FF6692",
+ "#B6E880",
+ "#FF97FF",
+ "#FECB52"
+ ],
+ "font": {
+ "color": "#2a3f5f"
+ },
+ "geo": {
+ "bgcolor": "white",
+ "lakecolor": "white",
+ "landcolor": "#E5ECF6",
+ "showlakes": true,
+ "showland": true,
+ "subunitcolor": "white"
+ },
+ "hoverlabel": {
+ "align": "left"
+ },
+ "hovermode": "closest",
+ "mapbox": {
+ "style": "light"
+ },
+ "paper_bgcolor": "white",
+ "plot_bgcolor": "#E5ECF6",
+ "polar": {
+ "angularaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "bgcolor": "#E5ECF6",
+ "radialaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ }
+ },
+ "scene": {
+ "xaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ },
+ "yaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ },
+ "zaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ }
+ },
+ "shapedefaults": {
+ "line": {
+ "color": "#2a3f5f"
+ }
+ },
+ "ternary": {
+ "aaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "baxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "bgcolor": "#E5ECF6",
+ "caxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ }
+ },
+ "title": {
+ "x": 0.05
+ },
+ "xaxis": {
+ "automargin": true,
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": "",
+ "title": {
+ "standoff": 15
+ },
+ "zerolinecolor": "white",
+ "zerolinewidth": 2
+ },
+ "yaxis": {
+ "automargin": true,
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": "",
+ "title": {
+ "standoff": 15
+ },
+ "zerolinecolor": "white",
+ "zerolinewidth": 2
+ }
+ }
+ },
+ "xaxis": {
+ "anchor": "y",
+ "domain": [
+ 0,
+ 1
+ ],
+ "title": {
+ "text": "month_end"
+ }
+ },
+ "yaxis": {
+ "anchor": "x",
+ "domain": [
+ 0,
+ 1
+ ],
+ "title": {
+ "text": "Total Return"
+ }
+ }
+ }
+ }
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# running solution\n",
+ "df_returns = pd.concat(objs=[df_returns_train, df_returns_test], ignore_index=True)\n",
+ "df_weights_index = equalise_weights(df_returns)\n",
+ "df_returns, df_weights_portfolio = generate_portfolio(df_returns_train, df_returns_test)\n",
+ "fig1, df_rtn = plot_total_return(\n",
+ " df_returns,\n",
+ " df_weights_index=df_weights_index,\n",
+ " df_weights_portfolio=df_weights_portfolio,\n",
+ ")\n",
+ "fig1"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.10.11"
+ },
+ "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Challenge.ipynb b/Challenge.ipynb
new file mode 100644
index 0000000..8304f18
--- /dev/null
+++ b/Challenge.ipynb
@@ -0,0 +1,3326 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 458,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "---Python script Start--- 2023-08-05 13:39:49.348381\n"
+ ]
+ }
+ ],
+ "source": [
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import datetime\n",
+ "import plotly.express as px\n",
+ "from keras.models import Sequential\n",
+ "from keras.layers import LSTM, Dense, Dropout\n",
+ "from sklearn.preprocessing import MinMaxScaler\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "print(\"---Python script Start---\", str(datetime.datetime.now()))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 459,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " month_end | \n",
+ " Stock1 | \n",
+ " Stock10 | \n",
+ " Stock11 | \n",
+ " Stock14 | \n",
+ " Stock16 | \n",
+ " Stock18 | \n",
+ " Stock19 | \n",
+ " Stock20 | \n",
+ " Stock21 | \n",
+ " ... | \n",
+ " Stock78 | \n",
+ " Stock79 | \n",
+ " Stock80 | \n",
+ " Stock81 | \n",
+ " Stock84 | \n",
+ " Stock85 | \n",
+ " Stock86 | \n",
+ " Stock87 | \n",
+ " Stock88 | \n",
+ " Stock9 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 2010-01-31 | \n",
+ " 0.042603 | \n",
+ " -0.076059 | \n",
+ " -0.149741 | \n",
+ " -0.031251 | \n",
+ " -0.053032 | \n",
+ " -0.113752 | \n",
+ " -0.071671 | \n",
+ " 0.005430 | \n",
+ " 0.005715 | \n",
+ " ... | \n",
+ " -0.028168 | \n",
+ " 0.017445 | \n",
+ " -0.100000 | \n",
+ " 0.018014 | \n",
+ " 0.044749 | \n",
+ " 0.016824 | \n",
+ " -0.111084 | \n",
+ " -0.035229 | \n",
+ " -0.033204 | \n",
+ " 0.030927 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2010-02-28 | \n",
+ " -0.015034 | \n",
+ " -0.100305 | \n",
+ " -0.023279 | \n",
+ " 0.002484 | \n",
+ " 0.077088 | \n",
+ " 0.010849 | \n",
+ " 0.022383 | \n",
+ " 0.095480 | \n",
+ " 0.067745 | \n",
+ " ... | \n",
+ " 0.082448 | \n",
+ " -0.106195 | \n",
+ " 0.066669 | \n",
+ " 0.000556 | \n",
+ " -0.010800 | \n",
+ " 0.006326 | \n",
+ " -0.026405 | \n",
+ " -0.013759 | \n",
+ " 0.095241 | \n",
+ " -0.010000 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 2010-03-31 | \n",
+ " 0.111545 | \n",
+ " 0.097933 | \n",
+ " 0.121501 | \n",
+ " 0.064357 | \n",
+ " 0.107439 | \n",
+ " 0.017883 | \n",
+ " 0.000892 | \n",
+ " 0.032425 | \n",
+ " 0.018012 | \n",
+ " ... | \n",
+ " 0.036357 | \n",
+ " 0.220049 | \n",
+ " 0.098957 | \n",
+ " 0.088889 | \n",
+ " 0.088630 | \n",
+ " 0.047296 | \n",
+ " 0.153527 | \n",
+ " 0.034416 | \n",
+ " 0.041795 | \n",
+ " 0.024809 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 2010-04-30 | \n",
+ " -0.040491 | \n",
+ " -0.034262 | \n",
+ " -0.032848 | \n",
+ " -0.030232 | \n",
+ " 0.022388 | \n",
+ " 0.085504 | \n",
+ " -0.007159 | \n",
+ " 0.052763 | \n",
+ " 0.017920 | \n",
+ " ... | \n",
+ " 0.040579 | \n",
+ " 0.004259 | \n",
+ " -0.052133 | \n",
+ " 0.005099 | \n",
+ " -0.016164 | \n",
+ " 0.012845 | \n",
+ " -0.004702 | \n",
+ " 0.019786 | \n",
+ " 0.042046 | \n",
+ " 0.030303 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 2010-05-31 | \n",
+ " -0.069359 | \n",
+ " -0.073188 | \n",
+ " 0.004349 | \n",
+ " 0.010792 | \n",
+ " -0.025548 | \n",
+ " -0.001887 | \n",
+ " -0.012534 | \n",
+ " 0.068973 | \n",
+ " -0.026794 | \n",
+ " ... | \n",
+ " -0.025069 | \n",
+ " -0.062221 | \n",
+ " 0.004332 | \n",
+ " -0.023857 | \n",
+ " -0.085645 | \n",
+ " -0.041085 | \n",
+ " -0.083320 | \n",
+ " 0.095238 | \n",
+ " -0.124253 | \n",
+ " -0.010784 | \n",
+ "
\n",
+ " \n",
+ " | ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " | 87 | \n",
+ " 2017-04-30 | \n",
+ " 0.057631 | \n",
+ " 0.089651 | \n",
+ " -0.090908 | \n",
+ " -0.045544 | \n",
+ " 0.033207 | \n",
+ " -0.003331 | \n",
+ " 0.036885 | \n",
+ " -0.017510 | \n",
+ " 0.097012 | \n",
+ " ... | \n",
+ " 0.039548 | \n",
+ " 0.009388 | \n",
+ " 0.096569 | \n",
+ " 0.086140 | \n",
+ " 0.097051 | \n",
+ " 0.036655 | \n",
+ " -0.059447 | \n",
+ " -0.005197 | \n",
+ " -0.111087 | \n",
+ " 0.044074 | \n",
+ "
\n",
+ " \n",
+ " | 88 | \n",
+ " 2017-05-31 | \n",
+ " -0.013557 | \n",
+ " -0.027089 | \n",
+ " -0.050713 | \n",
+ " -0.052443 | \n",
+ " -0.132316 | \n",
+ " -0.013774 | \n",
+ " -0.071147 | \n",
+ " -0.045192 | \n",
+ " -0.031881 | \n",
+ " ... | \n",
+ " -0.042451 | \n",
+ " -0.032799 | \n",
+ " 0.069729 | \n",
+ " -0.018660 | \n",
+ " -0.054422 | \n",
+ " 0.071153 | \n",
+ " -0.083055 | \n",
+ " 0.092917 | \n",
+ " -0.039052 | \n",
+ " -0.031945 | \n",
+ "
\n",
+ " \n",
+ " | 89 | \n",
+ " 2017-06-30 | \n",
+ " -0.022060 | \n",
+ " -0.098539 | \n",
+ " -0.016556 | \n",
+ " 0.005218 | \n",
+ " -0.008810 | \n",
+ " -0.125433 | \n",
+ " -0.028937 | \n",
+ " 0.069444 | \n",
+ " -0.055806 | \n",
+ " ... | \n",
+ " -0.001562 | \n",
+ " -0.055437 | \n",
+ " -0.062808 | \n",
+ " -0.019475 | \n",
+ " 0.034172 | \n",
+ " -0.077723 | \n",
+ " -0.002616 | \n",
+ " 0.020783 | \n",
+ " 0.038300 | \n",
+ " 0.011196 | \n",
+ "
\n",
+ " \n",
+ " | 90 | \n",
+ " 2017-07-31 | \n",
+ " 0.036795 | \n",
+ " 0.002527 | \n",
+ " 0.059680 | \n",
+ " 0.074563 | \n",
+ " 0.135041 | \n",
+ " 0.056864 | \n",
+ " 0.038476 | \n",
+ " 0.109808 | \n",
+ " 0.023922 | \n",
+ " ... | \n",
+ " 0.096860 | \n",
+ " 0.089980 | \n",
+ " 0.142830 | \n",
+ " 0.001359 | \n",
+ " 0.005916 | \n",
+ " 0.064159 | \n",
+ " 0.234903 | \n",
+ " 0.084005 | \n",
+ " 0.112443 | \n",
+ " 0.027391 | \n",
+ "
\n",
+ " \n",
+ " | 91 | \n",
+ " 2017-08-31 | \n",
+ " 0.032189 | \n",
+ " 0.001031 | \n",
+ " 0.101082 | \n",
+ " 0.008990 | \n",
+ " 0.010417 | \n",
+ " -0.035204 | \n",
+ " 0.112929 | \n",
+ " 0.046901 | \n",
+ " 0.082138 | \n",
+ " ... | \n",
+ " 0.073335 | \n",
+ " 0.083564 | \n",
+ " 0.011163 | \n",
+ " 0.016842 | \n",
+ " 0.026141 | \n",
+ " 0.022422 | \n",
+ " 0.116454 | \n",
+ " 0.019769 | \n",
+ " 0.171767 | \n",
+ " -0.005104 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
92 rows × 55 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " month_end Stock1 Stock10 Stock11 Stock14 Stock16 Stock18 \n",
+ "0 2010-01-31 0.042603 -0.076059 -0.149741 -0.031251 -0.053032 -0.113752 \\\n",
+ "1 2010-02-28 -0.015034 -0.100305 -0.023279 0.002484 0.077088 0.010849 \n",
+ "2 2010-03-31 0.111545 0.097933 0.121501 0.064357 0.107439 0.017883 \n",
+ "3 2010-04-30 -0.040491 -0.034262 -0.032848 -0.030232 0.022388 0.085504 \n",
+ "4 2010-05-31 -0.069359 -0.073188 0.004349 0.010792 -0.025548 -0.001887 \n",
+ ".. ... ... ... ... ... ... ... \n",
+ "87 2017-04-30 0.057631 0.089651 -0.090908 -0.045544 0.033207 -0.003331 \n",
+ "88 2017-05-31 -0.013557 -0.027089 -0.050713 -0.052443 -0.132316 -0.013774 \n",
+ "89 2017-06-30 -0.022060 -0.098539 -0.016556 0.005218 -0.008810 -0.125433 \n",
+ "90 2017-07-31 0.036795 0.002527 0.059680 0.074563 0.135041 0.056864 \n",
+ "91 2017-08-31 0.032189 0.001031 0.101082 0.008990 0.010417 -0.035204 \n",
+ "\n",
+ " Stock19 Stock20 Stock21 ... Stock78 Stock79 Stock80 Stock81 \n",
+ "0 -0.071671 0.005430 0.005715 ... -0.028168 0.017445 -0.100000 0.018014 \\\n",
+ "1 0.022383 0.095480 0.067745 ... 0.082448 -0.106195 0.066669 0.000556 \n",
+ "2 0.000892 0.032425 0.018012 ... 0.036357 0.220049 0.098957 0.088889 \n",
+ "3 -0.007159 0.052763 0.017920 ... 0.040579 0.004259 -0.052133 0.005099 \n",
+ "4 -0.012534 0.068973 -0.026794 ... -0.025069 -0.062221 0.004332 -0.023857 \n",
+ ".. ... ... ... ... ... ... ... ... \n",
+ "87 0.036885 -0.017510 0.097012 ... 0.039548 0.009388 0.096569 0.086140 \n",
+ "88 -0.071147 -0.045192 -0.031881 ... -0.042451 -0.032799 0.069729 -0.018660 \n",
+ "89 -0.028937 0.069444 -0.055806 ... -0.001562 -0.055437 -0.062808 -0.019475 \n",
+ "90 0.038476 0.109808 0.023922 ... 0.096860 0.089980 0.142830 0.001359 \n",
+ "91 0.112929 0.046901 0.082138 ... 0.073335 0.083564 0.011163 0.016842 \n",
+ "\n",
+ " Stock84 Stock85 Stock86 Stock87 Stock88 Stock9 \n",
+ "0 0.044749 0.016824 -0.111084 -0.035229 -0.033204 0.030927 \n",
+ "1 -0.010800 0.006326 -0.026405 -0.013759 0.095241 -0.010000 \n",
+ "2 0.088630 0.047296 0.153527 0.034416 0.041795 0.024809 \n",
+ "3 -0.016164 0.012845 -0.004702 0.019786 0.042046 0.030303 \n",
+ "4 -0.085645 -0.041085 -0.083320 0.095238 -0.124253 -0.010784 \n",
+ ".. ... ... ... ... ... ... \n",
+ "87 0.097051 0.036655 -0.059447 -0.005197 -0.111087 0.044074 \n",
+ "88 -0.054422 0.071153 -0.083055 0.092917 -0.039052 -0.031945 \n",
+ "89 0.034172 -0.077723 -0.002616 0.020783 0.038300 0.011196 \n",
+ "90 0.005916 0.064159 0.234903 0.084005 0.112443 0.027391 \n",
+ "91 0.026141 0.022422 0.116454 0.019769 0.171767 -0.005104 \n",
+ "\n",
+ "[92 rows x 55 columns]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "df = pd.read_csv(\n",
+ " \"C:\\\\Users\\\\terre\\OneDrive - University of Cape Town\\\\Terrence\\\\Code\\\\prescient-coding-challenge-2023\\\\data\\\\returns_train.csv\"\n",
+ ")\n",
+ "display(df)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 460,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " month_end | \n",
+ " Stock1 | \n",
+ " Stock10 | \n",
+ " Stock11 | \n",
+ " Stock14 | \n",
+ " Stock16 | \n",
+ " Stock18 | \n",
+ " Stock19 | \n",
+ " Stock20 | \n",
+ " Stock21 | \n",
+ " ... | \n",
+ " Stock78 | \n",
+ " Stock79 | \n",
+ " Stock80 | \n",
+ " Stock81 | \n",
+ " Stock84 | \n",
+ " Stock85 | \n",
+ " Stock86 | \n",
+ " Stock87 | \n",
+ " Stock88 | \n",
+ " Stock9 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 2017-09-30 | \n",
+ " 0.083899 | \n",
+ " 0.053319 | \n",
+ " 0.049182 | \n",
+ " -0.099562 | \n",
+ " -0.114310 | \n",
+ " -0.055291 | \n",
+ " -0.037531 | \n",
+ " -0.006674 | \n",
+ " -0.057661 | \n",
+ " ... | \n",
+ " -0.066003 | \n",
+ " -0.031052 | \n",
+ " -0.004497 | \n",
+ " -0.055256 | \n",
+ " -0.031516 | \n",
+ " 0.023068 | \n",
+ " 0.031268 | \n",
+ " -0.112615 | \n",
+ " -0.011307 | \n",
+ " 0.022963 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2017-10-31 | \n",
+ " 0.060536 | \n",
+ " 0.028676 | \n",
+ " 0.029625 | \n",
+ " 0.029335 | \n",
+ " -0.001841 | \n",
+ " -0.106763 | \n",
+ " -0.012945 | \n",
+ " -0.026603 | \n",
+ " 0.044929 | \n",
+ " ... | \n",
+ " 0.048952 | \n",
+ " 0.070757 | \n",
+ " 0.179795 | \n",
+ " 0.042174 | \n",
+ " 0.008201 | \n",
+ " -0.006720 | \n",
+ " 0.093561 | \n",
+ " -0.046792 | \n",
+ " 0.215918 | \n",
+ " -0.018551 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 2017-11-30 | \n",
+ " -0.102193 | \n",
+ " 0.027349 | \n",
+ " -0.128125 | \n",
+ " 0.073356 | \n",
+ " 0.166052 | \n",
+ " -0.041408 | \n",
+ " 0.052944 | \n",
+ " 0.186932 | \n",
+ " 0.106927 | \n",
+ " ... | \n",
+ " 0.123914 | \n",
+ " 0.156616 | \n",
+ " 0.070452 | \n",
+ " 0.014745 | \n",
+ " 0.125875 | \n",
+ " 0.115800 | \n",
+ " -0.046361 | \n",
+ " -0.030274 | \n",
+ " -0.026521 | \n",
+ " 0.018901 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 2017-12-31 | \n",
+ " -0.045036 | \n",
+ " -0.080070 | \n",
+ " -0.131899 | \n",
+ " 0.098228 | \n",
+ " 0.248923 | \n",
+ " -0.029056 | \n",
+ " 0.056703 | \n",
+ " 0.192133 | \n",
+ " 0.111679 | \n",
+ " ... | \n",
+ " 0.129262 | \n",
+ " 0.034759 | \n",
+ " -0.064190 | \n",
+ " 0.102804 | \n",
+ " 0.153443 | \n",
+ " 0.139685 | \n",
+ " 0.011155 | \n",
+ " 0.004274 | \n",
+ " 0.111534 | \n",
+ " 0.075942 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 2018-01-31 | \n",
+ " 0.026665 | \n",
+ " -0.025548 | \n",
+ " -0.009082 | \n",
+ " -0.018691 | \n",
+ " -0.001265 | \n",
+ " 0.071279 | \n",
+ " -0.038067 | \n",
+ " 0.167967 | \n",
+ " 0.013795 | \n",
+ " ... | \n",
+ " -0.092203 | \n",
+ " 0.075166 | \n",
+ " -0.019854 | \n",
+ " 0.001060 | \n",
+ " -0.010387 | \n",
+ " 0.146272 | \n",
+ " 0.133166 | \n",
+ " 0.122322 | \n",
+ " -0.046485 | \n",
+ " -0.049569 | \n",
+ "
\n",
+ " \n",
+ " | ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " | 56 | \n",
+ " 2022-05-31 | \n",
+ " -0.083869 | \n",
+ " -0.024526 | \n",
+ " -0.009009 | \n",
+ " -0.044468 | \n",
+ " 0.019794 | \n",
+ " -0.016504 | \n",
+ " 0.000652 | \n",
+ " -0.035289 | \n",
+ " 0.024911 | \n",
+ " ... | \n",
+ " -0.044724 | \n",
+ " -0.139194 | \n",
+ " 0.066355 | \n",
+ " 0.057087 | \n",
+ " 0.068901 | \n",
+ " 0.000458 | \n",
+ " 0.068366 | \n",
+ " -0.032767 | \n",
+ " -0.004966 | \n",
+ " -0.004018 | \n",
+ "
\n",
+ " \n",
+ " | 57 | \n",
+ " 2022-06-30 | \n",
+ " -0.004672 | \n",
+ " -0.053094 | \n",
+ " 0.022726 | \n",
+ " 0.057442 | \n",
+ " -0.138842 | \n",
+ " -0.213426 | \n",
+ " -0.217772 | \n",
+ " -0.120665 | \n",
+ " -0.216392 | \n",
+ " ... | \n",
+ " -0.119287 | \n",
+ " -0.074327 | \n",
+ " 0.381054 | \n",
+ " -0.137041 | \n",
+ " -0.158318 | \n",
+ " -0.039239 | \n",
+ " -0.238200 | \n",
+ " -0.078775 | \n",
+ " -0.179747 | \n",
+ " -0.137902 | \n",
+ "
\n",
+ " \n",
+ " | 58 | \n",
+ " 2022-07-31 | \n",
+ " 0.145072 | \n",
+ " 0.021164 | \n",
+ " -0.064891 | \n",
+ " -0.019389 | \n",
+ " 0.022547 | \n",
+ " 0.192015 | \n",
+ " 0.053393 | \n",
+ " 0.015562 | \n",
+ " 0.031020 | \n",
+ " ... | \n",
+ " 0.001483 | \n",
+ " 0.020277 | \n",
+ " -0.004769 | \n",
+ " 0.051881 | \n",
+ " 0.099740 | \n",
+ " 0.019991 | \n",
+ " 0.032506 | \n",
+ " 0.051858 | \n",
+ " 0.093850 | \n",
+ " 0.125350 | \n",
+ "
\n",
+ " \n",
+ " | 59 | \n",
+ " 2022-08-31 | \n",
+ " -0.023993 | \n",
+ " -0.166561 | \n",
+ " -0.145650 | \n",
+ " 0.121916 | \n",
+ " 0.045429 | \n",
+ " 0.003722 | \n",
+ " -0.106694 | \n",
+ " 0.033809 | \n",
+ " -0.021830 | \n",
+ " ... | \n",
+ " -0.042483 | \n",
+ " -0.047557 | \n",
+ " 0.029426 | \n",
+ " -0.067982 | \n",
+ " 0.047055 | \n",
+ " 0.005474 | \n",
+ " -0.046378 | \n",
+ " -0.085405 | \n",
+ " -0.006774 | \n",
+ " -0.136339 | \n",
+ "
\n",
+ " \n",
+ " | 60 | \n",
+ " 2022-09-30 | \n",
+ " -0.083590 | \n",
+ " -0.038025 | \n",
+ " -0.311732 | \n",
+ " -0.102412 | \n",
+ " -0.074947 | \n",
+ " 0.055505 | \n",
+ " -0.035172 | \n",
+ " -0.072121 | \n",
+ " -0.032445 | \n",
+ " ... | \n",
+ " -0.145799 | \n",
+ " 0.060575 | \n",
+ " -0.066981 | \n",
+ " 0.042320 | \n",
+ " 0.028347 | \n",
+ " -0.069651 | \n",
+ " -0.010064 | \n",
+ " -0.032264 | \n",
+ " 0.123798 | \n",
+ " -0.141075 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
61 rows × 55 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " month_end Stock1 Stock10 Stock11 Stock14 Stock16 Stock18 \n",
+ "0 2017-09-30 0.083899 0.053319 0.049182 -0.099562 -0.114310 -0.055291 \\\n",
+ "1 2017-10-31 0.060536 0.028676 0.029625 0.029335 -0.001841 -0.106763 \n",
+ "2 2017-11-30 -0.102193 0.027349 -0.128125 0.073356 0.166052 -0.041408 \n",
+ "3 2017-12-31 -0.045036 -0.080070 -0.131899 0.098228 0.248923 -0.029056 \n",
+ "4 2018-01-31 0.026665 -0.025548 -0.009082 -0.018691 -0.001265 0.071279 \n",
+ ".. ... ... ... ... ... ... ... \n",
+ "56 2022-05-31 -0.083869 -0.024526 -0.009009 -0.044468 0.019794 -0.016504 \n",
+ "57 2022-06-30 -0.004672 -0.053094 0.022726 0.057442 -0.138842 -0.213426 \n",
+ "58 2022-07-31 0.145072 0.021164 -0.064891 -0.019389 0.022547 0.192015 \n",
+ "59 2022-08-31 -0.023993 -0.166561 -0.145650 0.121916 0.045429 0.003722 \n",
+ "60 2022-09-30 -0.083590 -0.038025 -0.311732 -0.102412 -0.074947 0.055505 \n",
+ "\n",
+ " Stock19 Stock20 Stock21 ... Stock78 Stock79 Stock80 Stock81 \n",
+ "0 -0.037531 -0.006674 -0.057661 ... -0.066003 -0.031052 -0.004497 -0.055256 \\\n",
+ "1 -0.012945 -0.026603 0.044929 ... 0.048952 0.070757 0.179795 0.042174 \n",
+ "2 0.052944 0.186932 0.106927 ... 0.123914 0.156616 0.070452 0.014745 \n",
+ "3 0.056703 0.192133 0.111679 ... 0.129262 0.034759 -0.064190 0.102804 \n",
+ "4 -0.038067 0.167967 0.013795 ... -0.092203 0.075166 -0.019854 0.001060 \n",
+ ".. ... ... ... ... ... ... ... ... \n",
+ "56 0.000652 -0.035289 0.024911 ... -0.044724 -0.139194 0.066355 0.057087 \n",
+ "57 -0.217772 -0.120665 -0.216392 ... -0.119287 -0.074327 0.381054 -0.137041 \n",
+ "58 0.053393 0.015562 0.031020 ... 0.001483 0.020277 -0.004769 0.051881 \n",
+ "59 -0.106694 0.033809 -0.021830 ... -0.042483 -0.047557 0.029426 -0.067982 \n",
+ "60 -0.035172 -0.072121 -0.032445 ... -0.145799 0.060575 -0.066981 0.042320 \n",
+ "\n",
+ " Stock84 Stock85 Stock86 Stock87 Stock88 Stock9 \n",
+ "0 -0.031516 0.023068 0.031268 -0.112615 -0.011307 0.022963 \n",
+ "1 0.008201 -0.006720 0.093561 -0.046792 0.215918 -0.018551 \n",
+ "2 0.125875 0.115800 -0.046361 -0.030274 -0.026521 0.018901 \n",
+ "3 0.153443 0.139685 0.011155 0.004274 0.111534 0.075942 \n",
+ "4 -0.010387 0.146272 0.133166 0.122322 -0.046485 -0.049569 \n",
+ ".. ... ... ... ... ... ... \n",
+ "56 0.068901 0.000458 0.068366 -0.032767 -0.004966 -0.004018 \n",
+ "57 -0.158318 -0.039239 -0.238200 -0.078775 -0.179747 -0.137902 \n",
+ "58 0.099740 0.019991 0.032506 0.051858 0.093850 0.125350 \n",
+ "59 0.047055 0.005474 -0.046378 -0.085405 -0.006774 -0.136339 \n",
+ "60 0.028347 -0.069651 -0.010064 -0.032264 0.123798 -0.141075 \n",
+ "\n",
+ "[61 rows x 55 columns]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "df = pd.read_csv(\n",
+ " \"C:\\\\Users\\\\terre\\OneDrive - University of Cape Town\\\\Terrence\\\\Code\\\\prescient-coding-challenge-2023\\\\data\\\\returns_test.csv\"\n",
+ ")\n",
+ "display(df)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 461,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# data reads\n",
+ "df_returns_train = pd.read_csv(\"data/returns_train.csv\")\n",
+ "df_returns_test = pd.read_csv(\"data/returns_test.csv\")\n",
+ "df_returns_train[\"month_end\"] = pd.to_datetime(arg=df_returns_train[\"month_end\"]).apply(\n",
+ " lambda d: d.date()\n",
+ ")\n",
+ "df_returns_test[\"month_end\"] = pd.to_datetime(arg=df_returns_test[\"month_end\"]).apply(\n",
+ " lambda d: d.date()\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 462,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "['Stock1', 'Stock10', 'Stock11', 'Stock14', 'Stock16', 'Stock18', 'Stock19', 'Stock20', 'Stock21', 'Stock22', 'Stock26', 'Stock3', 'Stock30', 'Stock31', 'Stock33', 'Stock34', 'Stock35', 'Stock38', 'Stock39', 'Stock4', 'Stock40', 'Stock41', 'Stock43', 'Stock44', 'Stock46', 'Stock47', 'Stock49', 'Stock5', 'Stock50', 'Stock54', 'Stock56', 'Stock59', 'Stock6', 'Stock61', 'Stock63', 'Stock64', 'Stock66', 'Stock69', 'Stock7', 'Stock70', 'Stock73', 'Stock75', 'Stock76', 'Stock77', 'Stock78', 'Stock79', 'Stock80', 'Stock81', 'Stock84', 'Stock85', 'Stock86', 'Stock87', 'Stock88', 'Stock9']\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " Stock1 | \n",
+ " Stock10 | \n",
+ " Stock11 | \n",
+ " Stock14 | \n",
+ " Stock16 | \n",
+ " Stock18 | \n",
+ " Stock19 | \n",
+ " Stock20 | \n",
+ " Stock21 | \n",
+ " Stock22 | \n",
+ " ... | \n",
+ " Stock78 | \n",
+ " Stock79 | \n",
+ " Stock80 | \n",
+ " Stock81 | \n",
+ " Stock84 | \n",
+ " Stock85 | \n",
+ " Stock86 | \n",
+ " Stock87 | \n",
+ " Stock88 | \n",
+ " Stock9 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 0.042603 | \n",
+ " -0.076059 | \n",
+ " -0.149741 | \n",
+ " -0.031251 | \n",
+ " -0.053032 | \n",
+ " -0.113752 | \n",
+ " -0.071671 | \n",
+ " 0.005430 | \n",
+ " 0.005715 | \n",
+ " 0.001399 | \n",
+ " ... | \n",
+ " -0.028168 | \n",
+ " 0.017445 | \n",
+ " -0.100000 | \n",
+ " 0.018014 | \n",
+ " 0.044749 | \n",
+ " 0.016824 | \n",
+ " -0.111084 | \n",
+ " -0.035229 | \n",
+ " -0.033204 | \n",
+ " 0.030927 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " -0.015034 | \n",
+ " -0.100305 | \n",
+ " -0.023279 | \n",
+ " 0.002484 | \n",
+ " 0.077088 | \n",
+ " 0.010849 | \n",
+ " 0.022383 | \n",
+ " 0.095480 | \n",
+ " 0.067745 | \n",
+ " 0.082493 | \n",
+ " ... | \n",
+ " 0.082448 | \n",
+ " -0.106195 | \n",
+ " 0.066669 | \n",
+ " 0.000556 | \n",
+ " -0.010800 | \n",
+ " 0.006326 | \n",
+ " -0.026405 | \n",
+ " -0.013759 | \n",
+ " 0.095241 | \n",
+ " -0.010000 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 0.111545 | \n",
+ " 0.097933 | \n",
+ " 0.121501 | \n",
+ " 0.064357 | \n",
+ " 0.107439 | \n",
+ " 0.017883 | \n",
+ " 0.000892 | \n",
+ " 0.032425 | \n",
+ " 0.018012 | \n",
+ " 0.031663 | \n",
+ " ... | \n",
+ " 0.036357 | \n",
+ " 0.220049 | \n",
+ " 0.098957 | \n",
+ " 0.088889 | \n",
+ " 0.088630 | \n",
+ " 0.047296 | \n",
+ " 0.153527 | \n",
+ " 0.034416 | \n",
+ " 0.041795 | \n",
+ " 0.024809 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " -0.040491 | \n",
+ " -0.034262 | \n",
+ " -0.032848 | \n",
+ " -0.030232 | \n",
+ " 0.022388 | \n",
+ " 0.085504 | \n",
+ " -0.007159 | \n",
+ " 0.052763 | \n",
+ " 0.017920 | \n",
+ " 0.007674 | \n",
+ " ... | \n",
+ " 0.040579 | \n",
+ " 0.004259 | \n",
+ " -0.052133 | \n",
+ " 0.005099 | \n",
+ " -0.016164 | \n",
+ " 0.012845 | \n",
+ " -0.004702 | \n",
+ " 0.019786 | \n",
+ " 0.042046 | \n",
+ " 0.030303 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " -0.069359 | \n",
+ " -0.073188 | \n",
+ " 0.004349 | \n",
+ " 0.010792 | \n",
+ " -0.025548 | \n",
+ " -0.001887 | \n",
+ " -0.012534 | \n",
+ " 0.068973 | \n",
+ " -0.026794 | \n",
+ " -0.056697 | \n",
+ " ... | \n",
+ " -0.025069 | \n",
+ " -0.062221 | \n",
+ " 0.004332 | \n",
+ " -0.023857 | \n",
+ " -0.085645 | \n",
+ " -0.041085 | \n",
+ " -0.083320 | \n",
+ " 0.095238 | \n",
+ " -0.124253 | \n",
+ " -0.010784 | \n",
+ "
\n",
+ " \n",
+ " | ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " | 87 | \n",
+ " 0.057631 | \n",
+ " 0.089651 | \n",
+ " -0.090908 | \n",
+ " -0.045544 | \n",
+ " 0.033207 | \n",
+ " -0.003331 | \n",
+ " 0.036885 | \n",
+ " -0.017510 | \n",
+ " 0.097012 | \n",
+ " -0.000908 | \n",
+ " ... | \n",
+ " 0.039548 | \n",
+ " 0.009388 | \n",
+ " 0.096569 | \n",
+ " 0.086140 | \n",
+ " 0.097051 | \n",
+ " 0.036655 | \n",
+ " -0.059447 | \n",
+ " -0.005197 | \n",
+ " -0.111087 | \n",
+ " 0.044074 | \n",
+ "
\n",
+ " \n",
+ " | 88 | \n",
+ " -0.013557 | \n",
+ " -0.027089 | \n",
+ " -0.050713 | \n",
+ " -0.052443 | \n",
+ " -0.132316 | \n",
+ " -0.013774 | \n",
+ " -0.071147 | \n",
+ " -0.045192 | \n",
+ " -0.031881 | \n",
+ " -0.000167 | \n",
+ " ... | \n",
+ " -0.042451 | \n",
+ " -0.032799 | \n",
+ " 0.069729 | \n",
+ " -0.018660 | \n",
+ " -0.054422 | \n",
+ " 0.071153 | \n",
+ " -0.083055 | \n",
+ " 0.092917 | \n",
+ " -0.039052 | \n",
+ " -0.031945 | \n",
+ "
\n",
+ " \n",
+ " | 89 | \n",
+ " -0.022060 | \n",
+ " -0.098539 | \n",
+ " -0.016556 | \n",
+ " 0.005218 | \n",
+ " -0.008810 | \n",
+ " -0.125433 | \n",
+ " -0.028937 | \n",
+ " 0.069444 | \n",
+ " -0.055806 | \n",
+ " -0.002845 | \n",
+ " ... | \n",
+ " -0.001562 | \n",
+ " -0.055437 | \n",
+ " -0.062808 | \n",
+ " -0.019475 | \n",
+ " 0.034172 | \n",
+ " -0.077723 | \n",
+ " -0.002616 | \n",
+ " 0.020783 | \n",
+ " 0.038300 | \n",
+ " 0.011196 | \n",
+ "
\n",
+ " \n",
+ " | 90 | \n",
+ " 0.036795 | \n",
+ " 0.002527 | \n",
+ " 0.059680 | \n",
+ " 0.074563 | \n",
+ " 0.135041 | \n",
+ " 0.056864 | \n",
+ " 0.038476 | \n",
+ " 0.109808 | \n",
+ " 0.023922 | \n",
+ " 0.023766 | \n",
+ " ... | \n",
+ " 0.096860 | \n",
+ " 0.089980 | \n",
+ " 0.142830 | \n",
+ " 0.001359 | \n",
+ " 0.005916 | \n",
+ " 0.064159 | \n",
+ " 0.234903 | \n",
+ " 0.084005 | \n",
+ " 0.112443 | \n",
+ " 0.027391 | \n",
+ "
\n",
+ " \n",
+ " | 91 | \n",
+ " 0.032189 | \n",
+ " 0.001031 | \n",
+ " 0.101082 | \n",
+ " 0.008990 | \n",
+ " 0.010417 | \n",
+ " -0.035204 | \n",
+ " 0.112929 | \n",
+ " 0.046901 | \n",
+ " 0.082138 | \n",
+ " -0.010214 | \n",
+ " ... | \n",
+ " 0.073335 | \n",
+ " 0.083564 | \n",
+ " 0.011163 | \n",
+ " 0.016842 | \n",
+ " 0.026141 | \n",
+ " 0.022422 | \n",
+ " 0.116454 | \n",
+ " 0.019769 | \n",
+ " 0.171767 | \n",
+ " -0.005104 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
92 rows × 54 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Stock1 Stock10 Stock11 Stock14 Stock16 Stock18 Stock19 \n",
+ "0 0.042603 -0.076059 -0.149741 -0.031251 -0.053032 -0.113752 -0.071671 \\\n",
+ "1 -0.015034 -0.100305 -0.023279 0.002484 0.077088 0.010849 0.022383 \n",
+ "2 0.111545 0.097933 0.121501 0.064357 0.107439 0.017883 0.000892 \n",
+ "3 -0.040491 -0.034262 -0.032848 -0.030232 0.022388 0.085504 -0.007159 \n",
+ "4 -0.069359 -0.073188 0.004349 0.010792 -0.025548 -0.001887 -0.012534 \n",
+ ".. ... ... ... ... ... ... ... \n",
+ "87 0.057631 0.089651 -0.090908 -0.045544 0.033207 -0.003331 0.036885 \n",
+ "88 -0.013557 -0.027089 -0.050713 -0.052443 -0.132316 -0.013774 -0.071147 \n",
+ "89 -0.022060 -0.098539 -0.016556 0.005218 -0.008810 -0.125433 -0.028937 \n",
+ "90 0.036795 0.002527 0.059680 0.074563 0.135041 0.056864 0.038476 \n",
+ "91 0.032189 0.001031 0.101082 0.008990 0.010417 -0.035204 0.112929 \n",
+ "\n",
+ " Stock20 Stock21 Stock22 ... Stock78 Stock79 Stock80 Stock81 \n",
+ "0 0.005430 0.005715 0.001399 ... -0.028168 0.017445 -0.100000 0.018014 \\\n",
+ "1 0.095480 0.067745 0.082493 ... 0.082448 -0.106195 0.066669 0.000556 \n",
+ "2 0.032425 0.018012 0.031663 ... 0.036357 0.220049 0.098957 0.088889 \n",
+ "3 0.052763 0.017920 0.007674 ... 0.040579 0.004259 -0.052133 0.005099 \n",
+ "4 0.068973 -0.026794 -0.056697 ... -0.025069 -0.062221 0.004332 -0.023857 \n",
+ ".. ... ... ... ... ... ... ... ... \n",
+ "87 -0.017510 0.097012 -0.000908 ... 0.039548 0.009388 0.096569 0.086140 \n",
+ "88 -0.045192 -0.031881 -0.000167 ... -0.042451 -0.032799 0.069729 -0.018660 \n",
+ "89 0.069444 -0.055806 -0.002845 ... -0.001562 -0.055437 -0.062808 -0.019475 \n",
+ "90 0.109808 0.023922 0.023766 ... 0.096860 0.089980 0.142830 0.001359 \n",
+ "91 0.046901 0.082138 -0.010214 ... 0.073335 0.083564 0.011163 0.016842 \n",
+ "\n",
+ " Stock84 Stock85 Stock86 Stock87 Stock88 Stock9 \n",
+ "0 0.044749 0.016824 -0.111084 -0.035229 -0.033204 0.030927 \n",
+ "1 -0.010800 0.006326 -0.026405 -0.013759 0.095241 -0.010000 \n",
+ "2 0.088630 0.047296 0.153527 0.034416 0.041795 0.024809 \n",
+ "3 -0.016164 0.012845 -0.004702 0.019786 0.042046 0.030303 \n",
+ "4 -0.085645 -0.041085 -0.083320 0.095238 -0.124253 -0.010784 \n",
+ ".. ... ... ... ... ... ... \n",
+ "87 0.097051 0.036655 -0.059447 -0.005197 -0.111087 0.044074 \n",
+ "88 -0.054422 0.071153 -0.083055 0.092917 -0.039052 -0.031945 \n",
+ "89 0.034172 -0.077723 -0.002616 0.020783 0.038300 0.011196 \n",
+ "90 0.005916 0.064159 0.234903 0.084005 0.112443 0.027391 \n",
+ "91 0.026141 0.022422 0.116454 0.019769 0.171767 -0.005104 \n",
+ "\n",
+ "[92 rows x 54 columns]"
+ ]
+ },
+ "execution_count": 462,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Ignoring the month_end from training set\n",
+ "\n",
+ "# Get column names as a list but ignore the first column\n",
+ "header_list = df.columns[1:].tolist()\n",
+ "print(header_list)\n",
+ "\n",
+ "\n",
+ "def process_dataframe(dataframe):\n",
+ " # Create a new dataframe without the 'month_end' column\n",
+ " new_dataframe = dataframe.drop([\"month_end\"], axis=1)\n",
+ " return new_dataframe\n",
+ "\n",
+ "\n",
+ "clean_df = process_dataframe(df_returns_train)\n",
+ "clean_df"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 463,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def equalise_weights(df: pd.DataFrame):\n",
+ " \"\"\"\n",
+ " Function to generate the equal weights, i.e. 1/p for each active stock within a month\n",
+ "\n",
+ " Args:\n",
+ " df: A return data frame. First column is month end and remaining columns are stocks\n",
+ "\n",
+ " Returns:\n",
+ " A dataframe of the same dimension but with values 1/p on active funds within a month\n",
+ "\n",
+ " \"\"\"\n",
+ "\n",
+ " # create df to house weights\n",
+ " n_length = len(df)\n",
+ " df_returns = df\n",
+ " df_weights = df_returns[:n_length].copy()\n",
+ " df_weights.set_index(\"month_end\", inplace=True)\n",
+ "\n",
+ " # list of stock names\n",
+ " list_stocks = list(df_returns.columns)\n",
+ " list_stocks.remove(\"month_end\")\n",
+ "\n",
+ " # assign 1/p\n",
+ " df_weights[list_stocks] = 1 / len(list_stocks)\n",
+ "\n",
+ " return df_weights"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 464,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/50\n",
+ "2/2 [==============================] - 10s 2s/step - loss: 0.2312 - val_loss: 0.2173\n",
+ "Epoch 2/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.1978 - val_loss: 0.1785\n",
+ "Epoch 3/50\n",
+ "2/2 [==============================] - 0s 120ms/step - loss: 0.1697 - val_loss: 0.1472\n",
+ "Epoch 4/50\n",
+ "2/2 [==============================] - 0s 128ms/step - loss: 0.1430 - val_loss: 0.1206\n",
+ "Epoch 5/50\n",
+ "2/2 [==============================] - 0s 101ms/step - loss: 0.1329 - val_loss: 0.1012\n",
+ "Epoch 6/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.1153 - val_loss: 0.0879\n",
+ "Epoch 7/50\n",
+ "2/2 [==============================] - 0s 117ms/step - loss: 0.1047 - val_loss: 0.0779\n",
+ "Epoch 8/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.1038 - val_loss: 0.0689\n",
+ "Epoch 9/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0922 - val_loss: 0.0630\n",
+ "Epoch 10/50\n",
+ "2/2 [==============================] - 0s 103ms/step - loss: 0.0866 - val_loss: 0.0594\n",
+ "Epoch 11/50\n",
+ "2/2 [==============================] - 0s 105ms/step - loss: 0.0790 - val_loss: 0.0566\n",
+ "Epoch 12/50\n",
+ "2/2 [==============================] - 0s 120ms/step - loss: 0.0709 - val_loss: 0.0538\n",
+ "Epoch 13/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0773 - val_loss: 0.0523\n",
+ "Epoch 14/50\n",
+ "2/2 [==============================] - 0s 101ms/step - loss: 0.0755 - val_loss: 0.0515\n",
+ "Epoch 15/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0786 - val_loss: 0.0504\n",
+ "Epoch 16/50\n",
+ "2/2 [==============================] - 0s 132ms/step - loss: 0.0686 - val_loss: 0.0483\n",
+ "Epoch 17/50\n",
+ "2/2 [==============================] - 0s 125ms/step - loss: 0.0753 - val_loss: 0.0478\n",
+ "Epoch 18/50\n",
+ "2/2 [==============================] - 0s 103ms/step - loss: 0.0664 - val_loss: 0.0490\n",
+ "Epoch 19/50\n",
+ "2/2 [==============================] - 0s 102ms/step - loss: 0.0686 - val_loss: 0.0504\n",
+ "Epoch 20/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0690 - val_loss: 0.0493\n",
+ "Epoch 21/50\n",
+ "2/2 [==============================] - 0s 109ms/step - loss: 0.0679 - val_loss: 0.0480\n",
+ "Epoch 22/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0645 - val_loss: 0.0462\n",
+ "Epoch 23/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0641 - val_loss: 0.0454\n",
+ "Epoch 24/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0677 - val_loss: 0.0459\n",
+ "Epoch 25/50\n",
+ "2/2 [==============================] - 0s 102ms/step - loss: 0.0643 - val_loss: 0.0483\n",
+ "Epoch 26/50\n",
+ "2/2 [==============================] - 0s 137ms/step - loss: 0.0612 - val_loss: 0.0509\n",
+ "Epoch 27/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0626 - val_loss: 0.0511\n",
+ "Epoch 28/50\n",
+ "2/2 [==============================] - 0s 113ms/step - loss: 0.0680 - val_loss: 0.0477\n",
+ "Epoch 29/50\n",
+ "2/2 [==============================] - 0s 113ms/step - loss: 0.0628 - val_loss: 0.0451\n",
+ "Epoch 30/50\n",
+ "2/2 [==============================] - 0s 106ms/step - loss: 0.0618 - val_loss: 0.0445\n",
+ "Epoch 31/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0608 - val_loss: 0.0445\n",
+ "Epoch 32/50\n",
+ "2/2 [==============================] - 0s 120ms/step - loss: 0.0607 - val_loss: 0.0468\n",
+ "Epoch 33/50\n",
+ "2/2 [==============================] - 0s 109ms/step - loss: 0.0648 - val_loss: 0.0511\n",
+ "Epoch 34/50\n",
+ "2/2 [==============================] - 0s 122ms/step - loss: 0.0644 - val_loss: 0.0533\n",
+ "Epoch 35/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0626 - val_loss: 0.0511\n",
+ "Epoch 36/50\n",
+ "2/2 [==============================] - 0s 120ms/step - loss: 0.0589 - val_loss: 0.0471\n",
+ "Epoch 37/50\n",
+ "2/2 [==============================] - 0s 117ms/step - loss: 0.0568 - val_loss: 0.0455\n",
+ "Epoch 38/50\n",
+ "2/2 [==============================] - 0s 107ms/step - loss: 0.0582 - val_loss: 0.0449\n",
+ "Epoch 39/50\n",
+ "2/2 [==============================] - 0s 120ms/step - loss: 0.0613 - val_loss: 0.0446\n",
+ "Epoch 40/50\n",
+ "2/2 [==============================] - 0s 112ms/step - loss: 0.0585 - val_loss: 0.0444\n",
+ "Epoch 41/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0612 - val_loss: 0.0448\n",
+ "Epoch 42/50\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0546 - val_loss: 0.0460\n",
+ "Epoch 43/50\n",
+ "2/2 [==============================] - 0s 124ms/step - loss: 0.0583 - val_loss: 0.0485\n",
+ "Epoch 44/50\n",
+ "2/2 [==============================] - 0s 124ms/step - loss: 0.0594 - val_loss: 0.0508\n",
+ "Epoch 45/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0604 - val_loss: 0.0515\n",
+ "Epoch 46/50\n",
+ "2/2 [==============================] - 0s 124ms/step - loss: 0.0616 - val_loss: 0.0501\n",
+ "Epoch 47/50\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0624 - val_loss: 0.0481\n",
+ "Epoch 48/50\n",
+ "2/2 [==============================] - 0s 124ms/step - loss: 0.0595 - val_loss: 0.0465\n",
+ "Epoch 49/50\n",
+ "2/2 [==============================] - 0s 133ms/step - loss: 0.0608 - val_loss: 0.0457\n",
+ "Epoch 50/50\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0545 - val_loss: 0.0455\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 464,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Normalization\n",
+ "scaler = MinMaxScaler(feature_range=(0, 1))\n",
+ "scaled_data = scaler.fit_transform(clean_df.values)\n",
+ "\n",
+ "# Create a data structure with 60 time-steps and 1 output for each stock\n",
+ "lookback = 60\n",
+ "\n",
+ "X, y = [], []\n",
+ "for i in range(lookback, len(scaled_data)):\n",
+ " X.append(scaled_data[i - lookback : i])\n",
+ " y.append(scaled_data[i])\n",
+ "X, y = np.array(X), np.array(y)\n",
+ "\n",
+ "# Split the data into training and validation sets\n",
+ "X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)\n",
+ "\n",
+ "# Initialize the LSTM model\n",
+ "model = Sequential()\n",
+ "\n",
+ "model.add(\n",
+ " LSTM(\n",
+ " units=50,\n",
+ " return_sequences=True,\n",
+ " input_shape=(X_train.shape[1], X_train.shape[2]),\n",
+ " )\n",
+ ")\n",
+ "model.add(Dropout(0.2))\n",
+ "\n",
+ "model.add(LSTM(units=50, return_sequences=True))\n",
+ "model.add(Dropout(0.2))\n",
+ "\n",
+ "model.add(LSTM(units=50, return_sequences=True))\n",
+ "model.add(Dropout(0.2))\n",
+ "\n",
+ "model.add(LSTM(units=50))\n",
+ "model.add(Dropout(0.2))\n",
+ "\n",
+ "model.add(\n",
+ " Dense(units=clean_df.shape[1])\n",
+ ") # number of units in the output layer should be equal to the number of stocks\n",
+ "\n",
+ "# Compile and train the model\n",
+ "model.compile(optimizer=\"adam\", loss=\"mean_squared_error\")\n",
+ "model.fit(X_train, y_train, epochs=50, batch_size=20, validation_data=(X_val, y_val))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 465,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/50\n",
+ "3/3 [==============================] - 0s 98ms/step - loss: 0.0573 - val_loss: 0.0453\n",
+ "Epoch 2/50\n",
+ "3/3 [==============================] - 0s 87ms/step - loss: 0.0584 - val_loss: 0.0451\n",
+ "Epoch 3/50\n",
+ "3/3 [==============================] - 0s 85ms/step - loss: 0.0551 - val_loss: 0.0457\n",
+ "Epoch 4/50\n",
+ "3/3 [==============================] - 0s 96ms/step - loss: 0.0580 - val_loss: 0.0461\n",
+ "Epoch 5/50\n",
+ "3/3 [==============================] - 0s 81ms/step - loss: 0.0595 - val_loss: 0.0464\n",
+ "Epoch 6/50\n",
+ "3/3 [==============================] - 0s 78ms/step - loss: 0.0531 - val_loss: 0.0462\n",
+ "Epoch 7/50\n",
+ "3/3 [==============================] - 0s 87ms/step - loss: 0.0553 - val_loss: 0.0462\n",
+ "Epoch 8/50\n",
+ "3/3 [==============================] - 0s 83ms/step - loss: 0.0563 - val_loss: 0.0451\n",
+ "Epoch 9/50\n",
+ "3/3 [==============================] - 0s 91ms/step - loss: 0.0547 - val_loss: 0.0453\n",
+ "Epoch 10/50\n",
+ "3/3 [==============================] - 0s 78ms/step - loss: 0.0550 - val_loss: 0.0455\n",
+ "Epoch 11/50\n",
+ "3/3 [==============================] - 0s 84ms/step - loss: 0.0552 - val_loss: 0.0468\n",
+ "Epoch 12/50\n",
+ "3/3 [==============================] - 0s 80ms/step - loss: 0.0544 - val_loss: 0.0473\n",
+ "Epoch 13/50\n",
+ "3/3 [==============================] - 0s 85ms/step - loss: 0.0539 - val_loss: 0.0474\n",
+ "Epoch 14/50\n",
+ "3/3 [==============================] - 0s 92ms/step - loss: 0.0566 - val_loss: 0.0466\n",
+ "Epoch 15/50\n",
+ "3/3 [==============================] - 0s 86ms/step - loss: 0.0540 - val_loss: 0.0462\n",
+ "Epoch 16/50\n",
+ "3/3 [==============================] - 0s 81ms/step - loss: 0.0553 - val_loss: 0.0452\n",
+ "Epoch 17/50\n",
+ "3/3 [==============================] - 0s 84ms/step - loss: 0.0538 - val_loss: 0.0448\n",
+ "Epoch 18/50\n",
+ "3/3 [==============================] - 0s 94ms/step - loss: 0.0551 - val_loss: 0.0451\n",
+ "Epoch 19/50\n",
+ "3/3 [==============================] - 0s 117ms/step - loss: 0.0551 - val_loss: 0.0450\n",
+ "Epoch 20/50\n",
+ "3/3 [==============================] - 0s 102ms/step - loss: 0.0527 - val_loss: 0.0449\n",
+ "Epoch 21/50\n",
+ "3/3 [==============================] - 0s 100ms/step - loss: 0.0541 - val_loss: 0.0452\n",
+ "Epoch 22/50\n",
+ "3/3 [==============================] - 0s 101ms/step - loss: 0.0514 - val_loss: 0.0454\n",
+ "Epoch 23/50\n",
+ "3/3 [==============================] - 0s 113ms/step - loss: 0.0548 - val_loss: 0.0447\n",
+ "Epoch 24/50\n",
+ "3/3 [==============================] - 0s 89ms/step - loss: 0.0566 - val_loss: 0.0448\n",
+ "Epoch 25/50\n",
+ "3/3 [==============================] - 0s 119ms/step - loss: 0.0508 - val_loss: 0.0469\n",
+ "Epoch 26/50\n",
+ "3/3 [==============================] - 0s 114ms/step - loss: 0.0543 - val_loss: 0.0483\n",
+ "Epoch 27/50\n",
+ "3/3 [==============================] - 0s 82ms/step - loss: 0.0553 - val_loss: 0.0469\n",
+ "Epoch 28/50\n",
+ "3/3 [==============================] - 0s 93ms/step - loss: 0.0523 - val_loss: 0.0460\n",
+ "Epoch 29/50\n",
+ "3/3 [==============================] - 0s 92ms/step - loss: 0.0499 - val_loss: 0.0442\n",
+ "Epoch 30/50\n",
+ "3/3 [==============================] - 0s 83ms/step - loss: 0.0533 - val_loss: 0.0442\n",
+ "Epoch 31/50\n",
+ "3/3 [==============================] - 0s 85ms/step - loss: 0.0550 - val_loss: 0.0454\n",
+ "Epoch 32/50\n",
+ "3/3 [==============================] - 0s 88ms/step - loss: 0.0515 - val_loss: 0.0463\n",
+ "Epoch 33/50\n",
+ "3/3 [==============================] - 0s 94ms/step - loss: 0.0516 - val_loss: 0.0455\n",
+ "Epoch 34/50\n",
+ "3/3 [==============================] - 0s 87ms/step - loss: 0.0534 - val_loss: 0.0452\n",
+ "Epoch 35/50\n",
+ "3/3 [==============================] - 0s 90ms/step - loss: 0.0531 - val_loss: 0.0450\n",
+ "Epoch 36/50\n",
+ "3/3 [==============================] - 0s 92ms/step - loss: 0.0517 - val_loss: 0.0455\n",
+ "Epoch 37/50\n",
+ "3/3 [==============================] - 0s 90ms/step - loss: 0.0523 - val_loss: 0.0465\n",
+ "Epoch 38/50\n",
+ "3/3 [==============================] - 0s 104ms/step - loss: 0.0545 - val_loss: 0.0479\n",
+ "Epoch 39/50\n",
+ "3/3 [==============================] - 0s 88ms/step - loss: 0.0531 - val_loss: 0.0473\n",
+ "Epoch 40/50\n",
+ "3/3 [==============================] - 0s 88ms/step - loss: 0.0526 - val_loss: 0.0458\n",
+ "Epoch 41/50\n",
+ "3/3 [==============================] - 0s 101ms/step - loss: 0.0551 - val_loss: 0.0450\n",
+ "Epoch 42/50\n",
+ "3/3 [==============================] - 0s 99ms/step - loss: 0.0537 - val_loss: 0.0454\n",
+ "Epoch 43/50\n",
+ "3/3 [==============================] - 0s 95ms/step - loss: 0.0528 - val_loss: 0.0456\n",
+ "Epoch 44/50\n",
+ "3/3 [==============================] - 0s 101ms/step - loss: 0.0524 - val_loss: 0.0460\n",
+ "Epoch 45/50\n",
+ "3/3 [==============================] - 0s 90ms/step - loss: 0.0511 - val_loss: 0.0464\n",
+ "Epoch 46/50\n",
+ "3/3 [==============================] - 0s 87ms/step - loss: 0.0522 - val_loss: 0.0462\n",
+ "Epoch 47/50\n",
+ "3/3 [==============================] - 0s 81ms/step - loss: 0.0513 - val_loss: 0.0463\n",
+ "Epoch 48/50\n",
+ "3/3 [==============================] - 0s 94ms/step - loss: 0.0527 - val_loss: 0.0470\n",
+ "Epoch 49/50\n",
+ "3/3 [==============================] - 0s 84ms/step - loss: 0.0554 - val_loss: 0.0462\n",
+ "Epoch 50/50\n",
+ "3/3 [==============================] - 0s 84ms/step - loss: 0.0497 - val_loss: 0.0456\n"
+ ]
+ }
+ ],
+ "source": [
+ "history = model.fit(\n",
+ " X_train, y_train, epochs=50, batch_size=10, validation_data=(X_val, y_val)\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 466,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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kZiYSGRkJAkJCVr/JSIiIiLiQ73eXMzKHUd48/ZWdG1Wxelw8pwbON5kWURERERE5HxUKh2YFQ+VfImIiIiISEDxlJs/GGC9vpR8iYiIiIhIQKkYoCNfjhfcEBEREREROR/t61bA5apPi+oXOB3KeVHyJSIiIiIiAaVtrfK0rVXe6TDOm6YdioiIiIiI+ICSLxERERERER9Q8iUiIiIiIuIDSr5ERERERER8QMmXiIiIiIiIDyj5EhERERER8QElXyIiIiIiIj6g5EtERERERMQHlHyJiIiIiIj4gJIvERERERERH1DyJSIiIiIi4gNKvkRERERERHxAyZeIiIiIiIgPKPkSERERERHxASVfIiIiIiIiPqDkS0RERERExAeUfImIiIiIiPiAki8REREREREfUPIlIiIiIiLiA0q+REREREREfEDJl4iIiIiIiA8o+RIREREREfEBJV8iIiIiIiI+oORLRERERETEB5R8iYiIiIiI+ICSLxERERERER9Q8iUiIiIiIuIDSr5ERERERER8QMmXiIiIiIiIDyj5EhERERER8QElXyIiIiIiIj6g5EtERERERMQHlHyJiIgUhvQ02LUcMjKcjkRERPyEki8REZHCsGAU/K8TLHnd6UhERMRPKPkSERHxtvQ0+Pkj2141HtxuZ+MRERG/oORLRETE27YthGPxtn1oK+z52dl4RETELyj5EhER8ba1n2ZuuM74XUREijMlXyIiIt6Ukgwbvrbtyx62n+s/s6mIIiJSrCn5EhER8aZNMyA1GcrVgg6PQYnykLzfpiKKiEix5njyNXbsWGrVqkVERASxsbEsW7bsnPtPmTKFhg0bEhERQbNmzZg+ffpZ9x04cCAul4vRo0fnuH/z5s1cf/31VKxYkbJly3LppZfy3XffeePliIhIcbd2sv1s3htCwqDJDfb7uinOxSQiIn7B0eRr8uTJDB06lBEjRrBq1SpatGhB586d2b9/f677L168mD59+nDXXXfx888/07NnT3r27Mn69ev/tO+0adNYunQpMTExf3qse/fupKWlMX/+fFauXEmLFi3o3r07+/bt8/prFBGRYuTYAdg6z7ab3WI/m2f+3PA1pBx3Ji4REfELjiZfr7zyCgMGDKB///40btyYcePGUbJkSd57771c9x8zZgxdunRh2LBhNGrUiGeeeYZWrVrx+us5e6js3r2bBx54gAkTJhAaGprjsYMHD7Jlyxb++c9/0rx5c+rVq8dzzz3H8ePHc03iRERE8uyXz8GdDjGtoGJdu696LFxQA1KOwaazz9YQEZGiz7HkKyUlhZUrV9KpU6fsYIKC6NSpE0uWLMn1b5YsWZJjf4DOnTvn2D8jI4O+ffsybNgwmjRp8qdjVKhQgQYNGvDhhx+SnJxMWloab731FpUrV6Z169ZnjffUqVMkJibmuImIiOTgqWrYvHf2fS5X9iiYph6KiBRrjiVfBw8eJD09naioqBz3R0VFnXX63759+/5y/+eff56QkBAefPDBXI/hcrmYO3cuP//8M2XKlCEiIoJXXnmFmTNnUq5cubPGO2rUKCIjI7Nu1atXz+tLFRGR4uDQb7B7BbiCoemNOR/zTD3cOheSD/k+NhER8QuOF9zwppUrVzJmzBg++OADXC5Xrvu43W4GDRpE5cqVWbRoEcuWLaNnz5706NGDvXv3nvXYw4cPJyEhIeu2a9euwnoZIiISiDyjXnWugtKVcz5WqQFEN4eMNPh1mu9jE8mL9DRIS3E6CpEizbHkq2LFigQHBxMfH5/j/vj4eKKjo3P9m+jo6HPuv2jRIvbv30+NGjUICQkhJCSEHTt28PDDD1OrVi0A5s+fzzfffMOkSZO45JJLaNWqFW+88QYlSpRg/PjxZ403PDycsmXL5riJiIgA4HafVuXwltz38UxFVMNl8Udpp+CNWHitNRzZ4XQ0IkWWY8lXWFgYrVu3Zt68eVn3ZWRkMG/ePOLi4nL9m7i4uBz7A8yZMydr/759+7J27VpWr16ddYuJiWHYsGHMmjULgOPHrdJUUFDOlx4UFERGRobXXp+IiBQju1fCkW0QWgoadst9n6a9ABfs+gmObPdldCJ/beO3cGgrJOyECTfB8cNORyRSJDk67XDo0KG88847jB8/ng0bNnDfffeRnJxM//79AbjjjjsYPnx41v5Dhgxh5syZvPzyy2zcuJGRI0eyYsUKBg8eDFgxjaZNm+a4hYaGEh0dTYMGDQBL4MqVK0e/fv1Ys2YNmzdvZtiwYWzbto1u3c7ygSkiInIunlGvRt0hrFTu+5StAhdebtsqvCH+ZtWH2dsHN8MnfSD1hHPxiBRRjiZfvXv35qWXXuKpp56iZcuWrF69mpkzZ2YV1di5c2eOdVjt27dn4sSJvP3227Ro0YKpU6fyxRdf0LRp0zw/Z8WKFZk5cybHjh3jqquuok2bNvzwww98+eWXtGjRwuuvUUREirj0VFj/mW03O8uUQw/PlMS1U2yqoog/OLIdfv/OtvtMgvBI2LUUPh8AGemOhiZS1Ljcbr3750diYiKRkZEkJCRo/ZeISHG2eRZMvAVKVYKhGyE45Oz7nkyAl+pD2km493uooot+4gfmPwvfvwi1r4A7voTtP8BHN0B6CrS7B7q+YC0TROSs8pobFKlqhyIiIj7nKaDR9KZzJ14AEZFQv0vOvxNxUnoa/DzBtlv1s5+1LoUbxtn2srfhxzHOxCZSBCn5EhERya9TSVaoAM5e5fBMnv3WTdWULnHe1rmQtAdKlM9ZLKZpL7jm37Y9d4RNlRWRAlPyJSIikl8bvoG0E1ChLsRclLe/qXs1RFwAx/bB9kWFGp7IX/IU2mh5G4SE53ys/WC4eJBtf3Ef/L7Ap6GJFEVKvkRERPIrq7dX77yviQkJgyY9M/9eownioKR9sHmmbV/UN/d9rnkWmtwAGakwuS/sW++7+ESKICVfIiIi+ZG0D7YttO1mN5/f33oaLv/6pcp5i3NWTwB3OlSPhcoNc98nKAh6joOal8CpROsBdnSXb+MUKUKUfImIiOTH+s/AnWFfXMtfeH5/W/1iiKwOKUnZIw8ivpSRAas+sm1PoY2zCY2AWydApUaQtBc+7gUnjhR+jCJFkJIvERGR/PBMOTzfUS+w0YRmN2UeR1MPxQHbF8GRbRBeNnsa7LmUKAd/mwplYuDgJvjkNkg9WehhihQ1Sr5EpHCdOAK/L4TFr8Fnd8PrbeGZyrD8f05HJpJ/BzbB3jUQFAJNbszfMTwNmbfMhuOHvRebSF54Cm00uwnCSuXtbyKrWQIWXhZ2LoZp99oImojk2V80JBEROQ9J8bBvLexdbV9M966Fozty33fW43BhB6hY16chiniFp0dX3auhVIX8HSOqMUQ1g/h1tvarTX/vxSdyLscPw4avbLvVHef3t1FNbAriRzfCr1/ArCrQZZSaMIvkkZIvEcmfU0lWdtiTZO1dY6Wzc3NBTajSHKq0gCotbRRs20L4ajDcOd2mYIkEiowMWJeZfOW1t9fZNL8Z5qyzZE7Jl/jK2smQngLRzew9+XxdeLk1Yf7sLvjpTYisCu0f8HqYIkWRki8ROX+HfoMPe0LCzjMecEHF+plJVmayFd3M1gqcrmJ9eCMOdi6B5e9C7D2+ilyk4Hb9BEd3QlgZaNC1YMdqehPMGWFTuI7uhAtqeCdGkbNxu7OnHLbql/8Rq2Y3QeIemPMkzH4CylTJXscoImel5EtEzs/+jfDh9TbKVSYG6nbMTLZa2HSUvKwdKFcTrn4apj8Cc0dC/WugXK3CjlzEOzyjXo2vg9ASBTtWZFWodakVP1g3FS4bWvD4RM7ljxWw/1cIKZG/YjGna/8AJO6Gn8ZZE+YKdfLebFykmNJcHxHJu71r4YNrLfGq3ATuXQjXvw7tBkD1dnlftA3Q5i7rG5OaDF89YFdjRfxdWgqs/9y2Czrl0MPzBXjtp/p3IIVv1Xj72aQnlLigYMdyuaDzf6B+F5vG+NPbBY1OpMhT8iUiefPHChjfHY4fsiubd34DpSvn/3hBQXDda3b1ddv32V8IRPzZ1jlw8iiUjoZal3nnmI2vh+AwOLAB4td755giuTmVlH3x4HwLbZxNUDBc+g/b3vAVpBz3znFFiiglXyLy17b/aFMNTyZYc9g7voSS5Qt+3Ap14KonbHvWE5DwR8GPKVKYsnp73WRfOr2hxAVQv3Pm8T/1zjFFcrP+M5ttUKEe1Ijz3nGrx9p6xZRjsGm6944rUgQp+RKRc9s6Dz7uZR+qF14OfT+HiEjvHf/i+6BaW0hJgq8f0rQr8V8nE2DTTNtu3tu7x/b0/Fr/mfomSeHJKrRxh3dLw7tc2f8m1qlpuMi5KPkSkbPbOB0+uRXSTkC9a+C2T89vXVdeBAXD9WNt2tXWObBmknePL+Itv34F6aegUiOr4ulN9a6B8EgrXrDjR+8eWwRg33rYvRKCQqFFH+8f33MBYetcSD7o/eOLFBFKvkQkd+s/g0/72iLqRtdB7wkFr+x2NpUawBX/tO2Zj0HSWfqFiTjJM+Ww+c3ebygbGgFNrrftdZp6KIXAM+rV8FooXcn7x69U39YDZ6TBL9O8f3yRIkLJl4j82eqJ8Nnd9iHavDfc9D6EhBXuc7YfYs0+TybAN0M1/VD8S8Ju2P6DbRe0PPfZeEYOfvkSUk8WznNI8ZR6AtZmzirwVqGN3HjOYc+FCik+MjJgzWQbYZVzUvIlIjktf9f6tbgzrAFnz3EQ7IOWgMEhNv0wKBQ2fQu/fF74zymSV+unAm5rj1BYjZBrXgJlq8KpBNgyu3CeQ4qnDV/bha3I6lD7ysJ7nqa9wBUEfyyHQ78V3vOI//n+RZh2D3x4HRw/7HQ0fk3Jl4hkW/wafPuwbcfeBz3GWEl4X4luCpc/YtvTh2ndgPgPTxVCb/X2yk1QkH15BU09FO/yTDm8qK/3qnTmpkxUdnK3bmrhPY/4ly1zYMEo2z5+COY85Ww8fk7Jl4jYFL+FL8DszLLvlz0MXUZ5f11LXlw61Bo4Hz9kCZiI0/att/5bwWHWk6sweSrGbZ4FJ44W7nNJ8XDoN9i+yEakLrq98J/Pcw6vnazp48XB4W3w2V2AOzvx/vkj2LHY0bD8mZIvkeLO7Ya5I+G7f9vvVz0BHZ9yJvECW1vWcyy4gm3q4YavnYlDxMMzClXvGihRrnCfK7opVG5shW5+/bJwn0uKB8+oV91OEFmt8J+vYTcILQmHf4Pdqwr/+cQ5Kcdhcl+b0lq1Ddw22ZYrgLWOSUtxNDx/peRLpDhzu2HmP+HH0fZ751FwuR+MNsVcBJcMse1vhmr+uDjH7Yb1mesPvd3b62w8BT3WfKKRAymY9FQroASFW2jjdOGlLQEDFd4oytxu+OYfEL8OSlWCWz6EkHDoNBJKVoSDm2Dxq05H6ZeUfIkUZ1vmwE/jABd0/y/E3e90RNk6PAYVG0Dyfpj1uNPRSHF1aCsk7ILgcKh3tW+es3lvm+K4c4lNPxTJr82z7D20VGWo38V3z+u5ULH+M0sApehZ/q5V0HQFW0XkyKp2f8ny0Pk/tv39i3D4d+di9FNKvkSKs1Xj7WfsvdDm787GcqbQCKt+iMtGADar+ps4YPsi+1m9XeH1uTtTZFW4OPNCyMx/Qtop3zyvFD2e9/iWt0FwqO+et/aVNvpx/CD8vsB3zyu+sfMne28CuPppuPCynI83vwUu7ABpJ62Il0bwc1DyJVJcJcXDphm23bq/s7GcTfW2EDfItr8eYvPKRXxpW2byVetS3z7v5Y9A6Wg4sg2WjPXtc0vRkPAHbJ1r276acugRHALNbrJtTT0sWpLi4dM7rA9okxsgbvCf93FlzqYJDoff5tsIqGRR8iVSXK2ZCO50qB4LlRs6Hc3ZXfkvKF8bkvbA7CedjkaKE7c7u7FyrcvOva+3hZeBq//Ptr9/CRL3+vb5JfD9PMH6Nda6DCrU8f3zexoub/gGTiX5/vnF+9JTYcqdcGwfVGoI171+9uJcFepY5WSAmcNVvfU0Sr5EiiO3O7sClq+viJ6vsJL2Bg82hea375yNR4qPg5ttvUxIBFRr4/vnb34LVGsHqckwd4Tvn18CV0a6lfsG597jq7aC8nUg7QRs/NaZGMS75jwFOxdDWBno/bEVVzmXSx+CCvXsfXTe0z4JMRAo+RIpjnb8aItgw8pA455OR/PXal0CbQfY9ucDYNv3zsYjxYPnPKvezqp4+ZrLBV2fB1w2dWvnT76PQQLT7wusUExEJDTq4UwMLlfOnl8S2NZNhaVv2PYN46Bivb/+m5Bwm34IsOJ92LWs8OILIEq+RIojz6hXs15/feXKX3QaCVFNIfkAfHg9LHjeru6KFJasKYeXOxdD1VbQqq9tz3hU57zkjafQRvNbfVcoJjfNM9sm/L7A1gpJYIr/Bb56wLYvHQqNuuf9by+8DFrcBrit95eqXyr5Eil2ThzJbt7q71MOTxdeGu6aDS3/ZusYFvwHPuqpD3QpHDnWe/m42MaZrnoKwiNh72r4+WNnYxH/d+wAbJxu206/x5evDdXa2nu2ii4EphNHYfLfIPW4VbG86onzP8Y1z0KJ8rD/l+zRs2JMyZdIcbNuqpV/jWoKMa2cjub8hJWCnmPhhrcgtKRNCxt3qUoZi/cd2GhlskNKQNXWzsZSuhJckVnWed7TWrgu57bqA8hItfM2uqnT0WjqYSDLyIBpA22ZQmR16PU/CAo+/+OUqgDXPGPbC56DIzu8G2eAUfIlUpy43bAyczpKqzvOXqXI37W4Fe5ZCJUb20LeD3vCd//RlCzxHk+J+RqxEBLmbCwA7QZY0/Hjh2Dh805HI/4qJRmWZI4sxN7nbCweTW6AoBAbuT2wyelo5Hwsehk2z7CS8b0/siQqv1reDjUvsRG06cOKde8vJV8ixcmenyF+nb2RNrvZ6WgKplJ9uHte5rQat30h/fB6SNrndGRSFHiaK/u6xPzZBIdC1+ds+6e3YP9GZ+MR/7TifThx2Kb7NbnB6WhMqYpQt5Ntr/3U2Vgk77bMhe/+bdvdXoaYiwp2PE/vr6BQ2DILNnxV8BgDlJIvkeLEU2ij8XVQsryzsXhDWEm47jW48V0IK21fmMddak0dRfIrI8O5/l7nUucqaNjd+vPNfKxYXzmWXKSehMWv2val/7BGx/6ieWbPr3Wf6rw9H2s/hZcbwcTe1jA7I8M3z3tkO3x2F+CG1ndmF/0pqEoNrPw8wIzH4GSid44bYJR8SWA4vA1+etu+EKWnOR1NYEpJtvVe4PwibG9rfjPcsyC7GuJHN8K8Z3SuSP4c2GCjB6ElrdqgP7nmWRu5/n2BeidJTqs/hmPxULaaVTn0J/W72gWyozthl1om/KXUk/DNP6y1StIe2DwTPu4FY9vC0nGFm7SknoDJfeHkUVs32PUF7x7/soeh3IWQtBfmP+vdYwcIJV/i3xL+gK+HwOttYMYw+KAbvFQPvrjfvnikHHc6wsDxyxeQkmRvejUdrt5WGCrWg7vnQuv+gBsWvQTje0DiHqcjk0CTtd7rYpvu50/KXwjtM0s+zxpuX5SKo/Q0jaCcLj0Vfhhj25cM8Y91iqcLKwmNrrNtFd44t8Pb4L1rYMV7gMtGMWPvg/CycGirjXq/0gi+fdh7a+hOHIG1U2DqXfByA9i3FkpWhFs+9H6Pw9AS0P0V2172Nuxe5d3jBwAlX+KfkvbZgsxXL4KVH0BGml2BKVHOrkivngCTboMXasOk22H1RDh+2Omo/ZtnymGrvhBURP/ph5aAHqOtIlNYGdi52KYhbpnrdGQSSPxtvdeZLhsKZWJsFGHx605H43t7fobna1oVNiVgZu2nkLATSlX23hQxb/NMPVz/OaSlOBuLv9o4Hd7qAHvXWGn2v021Hpddn4Ohv8K1L1nhnZRjsPxdGNvO1jpv/Pb8C04d3AKLX4P3u8ELdeDzu2H9VDiZAKWjLPGKrFYoL5M6V2WuO3fDNw8Vu1kqLrdb71z5kZiYSGRkJAkJCZQtW9bpcIqO5IPww3/tTSXtpN1X81K46l9Qs739A925xN5oNn5rHzYeriCrpNOwGzS4FsrVdOY1+KMDm+xN2hUM//gFylZxOqLCd+g3mNIP9q2z3y/9h/VLKqqJp3hHRga8WNuuBN89D6q1cTqi3K2bamsyQkvC4OWF9yXJ32RkwLsdYU/m1fJe/4NmNzkbk9My0uH1tnD4N7j6GbjkQacjyl1GOrzSGI7tg1sn2me1mPQ0mP9/8GPm6GW1tnDzB7n/u3a7YdtCW4qxeYb1UAO4oAa0vRsu6pv7mu70VPv+tHkWbJph58vpKjWCBl1simi1NvkrKX8+ju23WU0nE6DzKIi7v3Cfzwfymhso+conJV9edvwwLHnd5jKnJtt91dpZ0nVhh9xLorvd9sXak4jFr8v5eHQzW5zesJutBQrUsureMOtf9t+3wbXQ5xOno/Gd1JMw+1+WzINVbGp7t7MxiX/buxbeuszWpzy23f+mHXq43fB+V/sy1bQX3PSe0xH5xsrx8PVpyUWJcnD/T1AmyrmYnLb+M5j6d/tv8dB6a0jvrzyfRY2vt5EVgcS99v9v52L7/eL7odPTeZs6emQHrPifzWw5ccTuC4mwUaV291jytnWeJWlb51qi4xEUag3kG3SF+p2hXC2vv7S/tOJ9G/kKKw2DlkFkVd/H4EVKvgqZki8vOZlo3c6XjIVTmQtIq7SAK5+AelefX8J0ZAdsmm6J2I4fs68Ggb0ZlapsJW9LZ/4sVTlzu1L2rXRlG+ovSqMjaSnwSkPrD9Rnkr3RFjc//BfmjoQyVeDBn216okhulrxha6nqXm1TfvzZ3rXwdgd7r7tzOtS6xOmICtfxw/Baa5t6fvX/2ejfvrXQoBvcOqF4XmDLyIBxl8D+X+HKf0GHR52O6Nz2roG3LreiMcO2QESk0xE56/eFNoKdfMCmyl//OjTpef7HST1h/x6WvZU92wNsRtDp34VKVoB6nS3ZqnMVRDj8/TUjA97vYkVYGna3f8cBLK+5gR/VIZViJSXZetUsfjX7ak3lxvbh0bBb/j5Ey9WEi++zW/Ih6yOx8Vu76pN2wqYonj5N8WxcQbbQtHRlqFAHuo8O7LLsm6Zb4lU62r5QFkcX3w/L3oXEP2wRc9wgpyMSf5W13isAitJUaQ6t+sHK961s870LC3+qkJO++48lXpUa2b/pup1sfcymb23NU4veTkfoe5tnWOIVVsYacfu76OZQqSEc2Ai/fuW/69MKW0aGNTBe8B9LjqKaws3joWLd/B0vtIT9t7zob7BzqRWy2PCVrZev3NiSLV9NJzwfQUHW++uty2HjN/bf5LKHnY6q0Cn5Et9KPWFffn/4r13pAahQD64cDo1v8N6IU6kK0PI2u6WdspKmxw7Ycybvt5/HPNsHbe5x8gH7YHdnZN6/H+LXW9neLv/xTlxO8BTauOh2/+r74ksh4XZF+OsHYdEr9oXVn6fmiDMy0m3UHOBCPy22caarnoRfPrdp1ys/gLZ3OR1R4di71qZXAVz7gk0HjWoCVzxm5apnPAoXXl481rN6uN3w/Uu23W6ATTv0dy6XFd6Y939W9bA4Jl/HD8Pn98DWOfZ7y7/BtS9aRciCcrmgZpzdkg/Z2nl/n8oX1cSmWc7+l50XISWKxPqvc3F8btXYsWOpVasWERERxMbGsmzZsnPuP2XKFBo2bEhERATNmjVj+vTpZ9134MCBuFwuRo8e/afHvv32W2JjYylRogTlypWjZ8+eBXwl8pe2LYI3LoZZj1uiU64W9BwH9y+1NQuFNdUvJNyeq3pbaHitNQy8fJh9gN/8Adz5DQxeBo9tgycPwsOb4N5Ftj4IbL1Qwh+FE1thO7ozu+HwRX9zNhantbzNyuwfP2hTM0TOtG+drYkIKwPRLZyOJm9KVbAZAwDznymaVV/dbpj+iF0Ya3KjJVkel/wDqrS0nkTfPFS8qh/+Nt8Kj4SUCKzR/GY328/tPwTuZ2t+/bECxl1miVdIBFz3OvQc653E60ylKvh/4uXRfjB0+KdtzxqeWWa/6HI0+Zo8eTJDhw5lxIgRrFq1ihYtWtC5c2f279+f6/6LFy+mT58+3HXXXfz888/07NmTnj17sn79+j/tO23aNJYuXUpMTMyfHvvss8/o27cv/fv3Z82aNfz444/cdtttXn99kunUMfj2ERjf3bqml4mBHq/C4BXQso9/jcYEh0KZaJvO0+YuKzWdfgoWPu90ZPnz8wTAbV9Wytd2OhpnBYfClY/b9o9j4MRRR8MRP7T9B/tZs71/vS/9lTZ32VS8E0dgwSino/G+tZNtTUhoKWsyfbrgEOj5JgSHWSPaNZOcidEJizIvELbpb+uYA8UFNaBGe8Bt65SKA7fbllq818Wmv5evbX0pi+PI39lc8U/rUQfWYHr1RGfjKUSOJl+vvPIKAwYMoH///jRu3Jhx48ZRsmRJ3nsv94x3zJgxdOnShWHDhtGoUSOeeeYZWrVqxeuv5+xzsnv3bh544AEmTJhAaGjOSlVpaWkMGTKEF198kYEDB1K/fn0aN27MLbfccs5YT506RWJiYo6b5MG27+HN9rD8Hfu99Z0w6Cdo3c9/q4h5uFw2pQcsiTm41dl4zldGOvz8sW236udsLP6iaS9bb3AywQq9iJzOs94rUKYcegSHQNfMC0TL34X4X5yNx5tOJsLszPfhDsNyv5If1di+uIGtfSsOjdW3/2hTZIPDsptuBxJPz691U5yNwxdOJcHU/jY1NiPVmk3fs8AqMks2l8umH7a7137/cpBV8iyCHEu+UlJSWLlyJZ06dcoOJiiITp06sWTJklz/ZsmSJTn2B+jcuXOO/TMyMujbty/Dhg2jSZMmfzrGqlWr2L17N0FBQVx00UVUqVKFrl275jp6drpRo0YRGRmZdatevfr5vNzi59Qx674+vgcc3QGR1aHvF9BjjPPVdc5HjVio3wXc6fDdv52O5vz89p1dYYu4wKoIiS009ox+LXnD5sSLQOZ6r8xSz4FQbONMtTvYlzp3hiUgRWX63YLnbP1thbpw8Tmm1rUfAjGt4FQCfD2k6Lz+s1mUudar5e1Q9s8zfPxek56WOMavh33n/v4V0PZvgLevhF+mQVCI9bO65UNVeTwblwu6PAet7rD3ss8GWOG0Isax5OvgwYOkp6cTFZWzN0dUVBT79u3L9W/27dv3l/s///zzhISE8OCDuTcZ/P333wEYOXIkTzzxBN988w3lypXjiiuu4PDhs8+VHz58OAkJCVm3Xbt25el1Fkvbvoc347J7K7X5O9y/BOpc6Wxc+XXVE/bzl89t0XegWDXefra4FUIjnI3FnzTsYRW3UpJg8RinoxF/sXeNtbsIj7TzIxBd86ytI9m+KLtwSCDbvwF+GmfbXV84d9+j06cfbpkNqwO7ZPU57V5p671cwXDpQ05Hkz8lykG9a2x73afOxlJY1kyGd66CQ1tsucWd062QRHFsiXA+goKsynTz3nbhe8qdsGWu01F5leMFN7xp5cqVjBkzhg8++ADXWU7ujAzrd/Cvf/2LXr160bp1a95//31cLhdTppx9+Ds8PJyyZcvmuMkZTh2Db4ZmjnbthMgacMeXVkY0vIzT0eVfdDNoepNtz3/23Pv6i2MHrMQ82BUkyRYUlJ1Q//Q2JOV+sUeKGc+Uw5rt/asU8/koV9Om1gJsmuFsLAXldsP0Yfblq2F3qNvxr/+mcsPs4iMzh0PC7sKN0SnfZ671an6LM41xvaV5ZmuAtVOs9HpRkXbK1ixNuwdSj0PtK+De720mjeRNUDBc/wY07gnpKTD5duuJVkQ4lnxVrFiR4OBg4uPjc9wfHx9PdHR0rn8THR19zv0XLVrE/v37qVGjBiEhIYSEhLBjxw4efvhhatWqBUCVKlaGtnHjxlnHCA8Pp3bt2uzcmYceUJK73xfaaJenFHCbu+D+xfamUxRc+bhdZdwyy3po+Ls1n1h/j6ptrIyr5FTvGqjW1vq/LXrF6WjEH3iKbQTaeq8zeUYTNs9yNo6C+mWaJcQhEdD5PFp9tH/A3vdOJcJXDxS96Yfxv1hfM1xw6VCnoymYetfYSHPSHtjxg9PReMeRHfBe5+xqfZc/Cn/7HEpXcjauQBQcAje+Y/3J0k7CJ30C4/tXHjiWfIWFhdG6dWvmzZuXdV9GRgbz5s0jLi4u17+Ji4vLsT/AnDlzsvbv27cva9euZfXq1Vm3mJgYhg0bxqxZ9kHUunVrwsPD2bRpU9YxUlNT2b59OzVr1vT2yyz6TiXZFZ4PrztttOsr6P5KYI92nalCnexS7XOf9u8PdLc7u7eXRr1y53Jlj36tfB+OahpxsZaeBjsy1w4H4nqv09W50taWHNoCh393Opr8OXUMZmWOYF061Eb08iooOHP6YTj8Ni/7vbCo8FQ4bHw9VKrvbCwFFRoBTa637aJQpXLzbGsWvOdnm1Z5+1S46l+BO5LuD0LCrCVQ7SshNRkm3Ay7VzkdVYE5Ou1w6NChvPPOO4wfP54NGzZw3333kZycTP/+/QG44447GD58eNb+Q4YMYebMmbz88sts3LiRkSNHsmLFCgYPHgxAhQoVaNq0aY5baGgo0dHRNGjQAICyZcsycOBARowYwezZs9m0aRP33XcfADfffLOP/wsEuN8XwBvts6/wtL07c7Srg6NhFZoOj9kH+s7F9qHur3YutS9eoaWg6Y1OR+O/LuyQ2UogBb5/0eloxEl719gawIgLICrAK5BFREKNzAuYm2c7G0t+LXrJRkPK1couPX0+KtXPvrgy619F5+LKwa2w/nPbvvwRZ2PxlhaZbX7WTArcKp0Z6TDvGZh4s/Wbi2ll0wzrXe10ZEVDaATcOhFqXmoj2h/dYD0ZA5ijyVfv3r156aWXeOqpp2jZsiWrV69m5syZWUU1du7cyd69e7P2b9++PRMnTuTtt9+mRYsWTJ06lS+++IKmTZue1/O++OKL3HrrrfTt25e2bduyY8cO5s+fT7lyAdAd3h+kpWSOdl0PCTutZ0e/r60pcVEa7TpTZFVoN8C25/2f/85R91zpbXpj0f7/UVCnj379/DEc+s3ZeMQ527+3nzUvKbxm775Uv7P93BKAUw8PboXFme1jujyX/2JBcYOgWjtLqovK9MMf/gu4bRpWUSlTXjMOGvWwtX3f/MN/P1fP5tgBSwY81SfbDoC/z7TvReI9YSXhtkn2b/rkUfiwJ+zf6HRU+eZyu4vCO5LvJSYmEhkZSUJCQvErvvHtI9l9u9oOgE4jIby0oyH5TPJBGNMCUo7BzeOtXK4/OXEUXm5oa5numgvV2zodkf/7+CbYOgea3wo3vuV0NOKEj3vB1rn2Zf/i+5yOpuAObIaxba3y36PbAuf92e22/xe/zbP1QLd9WrDKcAe3wrhLbL1I99HWjDhQHd0Jr15ka3nvngfV2jgdkfck/AGvt7NpZT1etT6ggWDnUqvEl7QXQkta7M01g6pQnThqy1z2roHS0dB/ui0L8RN5zQ2KwCU+8ak1k7ITr1s+gm4vBc4HuzeUqghxNs2V7/5ta0X8yfqplnhValS0PpwL01WZa0vWTg7oK2mST+mpp633CvBiGx4V69mUvfQU2BZAFcI2fmuJV3CYJcIFLcldsS50fMq2Zz9hxRAC1Y9jLPGqfUXRe2+PrJbdf3HuCLvI6c/cblgyFj7oZolXxfow4DslXr5Q4gLrGVu5MRzbB+Mz6w0EGCVfknd711rzSrD1T42vczYep8QNssW0BzfDWj9bJHx6oQ31EsmbmIsym1C7YcEop6MRX9uz2q64lyhvH+hFgcsF9TKnHgZK1cPUE1YeHqD9g967mh07EKpfbLMVvhoceNPawNphrPrIti8rImu9zhQ70NZbnjgCc55yOpqzO5kIn94Bsx63ZLjJjTBgvrU5EN8oWd7aGFWoB4l/WHujxD1OR3VelHxJ3pw4Ap/2tekbda+GDv90OiLnRJTNLvG74Dnr6eEP9qy2ofjgsOz+KZI3Vz4OuODXLwKrkbYUnGe9V60ist7Lo35myfktcwJjvdMPo20NcdlqcJkXS6gHBUPPNyCkBGz7Hla+571j+8ri1yD9lCWRgV6N82yCQ6xKMliD7O1+1iQ8PRV+ngDjLoUNX0FQKHR9EW56T2urnVC6MvT7ykb4j2y36Z+B8D6XqQh90kihyciAz++xE/yCmnDj20XrS0p+tBsAZapAwi5Y+YHT0ZifM6+MNuwOpSo4G0ugiWqS3Zz2u/PoKSSBz9Pfq6hMOfSoeamtQ0na4/+VwQ5vyywmAXT+N4SV8u7xK9SBTiNse/ZT9lkWKJIPndYz6pGiPaOhejtofadtfzvUins5Le0ULP8fvNoKvrwfju6wCwT9Z0DsPUX7/4e/Kxtjxd5iLoJurwTU/4ti/g1a8mTh87BltjW77P2RDfkWd6EloMOjtv39i9aXxkkpx2HtFNtWb6/8uWI4uIJg8wz4Y4XT0YgvpKVkN+0saslXaER2k3t/r3o463Eb2al9hfWvKgzt7oUa7W2K6Rf3w8mEwnkeb1v6BqQehyotoG4np6MpfB1HQMmKcGAjLHnduThSjsOSN6zA1rdDbVS2VCW4+v9g0FIVs/IXF9Sw9XbR51f13GlKvuTcNs+Chc/ZdvfR9gEg5qK+NuSdfAB+GudcHEn7YMF/4FSCvRFdWET7rBW2inWze87Mf9bZWMQ39qyyL7YlK0ClIrhmo17m1EN/7ve1eTZsmm6Nobu+UHhXr4OCoOdYGw3c8SO83hbWfurfU5VOHIVlb9v25cMC6sp+vpUsD9dkvv8ufMH3RVJOJtoo7OhmMGu4FdQoE2Pn5kPrrO+cphn6lwD8d6HkS87u8O/weWZfq7Z3Q8s+zsbjb4JD4crMSnk/vmrr4nwlYTcsHQfvdbXS8otfs/tb99eU0ILo8KjN5f/9u+zpaFJ0bV9kP2tdWjT/3XiSrz+W2/Q1f5N2CmY+ZtsX3weVGhTu85WvDbdPgfJ14Fi8fb590A3ify3c582vpW9YU9lKjaBBN6ej8Z0Wt9q02bQTMH2YbxLkE0dsDffoZjB3JBw/aMsseoyBIash9l6b8SLiBUXw00a8IuU4TO5rUzOqtYPOqgKXq6Y3QeUmNur045jCfa6jO6356LtXw38b25eWnYsBN1RrC12et6tykn/lamZP25z/b/++Kh6o3G7YtRxmP5m9lsUp2zzJVxGbcugRWdUqyOG2Xnb+ZukbdpGvdLRV0PWFWpfC/UvgqietCMeOH62IwszHbdTDH7jdsOgVm/IPcNnDRfPiwNm4XFZ8IyjUpsxu/KbwnuvYAUu2/tvMqt2ePGpV9HqOgwdW2hq0kPDCe34plkKcDkD8kNsN3zwE8ettjvMt4yEkzOmo/FNQEFz1BEzqYyNRsfdBmSjvHf/w7/DrV/DrlzZFKosLalxs6yMa9bA+KeIdlz9i1bZ2Lobf5kPdjk5HFPjcbns/Wf+Z3U7vyxJeFprd5PuY0k7BrmW2XVSTL7Cqh/HrbAp5i1udjiZb2ilbUwPQaaRvp3KFhNu/8+a32HqzDV/D0rF2bl7zrJ2PTk1lSk+DGcOyL0zEDXbm34fTKjWASx6ERS/DjMeg9pXe7SmauBcWvwor3rcRNrALqZc/Yp+rQcHeey6RMyj5KgrSUrybHC17xxrOuoLh5g+sooycXYOuNvL0x3JY9BJc+2LBjndwq5U8//VL2Hd62XMX1LwEmvS0ioZlqxTseSR3ZWNsmu2S123tV52rAnJOuV84uCU74Tq4Ofv+0FLWF2f3SusdWKWFNQb2pd0r7UtXqUqFP93NSfU62xfY3+bZF/tgP/nY/+ULSN5v62mcSi4uqAG9P4Ytcy3hOfw7fH63VbDt9hJUbuTbeE4dg6l/zyyQ4rJG0xcP9G0M/uSyR2DdVKswuGCUVcIsqIwMWDzGqtqmZ1ZTjLnI1tTV71q8RhjFMX7yLiz55nbDe53hgurQfghUa12w4+1caotMwar6FNWeIt7kckHHp6zR34r3rQlzuVp5/3vPqMCGb+wK7P5fTjt2kF2V94xwla7s9fAlF5c8ZP8v96yyYgANi9F6i4I6uhPWf24J1+kXD4LDod7VVtK/fhfrR/dRT1t39Wk/uHsuhJX0XZxZJeYvLdrJdbU21kD6xGHY9ZP1M/MHy96yn23/butnnVSvE9RaAkteg+9fhh0/2FTE2IFwxT99MyqXFA8Tb4G9q62ycK937T2/OAsrCde+BBNvhqVvQos+BatqlxQP0+6B3xfY79Uvhg7DoE7Hov0eIH5HyVeg27fOviDuWWUjJTUvgfYP2kLr872CkxRvX4I8XdvjBhVOzEXRhZdbmeTfF8CC5+GGN8+9f0YG7F5hzRo3fJ2z70xQiFUsbHy9fekvVbEQA5dcla5kV5wXvWxrv3RF9NyS4m20dt1U+GNZ9v1BITZdqGkvaHgtRETm/Lte78K4y+yCw4xhcP1Y38W8zdNcuQhPOQSbPlW3E6z71EZU/CH5+mOFjTwGh0GrO52OxoRG2OhHs8ypiBu/sdFvz1TEpr0K7wv6gc0woZdduChZAfpMVilzj/rXQKPr7LPym3/A32fl7714y1yYdq8V0ggpAde+YBWLlXSJA1xut1aU50diYiKRkZEkJCRQtmxZZ4OJ/9Wq3a2bAhmpdl/FBtB+MDTvnbfFoumpMP46W+dSqZFdhfbm/Ori4I+V8O5VNlp13xKbVnW69FRb3L3haxvlOrYv+7GQCLv61qi7jQqol5rzThyB0S2smMqN70Lzm52OyP/s/Am++7eNXrkzMu902WhS0172pemvGn7/vhA+vB5wQ883oeVthR01pJ6E52tC2kkYtBwq1S/853TSuqnw2V323j5oqdPRwGcDLBls0QducLBNx7lsng0zHoUj2+z3WpfZKMyZ7+sFtWMxfNLHCj2Urw23T7Wm0JItYTeMbQcpx6z6oKcRc16kpcC8p7N7hkU1hZveK9pTjcUxec0NlHzlk18lXx6Je2xofuUHVp4WoHQUtLsH2t4FJcqd/W9n/BN+ehPCysA9C6znkZy/SbfbFdNGPWwtQepJK1u+4WubvnZ6OfqwMlC/s+1bt5OSXX+08AVLLkJKQK93NA3I48RR+0JzerXCam0t4Wrc8/zXI57+33nAfIhq7M1o/2z7D1ZivHQUPLyp6F/9Pn4YXqxjCfJD62ytk1OS4uG/TexC4T0LbL2Nv0o9aUUZFr1siXpQiM0KaXsXVI8t+Hmz/jOYNtDWHlVrB30m/fXFiuJqyVgbkYy4AAavsNkJf+XQb3bRYc/P9nu7e+DqZ2yUU6QQKPkqZH6ZfHmcTIRV4y0RS9xt94WWshLacff/+YPXc1UUoPcEG32R/Nm/Ad6IA9w2VW3b95CanP14yQo2lbDRdTZVUSVs/VvqCfj0DtgyG3BB5//Yv6Hiyu226YUzHrM+SQAt/2brJs5nneOZMtLh4152oaJifRjwXeFejPhulDWPb9rLroIXB+91gZ1LbPSm3QDn4ljwvDWFr9YO7vbD8ve5ObIdZg63C2geUU2hzd+tYuL5rglzu222ypwn7feG3W0KrvpInV16Grx9hVXubHHbX0/tX/upTVNMOWYXnq8fq7W7UuiUfBUyv06+PNJS4JfP7U0+fr3d5wq2anntH4SYlhD/C7zbCVKPw6VDodMIJyMuGj6/F9ZOyv69bFUbMWnUwxb4+ku1McmbM0s/xw60JKy4lSI+uhO+fSSzEhtQoS50Hw0XemnN1LED8NZlkLTX1t3c+HbhjUi9382KKnQfDW36F85z+JtFr9hoZb1rrNGwE9JSYHRTS9x7/S/wSqjvXgUr/gfrPssuTx5WBlr0hjZ35W3ENiPdLl4sf8d+j73PqvgVt/eT/PhjhX1fwQ13fpt7QbBTx2D6I7DmE/u95iVw4zvW806kkCn5KmQBkXx5uN3Wr2jxq9lVfsBGXo7usjntta+Ev32mDwBvSIq36REX1LCEK+aioj+tqahzu62J9tzMixMNu9sHemFU54v/xa6wR9bILsHu5L/L9DT4aZxNC0w9bo1PLxtqF2u8PX1nx2L4oDu4089/bUdepZ6A52rYVK8HVhWf9TXxv8Cb7W196aPbfFtZ0sMzy6J0tE1/DNT+kSeOwJpJsPx/cGhL9v014qxNRaMeuc9qSDlur3/TdDSSnk9fPwQr37d17QN/yHkO7VltpfoP/2Zrrzs8ZkVU9L1GfETJVyELqOTrdHvX2EjY+s/tCw5AZHW4Z6Hmmov8lfWfZ67ROAVVW1tVsrysPciLE0dsOtzyd04rXgGEloToZlClpY1WV2lhXzx8MYK652frw7V3jf1eoz30GF24i9V/GG1JbnC4Ff6p0ty7x9/2vbWFKFMFhm4oPhdG3G4Y3QwSdsFtn9p6U19792qrhnnF43DFY75/fm9zu+18WvE/K6Lk+UwtWRFa9YXW/aFcTbvv2AH4pLdVeQyJsJHdxtc7F3ugOnEEXmtjVQs7PgWXPWz/H5a+ae8b6Sk226TXu1CzvdPRSjGj5KuQBWzy5XF0l71Z7VkFXV/w/hcckaJqxxKY1Me+BFxQ00aMC9IgOCMDVn8Mc0fC8UN2X+0rbYRm31obbTpTSAnrd1OlhSVlVVpYQ1hv9Us6dcxGun4aZ4lgRKQtVL+ob+GX3M/IgE9utemN5WtbUYYzS9QXxPx/w/cv2NTGXu9477iB4Juhlii0uQu6v+Lb5969Ct650kZO//ELlIny7fMXtsS9sOpDK3iVtCfzTpdN82zay9a5HdluPdf6TIIasQ4GG+DWTLZ+XSER0H+6rSP0TIdu2B2ue00Vg8URSr4KWcAnXyKSfwe3Wl+eI9ut+lafT/J3lfWPlbY+Yc8q+71iA+s/U/sK+z0jHQ5ttek0e9dYA9a9ayEl6c/HCg6DqCZQuTGUvxDK17HkpXxtiDiP96hNMy2mhF32e9OboMso3zb4Pn4Y3rrcYmh8Pdw83nsjVO91tZYaPV6F1v28c8xAsXmWNfKNrG7T/nw56jdtoK3Dad7bRn2KqvQ02DzDpiT+/l3Ox8rVgts/UzXhgnK7bfR6+6Ls+4LDbe1c27uLz2i2+B0lX4VMyZdIMZd80EZo/lhuiU/PN/NeQODYASt+8PNH9ntYGbhyuJVC/qvRq4wMOPx7ZiK2OjMxW2v9yM6mVKXsZKxCZkLm+d2TmCXuhZmPWbN2sFG9bq9AvU55e03e9scKq9CXkQpdX4TYewp+zJTjtt4rIxUe/Nlef3GSchxeuNDKpt+3pPBL+nscOwD/bWxTwu6eD9Va++Z5nXboNyvUs3qiTdW95SPvTVMu7g5stjWMGal20eqm92w2gIiDlHwVMiVfIkLqCfh8gPVxA+g4Ai79x9mvvKan2bSv+f/OTpZa9IFOTxdsGpbbbYVz9q6xUbnDv1mCdug3WxtxLqUqWRKyf4P1B3QFW4P2Dv90pijD6Za8AbOG21S1u2bZOruC+H2BNXQuW9WmvhXHK+QTbrbWCZ1G2rnqCwtfhO+etf9/A+b75jn9iedrVnE83wrT5tmw/1drnRBWyuloRPKcG6jmtYhIfoWWsClxs5+EpWNtNOvoDrj25T8XxNj+I0wfBvt/sd+jm1vPJW+s/XC5sqcYnulkgiVih3+HQ5k/PclZ8oHsG9iX4x5jrMCHP7j4PtjxozUu//ROGPj9uZvF/5VtmdOUal1WfL8I17vGkq/Ns32TfKWn2gUHsDYNxVFxPdcKW/1r7CYSYJR8iYgURFAwdPmPVTWb8ZgtuE/4A27+wJqvJu6x5Gz9VNu/RDmr0tWqn29KIEdEWruDmIv+/NjJBDi8zZKxkAio38W/yjK7XNYcNX69ra/74n64dWL+v8xu/8F+5tYfqLio39nW9O36yYrGFCSZzYsNX1vvtlKVoXHPwn0uEZEAUMhlq0REionYe+HWCVaJcOtcK+yw8AUri7x+KuCCNn+33lJt/u4fSU5EpJWvb9oLGnbzj5jOVOICG10MDrP+SEtez99xkg9ZmW/wXmPoQHRBDajUyMqib51X+M/301v2s03/wO3rJSLiRRr5EhHxlobd4M5vrZ9P/Dq7AVSPtZYOMS0dDS9gxbS0iovfPgxzRkC1tlDjYnssIx2O7bfy3ol7bZQlcc8ZP/dmV4iMrGFV54qz+tfAgQ02/TCvRWLyY+8a2LUUgkLsgoOIiCj5EhHxqmqtrTnwpNutb1enkVZeW+s+CqbNXbBjMaz/zP7blqtpSdWx+Ozmtn8lvKwVEynu6nWGH8fAljmWvBbWiOdPmSXlG/eEMtGF8xwiIgFGyZeIiLeVqwX3LrKES0mXd7hcVgxk7xrrfXZ6FUdXEJSOhrJVoEzmrWwVKBOT82d4Gefi9yfVY23K6YnDVtK/MBr+Jh+EdVNsO/Ze7x9fRCRAKfkSESkMQVpS63XhZeCOr2DrHChZMTuxKl3ZP9er+avgEKjTEX75HLbMKpzka9V4SD8FVVraNFEREQFUcENERAJJZFVofSc06m6l8ctWUeKVH/U728/Ns71/7PQ0WH5aeXmN/oqIZFHyJSIiUtzU7QS4rChMwm7vHnvjN5C420Ynm97o3WOLiAQ4JV8iIiLFTamKUK2NbW/x8ujXssxCG63vhJBw7x5bRCTAKfkSEREpjuplTj30ZvK1bx3s+BFcwdD2Lu8dV0SkiFDyJSIiUhzVv8Z+/r4AUk9655iepsqNr4OyMd45pohIEaLkS0REpDiKbm5l+VOPw44fCn6844ezy8u3U3l5EZHcKPkSEREpjlwuqHe1bXuj6uGqDyHtpCV1NS4u+PFERIogJV8iIiLFVda6r1ngduf/OOlpsPxd2469V+XlRUTOQsmXiIhIcVX7CggOgyPb4eCW/B9n8wxI2AUlykPTXt6KTkSkyFHyJSIiUlyFl4aal9j2lln5P46n0EbrOyG0RIHDEhEpqpR8iYiIFGf1M6cebs5n8hX/C2xfpPLyIiJ5oORLRESkOKuXWXJ+5xI4mZC3v0lPheSDcOg3+GG03dewG0RWK5QQRUSKihCnAxAREREHVagDFerCoa2w4DkoW9WSsJNHM39m3k6c9ntq8p+PEzvQ15GLiAQcJV8iIiLFXb3OlnwtfeP8/i6sDEREQp0roWb7wolNRKQI8Ytph2PHjqVWrVpEREQQGxvLsmXLzrn/lClTaNiwIRERETRr1ozp06efdd+BAwficrkYPXp0ro+fOnWKli1b4nK5WL16dQFehYiISIC6+D6o39WmIDa7GdreDZc9Alc/Az1ehVs+hDu+hHsWwIM/w6Pb4MlD8PgfMPQXuP51lZcXEckDx0e+Jk+ezNChQxk3bhyxsbGMHj2azp07s2nTJipXrvyn/RcvXkyfPn0YNWoU3bt3Z+LEifTs2ZNVq1bRtGnTHPtOmzaNpUuXEhMTc9bnf/TRR4mJiWHNmjVef20iIiIB4YLqcNskp6MQESnyHB/5euWVVxgwYAD9+/encePGjBs3jpIlS/Lee+/luv+YMWPo0qULw4YNo1GjRjzzzDO0atWK119/Pcd+u3fv5oEHHmDChAmEhobmeqwZM2Ywe/ZsXnrpJa+/LhERERERkdM5mnylpKSwcuVKOnXqlHVfUFAQnTp1YsmSJbn+zZIlS3LsD9C5c+cc+2dkZNC3b1+GDRtGkyZNcj1OfHw8AwYM4KOPPqJkyZJ/GeupU6dITEzMcRMREREREckrR5OvgwcPkp6eTlRUVI77o6Ki2LdvX65/s2/fvr/c//nnnyckJIQHH3ww12O43W7uvPNOBg4cSJs2bfIU66hRo4iMjMy6Va9ePU9/JyIiIiIiAn4w7dDbVq5cyZgxY/jggw9wnWXx72uvvUZSUhLDhw/P83GHDx9OQkJC1m3Xrl3eCllERERERIoBR5OvihUrEhwcTHx8fI774+PjiY6OzvVvoqOjz7n/okWL2L9/PzVq1CAkJISQkBB27NjBww8/TK1atQCYP38+S5YsITw8nJCQEOrWrQtAmzZt6NevX67PGx4eTtmyZXPcRERERERE8srR5CssLIzWrVszb968rPsyMjKYN28ecXFxuf5NXFxcjv0B5syZk7V/3759Wbt2LatXr866xcTEMGzYMGbNmgXAq6++ypo1a7Ie95Sqnzx5Mv/+978L46WKiIiIiEgx53ip+aFDh9KvXz/atGlDu3btGD16NMnJyfTv3x+AO+64g6pVqzJq1CgAhgwZQocOHXj55Zfp1q0bkyZNYsWKFbz99tsAVKhQgQoVKuR4jtDQUKKjo2nQoAEANWrUyPF46dKlAahTpw7VqlUr1NcrIiIiIiLFk+PJV+/evTlw4ABPPfUU+/bto2XLlsycOTOrqMbOnTsJCsoeoGvfvj0TJ07kiSee4PHHH6devXp88cUXf+rxJSIiIiIi4k9cbrfb7XQQgSgxMZHIyEgSEhK0/ktEREREpBjLa25Q5KodioiIiIiI+CMlXyIiIiIiIj6g5EtERERERMQHlHyJiIiIiIj4gJIvERERERERH1DyJSIiIiIi4gNKvkRERERERHxAyZeIiIiIiIgPKPkSERERERHxgRCnAwhUbrcbsG7WIiIiIiJSfHlyAk+OcDZKvvIpKSkJgOrVqzsciYiIiIiI+IOkpCQiIyPP+rjL/VfpmeQqIyODPXv2UKZMGVwul6OxJCYmUr16dXbt2kXZsmUdjUUCj84fKQidP5JfOnekIHT+SEEUxvnjdrtJSkoiJiaGoKCzr+zSyFc+BQUFUa1aNafDyKFs2bJ6A5J80/kjBaHzR/JL544UhM4fKQhvnz/nGvHyUMENERERERERH1DyJSIiIiIi4gNKvoqA8PBwRowYQXh4uNOhSADS+SMFofNH8kvnjhSEzh8pCCfPHxXcEBERERER8QGNfImIiIiIiPiAki8REREREREfUPIlIiIiIiLiA0q+REREREREfEDJVxEwduxYatWqRUREBLGxsSxbtszpkMQPff/99/To0YOYmBhcLhdffPFFjsfdbjdPPfUUVapUoUSJEnTq1IktW7Y4E6z4lVGjRtG2bVvKlClD5cqV6dmzJ5s2bcqxz8mTJxk0aBAVKlSgdOnS9OrVi/j4eIciFn/y5ptv0rx586xmpnFxccyYMSPrcZ07klfPPfccLpeLhx56KOs+nT9yNiNHjsTlcuW4NWzYMOtxp84dJV8BbvLkyQwdOpQRI0awatUqWrRoQefOndm/f7/ToYmfSU5OpkWLFowdOzbXx1944QVeffVVxo0bx08//USpUqXo3LkzJ0+e9HGk4m8WLlzIoEGDWLp0KXPmzCE1NZVrrrmG5OTkrH3+8Y9/8PXXXzNlyhQWLlzInj17uPHGGx2MWvxFtWrVeO6551i5ciUrVqzgqquu4vrrr+eXX34BdO5I3ixfvpy33nqL5s2b57hf54+cS5MmTdi7d2/W7Ycffsh6zLFzxy0BrV27du5BgwZl/Z6enu6OiYlxjxo1ysGoxN8B7mnTpmX9npGR4Y6Ojna/+OKLWfcdPXrUHR4e7v7kk08ciFD82f79+92Ae+HChW63286V0NBQ95QpU7L22bBhgxtwL1myxKkwxY+VK1fO/e677+rckTxJSkpy16tXzz1nzhx3hw4d3EOGDHG73XrvkXMbMWKEu0WLFrk+5uS5o5GvAJaSksLKlSvp1KlT1n1BQUF06tSJJUuWOBiZBJpt27axb9++HOdSZGQksbGxOpfkTxISEgAoX748ACtXriQ1NTXH+dOwYUNq1Kih80dySE9PZ9KkSSQnJxMXF6dzR/Jk0KBBdOvWLcd5Anrvkb+2ZcsWYmJiqF27Nrfffjs7d+4EnD13Qgr16FKoDh48SHp6OlFRUTnuj4qKYuPGjQ5FJYFo3759ALmeS57HRAAyMjJ46KGHuOSSS2jatClg509YWBgXXHBBjn11/ojHunXriIuL4+TJk5QuXZpp06bRuHFjVq9erXNHzmnSpEmsWrWK5cuX/+kxvffIucTGxvLBBx/QoEED9u7dy9NPP81ll13G+vXrHT13lHyJiEieDRo0iPXr1+eYNy/yVxo0aMDq1atJSEhg6tSp9OvXj4ULFzodlvi5Xbt2MWTIEObMmUNERITT4UiA6dq1a9Z28+bNiY2NpWbNmnz66aeUKFHCsbg07TCAVaxYkeDg4D9VZomPjyc6OtqhqCQQec4XnUtyLoMHD+abb77hu+++o1q1aln3R0dHk5KSwtGjR3Psr/NHPMLCwqhbty6tW7dm1KhRtGjRgjFjxujckXNauXIl+/fvp1WrVoSEhBASEsLChQt59dVXCQkJISoqSueP5NkFF1xA/fr12bp1q6PvPUq+AlhYWBitW7dm3rx5WfdlZGQwb9484uLiHIxMAs2FF15IdHR0jnMpMTGRn376SeeS4Ha7GTx4MNOmTWP+/PlceOGFOR5v3bo1oaGhOc6fTZs2sXPnTp0/kquMjAxOnTqlc0fOqWPHjqxbt47Vq1dn3dq0acPtt9+eta3zR/Lq2LFj/Pbbb1SpUsXR9x5NOwxwQ4cOpV+/frRp04Z27doxevRokpOT6d+/v9OhiZ85duwYW7duzfp927ZtrF69mvLly1OjRg0eeughnn32WerVq8eFF17Ik08+SUxMDD179nQuaPELgwYNYuLEiXz55ZeUKVMmaz58ZGQkJUqUIDIykrvuuouhQ4dSvnx5ypYtywMPPEBcXBwXX3yxw9GL04YPH07Xrl2pUaMGSUlJTJw4kQULFjBr1iydO3JOZcqUyVpb6lGqVCkqVKiQdb/OHzmbRx55hB49elCzZk327NnDiBEjCA4Opk+fPs6+9xRqLUXxiddee81do0YNd1hYmLtdu3bupUuXOh2S+KHvvvvODfzp1q9fP7fbbeXmn3zySXdUVJQ7PDzc3bFjR/emTZucDVr8Qm7nDeB+//33s/Y5ceKE+/7773eXK1fOXbJkSfcNN9zg3rt3r3NBi9/4+9//7q5Zs6Y7LCzMXalSJXfHjh3ds2fPznpc546cj9NLzbvdOn/k7Hr37u2uUqWKOywszF21alV379693Vu3bs163Klzx+V2u92Fm96JiIiIiIiI1nyJiIiIiIj4gJIvERERERERH1DyJSIiIiIi4gNKvkRERERERHxAyZeIiIiIiIgPKPkSERERERHxASVfIiIiIiIiPqDkS0RERERExAeUfImIiPiYy+Xiiy++cDoMERHxMSVfIiJSrNx55524XK4/3bp06eJ0aCIiUsSFOB2AiIiIr3Xp0oX3338/x33h4eEORSMiIsWFRr5ERKTYCQ8PJzo6OsetXLlygE0JfPPNN+natSslSpSgdu3aTJ06Ncffr1u3jquuuooSJUpQoUIF7rnnHo4dO5Zjn/fee48mTZoQHh5OlSpVGDx4cI7HDx48yA033EDJkiWpV68eX331VeG+aBERcZySLxERkTM8+eST9OrVizVr1nD77bdz6623smHDBgCSk5Pp3Lkz5cqVY/ny5UyZMoW5c+fmSK7efPNNBg0axD333MO6dev46quvqFu3bo7nePrpp7nllltYu3Yt1157LbfffjuHDx/26esUERHfcrndbrfTQYiIiPjKnXfeyccff0xERESO+x9//HEef/xxXC4XAwcO5M0338x67OKLL6ZVq1a88cYbvPPOOzz22GPs2rWLUqVKATB9+nR69OjBnj17iIqKomrVqvTv359nn3021xhcLhdPPPEEzzzzDGAJXenSpZkxY4bWnomIFGFa8yUiIsXOlVdemSO5AihfvnzWdlxcXI7H4uLiWL16NQAbNmygRYsWWYkXwCWXXEJGRgabNm3C5XKxZ88eOnbseM4YmjdvnrVdqlQpypYty/79+/P7kkREJAAo+RIRkWKnVKlSf5oG6C0lSpTI036hoaE5fne5XGRkZBRGSCIi4ie05ktEROQMS5cu/dPvjRo1AqBRo0asWbOG5OTkrMd//PFHgoKCaNCgAWXKlKFWrVrMmzfPpzGLiIj/08iXiIgUO6dOnWLfvn057gsJCaFixYoATJkyhTZt2nDppZcyYcIEli1bxv/+9z8Abr/9dkaMGEG/fv0YOXIkBw4c4IEHHqBv375ERUUBMHLkSAYOHEjlypXp2rUrSUlJ/PjjjzzwwAO+faEiIuJXlHyJiEixM3PmTKpUqZLjvgYNGrBx40bAKhFOmjSJ+++/nypVqvDJJ5/QuHFjAEqWLMmsWbMYMmQIbdu2pWTJkvTq1YtXXnkl61j9+vXj5MmT/Pe//+WRRx6hYsWK3HTTTb57gSIi4pdU7VBEROQ0LpeLadOm0bNnT6dDERGRIkZrvkRERERERHxAyZeIiIiIiIgPaM2XiIjIaTQbX0RECotGvkRERERERHxAyZeIiIiIiIgPKPkSERERERHxASVfIiIiIiIiPqDkS0RERERExAeUfImIiIiIiPiAki8REREREREfUPIlIiIiIiLiA/8PweSziqLNEcUAAAAASUVORK5CYII=",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# summarize history for loss\n",
+ "plt.figure(figsize=(10, 6))\n",
+ "plt.plot(history.history[\"loss\"])\n",
+ "plt.plot(history.history[\"val_loss\"])\n",
+ "plt.title(\"Model Loss\")\n",
+ "plt.ylabel(\"Loss\")\n",
+ "plt.xlabel(\"Epoch\")\n",
+ "plt.legend([\"Train\", \"Validation\"], loc=\"upper right\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 467,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "model.compile(optimizer=\"adam\", loss=\"mean_squared_error\", metrics=[\"mae\", \"mape\"])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 468,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame):\n",
+ " \"\"\"\n",
+ " Function to generate stocks weight allocation for time t+1 using historic data. Initial weights generated as 1/p for active stock within a month\n",
+ "\n",
+ " Args:\n",
+ " df_train: The training set of returns. First column is month end and remaining columns are stocks\n",
+ " df_test: The testing set of returns. First column is month end and remaining columns are stocks\n",
+ "\n",
+ " Returns:\n",
+ " The returns dataframe and the weights\n",
+ " \"\"\"\n",
+ "\n",
+ " print(\n",
+ " \"---> training set spans\",\n",
+ " df_train[\"month_end\"].min(),\n",
+ " df_train[\"month_end\"].max(),\n",
+ " )\n",
+ " print(\n",
+ " \"---> training set spans\",\n",
+ " df_test[\"month_end\"].min(),\n",
+ " df_test[\"month_end\"].max(),\n",
+ " )\n",
+ "\n",
+ " # initialise data\n",
+ " n_train = len(df_train)\n",
+ " df_returns = pd.concat(objs=[df_train, df_test], ignore_index=True)\n",
+ "\n",
+ " df_weights = equalise_weights(\n",
+ " df_returns[:n_train]\n",
+ " ) # df to store weights and create initial\n",
+ "\n",
+ " # list of stock names\n",
+ " list_stocks = list(df_returns.columns)\n",
+ " list_stocks.remove(\"month_end\")\n",
+ "\n",
+ " # Only positive predicted stock are considered\n",
+ " # Higher volitility have higher weighting\n",
+ " # Higher prediction through my machine learning algorithm (LSTM) will have higher weighting\n",
+ " for i in range(len(df_test)):\n",
+ " df_latest = df_returns[(df_returns[\"month_end\"] < df_test.loc[i, \"month_end\"])]\n",
+ "\n",
+ " if len(df_latest) >= lookback:\n",
+ " latest_returns = df_latest[-lookback:][list_stocks].values\n",
+ " else:\n",
+ " continue\n",
+ "\n",
+ " # reshape the latest returns to be suitable for the LSTM model\n",
+ " latest_returns = np.reshape(latest_returns, (1, lookback, len(list_stocks)))\n",
+ "\n",
+ " # predict the future returns using the LSTM model\n",
+ " predicted_returns = model.predict(latest_returns)\n",
+ "\n",
+ " # Filter out the stocks with positive predicted returns\n",
+ " positive_returns_indices = np.where(predicted_returns[0] > 0)[0]\n",
+ " positive_returns = predicted_returns[0][positive_returns_indices]\n",
+ " positive_stock_names = np.array(list_stocks)[positive_returns_indices]\n",
+ "\n",
+ " # Apply exponential weighting to the positive returns\n",
+ " exp_returns = np.exp(positive_returns)\n",
+ "\n",
+ " # Calculate the recent volatility for each stock\n",
+ " volatilities = np.std(latest_returns[0], axis=0)\n",
+ "\n",
+ " # Scale the weights of each stock correspondto its recent volatility\n",
+ " volatility_scaled_weights = exp_returns * volatilities[positive_returns_indices]\n",
+ "\n",
+ " # Normalize the weights to sum to 1\n",
+ " weights = volatility_scaled_weights / np.sum(volatility_scaled_weights)\n",
+ "\n",
+ " # Create a new weight dataframe\n",
+ " weights_dict = dict(zip(positive_stock_names, weights))\n",
+ " weights_dict[\"month_end\"] = df_test.loc[i, \"month_end\"]\n",
+ " df_this = pd.DataFrame(data=[weights_dict], columns=df_weights.columns)\n",
+ " df_this = df_this.fillna(0) # fill NaNs for stocks that have been excluded\n",
+ "\n",
+ " # Append the weights to the df_weights dataframe\n",
+ " df_weights = pd.concat(objs=[df_weights, df_this], ignore_index=True)\n",
+ "\n",
+ " # 10% limit check\n",
+ " if len(\n",
+ " np.array(df_weights[list_stocks])[np.array(df_weights[list_stocks]) > 0.101]\n",
+ " ):\n",
+ " raise Exception(r\"---> 10% limit exceeded\")\n",
+ "\n",
+ " return df_returns, df_weights"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 469,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def plot_total_return(\n",
+ " df_returns: pd.DataFrame,\n",
+ " df_weights_index: pd.DataFrame,\n",
+ " df_weights_portfolio: pd.DataFrame,\n",
+ "):\n",
+ " \"\"\"\n",
+ " Function to generate the two total return indices.\n",
+ "\n",
+ " Args:\n",
+ " df_returns: Ascending date ordered combined training and test returns data.\n",
+ " df_weights_index: Index weights. Equally weighted\n",
+ " df_weights_index: Portfolio weights. Your portfolio should use equally weighted for the training date range. If blank will be ignored\n",
+ "\n",
+ " Returns:\n",
+ " A plot of the two total return indices and the total return indices as a dataframe\n",
+ " \"\"\"\n",
+ "\n",
+ " # list of stock names\n",
+ " list_stocks = list(df_returns.columns)\n",
+ " list_stocks.remove(\"month_end\")\n",
+ "\n",
+ " # replace nans with 0 in return array\n",
+ " ar_returns = np.array(df_returns[list_stocks])\n",
+ " np.nan_to_num(x=ar_returns, copy=False, nan=0)\n",
+ "\n",
+ " # calc index\n",
+ " ar_rtn_index = np.array(df_weights_index[list_stocks]) * ar_returns\n",
+ " ar_rtn_port = np.array(df_weights_portfolio[list_stocks]) * ar_returns\n",
+ "\n",
+ " v_rtn_index = np.sum(ar_rtn_index, axis=1)\n",
+ " v_rtn_port = np.sum(ar_rtn_port, axis=1)\n",
+ "\n",
+ " # add return series to dataframe\n",
+ " df_rtn = pd.DataFrame(data=df_returns[\"month_end\"], columns=[\"month_end\"])\n",
+ " df_rtn[\"index\"] = v_rtn_index\n",
+ " df_rtn[\"portfolio\"] = v_rtn_port\n",
+ " df_rtn\n",
+ "\n",
+ " # create total return\n",
+ " base_price = 100\n",
+ " df_rtn.sort_values(by=\"month_end\", inplace=True)\n",
+ " df_rtn[\"index_tr\"] = ((1 + df_rtn[\"index\"]).cumprod()) * base_price\n",
+ " df_rtn[\"portfolio_tr\"] = ((1 + df_rtn[\"portfolio\"]).cumprod()) * base_price\n",
+ " df_rtn\n",
+ "\n",
+ " df_rtn_long = df_rtn[[\"month_end\", \"index_tr\", \"portfolio_tr\"]].melt(\n",
+ " id_vars=\"month_end\", var_name=\"series\", value_name=\"Total Return\"\n",
+ " )\n",
+ "\n",
+ " # plot\n",
+ " fig1 = px.line(\n",
+ " data_frame=df_rtn_long, x=\"month_end\", y=\"Total Return\", color=\"series\"\n",
+ " )\n",
+ "\n",
+ " return fig1, df_rtn"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 470,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "---> training set spans 2010-01-31 2017-08-31\n",
+ "---> training set spans 2017-09-30 2022-09-30\n",
+ "1/1 [==============================] - 2s 2s/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 42ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 38ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 30ms/step\n",
+ "1/1 [==============================] - 0s 38ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 41ms/step\n",
+ "1/1 [==============================] - 0s 37ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 35ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 30ms/step\n",
+ "1/1 [==============================] - 0s 35ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 44ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 37ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 37ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 35ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 44ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 40ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 44ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 38ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 39ms/step\n",
+ "1/1 [==============================] - 0s 60ms/step\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.plotly.v1+json": {
+ "config": {
+ "plotlyServerURL": "https://plot.ly"
+ },
+ "data": [
+ {
+ "hovertemplate": "series=index_tr
month_end=%{x}
Total Return=%{y}",
+ "legendgroup": "index_tr",
+ "line": {
+ "color": "#636efa",
+ "dash": "solid"
+ },
+ "marker": {
+ "symbol": "circle"
+ },
+ "mode": "lines",
+ "name": "index_tr",
+ "orientation": "v",
+ "showlegend": true,
+ "type": "scatter",
+ "x": [
+ "2010-01-31",
+ "2010-02-28",
+ "2010-03-31",
+ "2010-04-30",
+ "2010-05-31",
+ "2010-06-30",
+ "2010-07-31",
+ "2010-08-31",
+ "2010-09-30",
+ "2010-10-31",
+ "2010-11-30",
+ "2010-12-31",
+ "2011-01-31",
+ "2011-02-28",
+ "2011-03-31",
+ "2011-04-30",
+ "2011-05-31",
+ "2011-06-30",
+ "2011-07-31",
+ "2011-08-31",
+ "2011-09-30",
+ "2011-10-31",
+ "2011-11-30",
+ "2011-12-31",
+ "2012-01-31",
+ "2012-02-29",
+ "2012-03-31",
+ "2012-04-30",
+ "2012-05-31",
+ "2012-06-30",
+ "2012-07-31",
+ "2012-08-31",
+ "2012-09-30",
+ "2012-10-31",
+ "2012-11-30",
+ "2012-12-31",
+ "2013-01-31",
+ "2013-02-28",
+ "2013-03-31",
+ "2013-04-30",
+ "2013-05-31",
+ "2013-06-30",
+ "2013-07-31",
+ "2013-08-31",
+ "2013-09-30",
+ "2013-10-31",
+ "2013-11-30",
+ "2013-12-31",
+ "2014-01-31",
+ "2014-02-28",
+ "2014-03-31",
+ "2014-04-30",
+ "2014-05-31",
+ "2014-06-30",
+ "2014-07-31",
+ "2014-08-31",
+ "2014-09-30",
+ "2014-10-31",
+ "2014-11-30",
+ "2014-12-31",
+ "2015-01-31",
+ "2015-02-28",
+ "2015-03-31",
+ "2015-04-30",
+ "2015-05-31",
+ "2015-06-30",
+ "2015-07-31",
+ "2015-08-31",
+ "2015-09-30",
+ "2015-10-31",
+ "2015-11-30",
+ "2015-12-31",
+ "2016-01-31",
+ "2016-02-29",
+ "2016-03-31",
+ "2016-04-30",
+ "2016-05-31",
+ "2016-06-30",
+ "2016-07-31",
+ "2016-08-31",
+ "2016-09-30",
+ "2016-10-31",
+ "2016-11-30",
+ "2016-12-31",
+ "2017-01-31",
+ "2017-02-28",
+ "2017-03-31",
+ "2017-04-30",
+ "2017-05-31",
+ "2017-06-30",
+ "2017-07-31",
+ "2017-08-31",
+ "2017-09-30",
+ "2017-10-31",
+ "2017-11-30",
+ "2017-12-31",
+ "2018-01-31",
+ "2018-02-28",
+ "2018-03-31",
+ "2018-04-30",
+ "2018-05-31",
+ "2018-06-30",
+ "2018-07-31",
+ "2018-08-31",
+ "2018-09-30",
+ "2018-10-31",
+ "2018-11-30",
+ "2018-12-31",
+ "2019-01-31",
+ "2019-02-28",
+ "2019-03-31",
+ "2019-04-30",
+ "2019-05-31",
+ "2019-06-30",
+ "2019-07-31",
+ "2019-08-31",
+ "2019-09-30",
+ "2019-10-31",
+ "2019-11-30",
+ "2019-12-31",
+ "2020-01-31",
+ "2020-02-29",
+ "2020-03-31",
+ "2020-04-30",
+ "2020-05-31",
+ "2020-06-30",
+ "2020-07-31",
+ "2020-08-31",
+ "2020-09-30",
+ "2020-10-31",
+ "2020-11-30",
+ "2020-12-31",
+ "2021-01-31",
+ "2021-02-28",
+ "2021-03-31",
+ "2021-04-30",
+ "2021-05-31",
+ "2021-06-30",
+ "2021-07-31",
+ "2021-08-31",
+ "2021-09-30",
+ "2021-10-31",
+ "2021-11-30",
+ "2021-12-31",
+ "2022-01-31",
+ "2022-02-28",
+ "2022-03-31",
+ "2022-04-30",
+ "2022-05-31",
+ "2022-06-30",
+ "2022-07-31",
+ "2022-08-31",
+ "2022-09-30"
+ ],
+ "xaxis": "x",
+ "y": [
+ 98.40422503465814,
+ 100.93798662242051,
+ 107.68288522534036,
+ 109.7995615285553,
+ 107.23242817648126,
+ 106.43966113566464,
+ 113.91349320384909,
+ 112.29508785565194,
+ 122.12549889316125,
+ 124.87638245152488,
+ 124.37504919099058,
+ 131.02440630172168,
+ 125.53974799975698,
+ 128.16916055886097,
+ 130.8873968980463,
+ 134.06376216689685,
+ 133.87076190339369,
+ 132.59760255874266,
+ 132.19487983933925,
+ 133.93330703110996,
+ 130.5237798699564,
+ 139.62267767903492,
+ 142.58187781542216,
+ 140.81510171281383,
+ 147.43151378288488,
+ 151.98680235958813,
+ 152.40074939942423,
+ 156.02418771795553,
+ 152.8161411497546,
+ 155.48775962326914,
+ 159.96753392766976,
+ 161.2555092837166,
+ 163.55646116844596,
+ 166.76092531656502,
+ 169.35948468015056,
+ 179.51302600735073,
+ 178.97405279416094,
+ 175.715694663543,
+ 177.78002433183755,
+ 173.6270905121469,
+ 179.05309265268664,
+ 174.40587342069082,
+ 177.70371255865953,
+ 180.45868512898545,
+ 190.13847786882747,
+ 199.8342118600708,
+ 195.61245975954753,
+ 198.21223347276447,
+ 192.83928084761467,
+ 199.0110446369025,
+ 209.28517002996813,
+ 216.99871696931413,
+ 215.54672594503234,
+ 221.47400674506645,
+ 229.30151970138036,
+ 231.71558423761155,
+ 223.30433148163613,
+ 230.03817391436593,
+ 237.31763181271953,
+ 238.0489478471065,
+ 253.40103532914986,
+ 257.65372033222815,
+ 250.32521657304318,
+ 261.0487471728084,
+ 244.49076503231,
+ 240.52762911874868,
+ 239.19767530915811,
+ 235.3547408233148,
+ 222.77135367139928,
+ 234.26747289033133,
+ 222.1090879667571,
+ 213.67839960700294,
+ 220.78695617407473,
+ 238.25962030287462,
+ 265.5875885745103,
+ 281.4830979229849,
+ 265.08963832048636,
+ 272.6053430199218,
+ 290.46865219314884,
+ 277.2773336280136,
+ 279.3254063118272,
+ 277.71860735593725,
+ 274.1748170835136,
+ 284.22745240063205,
+ 296.41653958631605,
+ 293.1716168419007,
+ 293.7023992516104,
+ 296.36419976912174,
+ 289.35664391915265,
+ 278.34458913811073,
+ 293.49195242698454,
+ 302.7447105318491,
+ 293.3548318464133,
+ 306.265024468535,
+ 316.34007571598295,
+ 320.6050708597117,
+ 319.8398684632358,
+ 314.3939885564841,
+ 299.3651563947235,
+ 311.75016932500927,
+ 286.5744449293349,
+ 284.51792257776367,
+ 296.12916505146376,
+ 296.143910254921,
+ 290.4436965043894,
+ 286.9509171356384,
+ 285.7353782660105,
+ 295.5481203141585,
+ 303.41923749726544,
+ 308.1306150282999,
+ 298.5647435963675,
+ 309.02289813595524,
+ 300.56226016303185,
+ 312.06482538817767,
+ 298.2095280041462,
+ 288.517714586796,
+ 289.2751273268798,
+ 302.77492930198224,
+ 296.15403611536595,
+ 301.300222213508,
+ 288.1274106750146,
+ 256.3501391424798,
+ 198.61104648895602,
+ 232.17876375277234,
+ 226.37299938748362,
+ 251.28070815857097,
+ 253.4386819534693,
+ 248.00730686110998,
+ 251.20981465197428,
+ 242.3029989334201,
+ 277.8151656727379,
+ 304.3408079639736,
+ 323.87054861742905,
+ 344.77548375050344,
+ 366.4195141948255,
+ 381.31140527510394,
+ 402.786450399951,
+ 391.0039272495355,
+ 405.4842305132651,
+ 429.09830839640495,
+ 428.2369585651376,
+ 437.4693282884787,
+ 444.0045333993229,
+ 476.727609087252,
+ 484.55475348051664,
+ 493.4639696855345,
+ 514.924562516531,
+ 488.9124266125262,
+ 482.9373630725979,
+ 440.5963276777227,
+ 459.5446640353366,
+ 452.01765890108527,
+ 450.7681381232569
+ ],
+ "yaxis": "y"
+ },
+ {
+ "hovertemplate": "series=portfolio_tr
month_end=%{x}
Total Return=%{y}",
+ "legendgroup": "portfolio_tr",
+ "line": {
+ "color": "#EF553B",
+ "dash": "solid"
+ },
+ "marker": {
+ "symbol": "circle"
+ },
+ "mode": "lines",
+ "name": "portfolio_tr",
+ "orientation": "v",
+ "showlegend": true,
+ "type": "scatter",
+ "x": [
+ "2010-01-31",
+ "2010-02-28",
+ "2010-03-31",
+ "2010-04-30",
+ "2010-05-31",
+ "2010-06-30",
+ "2010-07-31",
+ "2010-08-31",
+ "2010-09-30",
+ "2010-10-31",
+ "2010-11-30",
+ "2010-12-31",
+ "2011-01-31",
+ "2011-02-28",
+ "2011-03-31",
+ "2011-04-30",
+ "2011-05-31",
+ "2011-06-30",
+ "2011-07-31",
+ "2011-08-31",
+ "2011-09-30",
+ "2011-10-31",
+ "2011-11-30",
+ "2011-12-31",
+ "2012-01-31",
+ "2012-02-29",
+ "2012-03-31",
+ "2012-04-30",
+ "2012-05-31",
+ "2012-06-30",
+ "2012-07-31",
+ "2012-08-31",
+ "2012-09-30",
+ "2012-10-31",
+ "2012-11-30",
+ "2012-12-31",
+ "2013-01-31",
+ "2013-02-28",
+ "2013-03-31",
+ "2013-04-30",
+ "2013-05-31",
+ "2013-06-30",
+ "2013-07-31",
+ "2013-08-31",
+ "2013-09-30",
+ "2013-10-31",
+ "2013-11-30",
+ "2013-12-31",
+ "2014-01-31",
+ "2014-02-28",
+ "2014-03-31",
+ "2014-04-30",
+ "2014-05-31",
+ "2014-06-30",
+ "2014-07-31",
+ "2014-08-31",
+ "2014-09-30",
+ "2014-10-31",
+ "2014-11-30",
+ "2014-12-31",
+ "2015-01-31",
+ "2015-02-28",
+ "2015-03-31",
+ "2015-04-30",
+ "2015-05-31",
+ "2015-06-30",
+ "2015-07-31",
+ "2015-08-31",
+ "2015-09-30",
+ "2015-10-31",
+ "2015-11-30",
+ "2015-12-31",
+ "2016-01-31",
+ "2016-02-29",
+ "2016-03-31",
+ "2016-04-30",
+ "2016-05-31",
+ "2016-06-30",
+ "2016-07-31",
+ "2016-08-31",
+ "2016-09-30",
+ "2016-10-31",
+ "2016-11-30",
+ "2016-12-31",
+ "2017-01-31",
+ "2017-02-28",
+ "2017-03-31",
+ "2017-04-30",
+ "2017-05-31",
+ "2017-06-30",
+ "2017-07-31",
+ "2017-08-31",
+ "2017-09-30",
+ "2017-10-31",
+ "2017-11-30",
+ "2017-12-31",
+ "2018-01-31",
+ "2018-02-28",
+ "2018-03-31",
+ "2018-04-30",
+ "2018-05-31",
+ "2018-06-30",
+ "2018-07-31",
+ "2018-08-31",
+ "2018-09-30",
+ "2018-10-31",
+ "2018-11-30",
+ "2018-12-31",
+ "2019-01-31",
+ "2019-02-28",
+ "2019-03-31",
+ "2019-04-30",
+ "2019-05-31",
+ "2019-06-30",
+ "2019-07-31",
+ "2019-08-31",
+ "2019-09-30",
+ "2019-10-31",
+ "2019-11-30",
+ "2019-12-31",
+ "2020-01-31",
+ "2020-02-29",
+ "2020-03-31",
+ "2020-04-30",
+ "2020-05-31",
+ "2020-06-30",
+ "2020-07-31",
+ "2020-08-31",
+ "2020-09-30",
+ "2020-10-31",
+ "2020-11-30",
+ "2020-12-31",
+ "2021-01-31",
+ "2021-02-28",
+ "2021-03-31",
+ "2021-04-30",
+ "2021-05-31",
+ "2021-06-30",
+ "2021-07-31",
+ "2021-08-31",
+ "2021-09-30",
+ "2021-10-31",
+ "2021-11-30",
+ "2021-12-31",
+ "2022-01-31",
+ "2022-02-28",
+ "2022-03-31",
+ "2022-04-30",
+ "2022-05-31",
+ "2022-06-30",
+ "2022-07-31",
+ "2022-08-31",
+ "2022-09-30"
+ ],
+ "xaxis": "x",
+ "y": [
+ 98.40422503465814,
+ 100.93798662242051,
+ 107.68288522534036,
+ 109.7995615285553,
+ 107.23242817648126,
+ 106.43966113566464,
+ 113.91349320384909,
+ 112.29508785565194,
+ 122.12549889316125,
+ 124.87638245152488,
+ 124.37504919099058,
+ 131.02440630172168,
+ 125.53974799975698,
+ 128.16916055886097,
+ 130.8873968980463,
+ 134.06376216689685,
+ 133.87076190339369,
+ 132.59760255874266,
+ 132.19487983933925,
+ 133.93330703110996,
+ 130.5237798699564,
+ 139.62267767903492,
+ 142.58187781542216,
+ 140.81510171281383,
+ 147.43151378288488,
+ 151.98680235958813,
+ 152.40074939942423,
+ 156.02418771795553,
+ 152.8161411497546,
+ 155.48775962326914,
+ 159.96753392766976,
+ 161.2555092837166,
+ 163.55646116844596,
+ 166.76092531656502,
+ 169.35948468015056,
+ 179.51302600735073,
+ 178.97405279416094,
+ 175.715694663543,
+ 177.78002433183755,
+ 173.6270905121469,
+ 179.05309265268664,
+ 174.40587342069082,
+ 177.70371255865953,
+ 180.45868512898545,
+ 190.13847786882747,
+ 199.8342118600708,
+ 195.61245975954753,
+ 198.21223347276447,
+ 192.83928084761467,
+ 199.0110446369025,
+ 209.28517002996813,
+ 216.99871696931413,
+ 215.54672594503234,
+ 221.47400674506645,
+ 229.30151970138036,
+ 231.71558423761155,
+ 223.30433148163613,
+ 230.03817391436593,
+ 237.31763181271953,
+ 238.0489478471065,
+ 253.40103532914986,
+ 257.65372033222815,
+ 250.32521657304318,
+ 261.0487471728084,
+ 244.49076503231,
+ 240.52762911874868,
+ 239.19767530915811,
+ 235.3547408233148,
+ 222.77135367139928,
+ 234.26747289033133,
+ 222.1090879667571,
+ 213.67839960700294,
+ 220.78695617407473,
+ 238.25962030287462,
+ 265.5875885745103,
+ 281.4830979229849,
+ 265.08963832048636,
+ 272.6053430199218,
+ 290.46865219314884,
+ 277.2773336280136,
+ 279.3254063118272,
+ 277.71860735593725,
+ 274.1748170835136,
+ 284.22745240063205,
+ 296.41653958631605,
+ 293.1716168419007,
+ 293.7023992516104,
+ 296.36419976912174,
+ 289.35664391915265,
+ 278.34458913811073,
+ 293.49195242698454,
+ 302.7447105318491,
+ 291.80561414251906,
+ 308.7046914571386,
+ 317.37340117854444,
+ 316.00027449376114,
+ 315.04819761142625,
+ 306.54761587955977,
+ 288.5749801417521,
+ 297.3710943578813,
+ 270.8644143968313,
+ 269.88887599309936,
+ 284.5468402742835,
+ 283.1334606819686,
+ 281.18459819952244,
+ 281.7586332848043,
+ 277.13224150524445,
+ 290.7454324362917,
+ 299.42661412519664,
+ 310.52344774816237,
+ 300.32090977991925,
+ 304.6164403283686,
+ 298.92563811425674,
+ 314.8609833784845,
+ 302.6856522412175,
+ 298.72485372367873,
+ 294.70785693989063,
+ 309.5799623471108,
+ 301.35372611330456,
+ 308.74983744621244,
+ 296.54105058632473,
+ 268.3931479189067,
+ 209.3687829199057,
+ 252.41495812129688,
+ 246.66633447566832,
+ 280.8818649402667,
+ 288.34459739399836,
+ 281.0120003342246,
+ 277.5546298421611,
+ 266.2065334238612,
+ 306.9437347537798,
+ 342.3440844746676,
+ 377.15920697630804,
+ 410.73728795625203,
+ 443.0053154812966,
+ 467.6019738311346,
+ 489.5185046824169,
+ 471.5808724758861,
+ 495.76860453946597,
+ 530.2732496470309,
+ 534.0880240810674,
+ 546.5960135983152,
+ 559.7921928630421,
+ 619.5674937724186,
+ 631.5052822392762,
+ 635.2106136046119,
+ 655.0297003162399,
+ 613.178964349321,
+ 604.2691492939866,
+ 549.8169148037354,
+ 575.2233267859957,
+ 556.6656617493052,
+ 544.134608994288
+ ],
+ "yaxis": "y"
+ }
+ ],
+ "layout": {
+ "legend": {
+ "title": {
+ "text": "series"
+ },
+ "tracegroupgap": 0
+ },
+ "margin": {
+ "t": 60
+ },
+ "template": {
+ "data": {
+ "bar": [
+ {
+ "error_x": {
+ "color": "#2a3f5f"
+ },
+ "error_y": {
+ "color": "#2a3f5f"
+ },
+ "marker": {
+ "line": {
+ "color": "#E5ECF6",
+ "width": 0.5
+ },
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "bar"
+ }
+ ],
+ "barpolar": [
+ {
+ "marker": {
+ "line": {
+ "color": "#E5ECF6",
+ "width": 0.5
+ },
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "barpolar"
+ }
+ ],
+ "carpet": [
+ {
+ "aaxis": {
+ "endlinecolor": "#2a3f5f",
+ "gridcolor": "white",
+ "linecolor": "white",
+ "minorgridcolor": "white",
+ "startlinecolor": "#2a3f5f"
+ },
+ "baxis": {
+ "endlinecolor": "#2a3f5f",
+ "gridcolor": "white",
+ "linecolor": "white",
+ "minorgridcolor": "white",
+ "startlinecolor": "#2a3f5f"
+ },
+ "type": "carpet"
+ }
+ ],
+ "choropleth": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "choropleth"
+ }
+ ],
+ "contour": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "contour"
+ }
+ ],
+ "contourcarpet": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "contourcarpet"
+ }
+ ],
+ "heatmap": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "heatmap"
+ }
+ ],
+ "heatmapgl": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "heatmapgl"
+ }
+ ],
+ "histogram": [
+ {
+ "marker": {
+ "pattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ }
+ },
+ "type": "histogram"
+ }
+ ],
+ "histogram2d": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "histogram2d"
+ }
+ ],
+ "histogram2dcontour": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "histogram2dcontour"
+ }
+ ],
+ "mesh3d": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "type": "mesh3d"
+ }
+ ],
+ "parcoords": [
+ {
+ "line": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "parcoords"
+ }
+ ],
+ "pie": [
+ {
+ "automargin": true,
+ "type": "pie"
+ }
+ ],
+ "scatter": [
+ {
+ "fillpattern": {
+ "fillmode": "overlay",
+ "size": 10,
+ "solidity": 0.2
+ },
+ "type": "scatter"
+ }
+ ],
+ "scatter3d": [
+ {
+ "line": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatter3d"
+ }
+ ],
+ "scattercarpet": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattercarpet"
+ }
+ ],
+ "scattergeo": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattergeo"
+ }
+ ],
+ "scattergl": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattergl"
+ }
+ ],
+ "scattermapbox": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scattermapbox"
+ }
+ ],
+ "scatterpolar": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterpolar"
+ }
+ ],
+ "scatterpolargl": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterpolargl"
+ }
+ ],
+ "scatterternary": [
+ {
+ "marker": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "type": "scatterternary"
+ }
+ ],
+ "surface": [
+ {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ },
+ "colorscale": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "type": "surface"
+ }
+ ],
+ "table": [
+ {
+ "cells": {
+ "fill": {
+ "color": "#EBF0F8"
+ },
+ "line": {
+ "color": "white"
+ }
+ },
+ "header": {
+ "fill": {
+ "color": "#C8D4E3"
+ },
+ "line": {
+ "color": "white"
+ }
+ },
+ "type": "table"
+ }
+ ]
+ },
+ "layout": {
+ "annotationdefaults": {
+ "arrowcolor": "#2a3f5f",
+ "arrowhead": 0,
+ "arrowwidth": 1
+ },
+ "autotypenumbers": "strict",
+ "coloraxis": {
+ "colorbar": {
+ "outlinewidth": 0,
+ "ticks": ""
+ }
+ },
+ "colorscale": {
+ "diverging": [
+ [
+ 0,
+ "#8e0152"
+ ],
+ [
+ 0.1,
+ "#c51b7d"
+ ],
+ [
+ 0.2,
+ "#de77ae"
+ ],
+ [
+ 0.3,
+ "#f1b6da"
+ ],
+ [
+ 0.4,
+ "#fde0ef"
+ ],
+ [
+ 0.5,
+ "#f7f7f7"
+ ],
+ [
+ 0.6,
+ "#e6f5d0"
+ ],
+ [
+ 0.7,
+ "#b8e186"
+ ],
+ [
+ 0.8,
+ "#7fbc41"
+ ],
+ [
+ 0.9,
+ "#4d9221"
+ ],
+ [
+ 1,
+ "#276419"
+ ]
+ ],
+ "sequential": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ],
+ "sequentialminus": [
+ [
+ 0,
+ "#0d0887"
+ ],
+ [
+ 0.1111111111111111,
+ "#46039f"
+ ],
+ [
+ 0.2222222222222222,
+ "#7201a8"
+ ],
+ [
+ 0.3333333333333333,
+ "#9c179e"
+ ],
+ [
+ 0.4444444444444444,
+ "#bd3786"
+ ],
+ [
+ 0.5555555555555556,
+ "#d8576b"
+ ],
+ [
+ 0.6666666666666666,
+ "#ed7953"
+ ],
+ [
+ 0.7777777777777778,
+ "#fb9f3a"
+ ],
+ [
+ 0.8888888888888888,
+ "#fdca26"
+ ],
+ [
+ 1,
+ "#f0f921"
+ ]
+ ]
+ },
+ "colorway": [
+ "#636efa",
+ "#EF553B",
+ "#00cc96",
+ "#ab63fa",
+ "#FFA15A",
+ "#19d3f3",
+ "#FF6692",
+ "#B6E880",
+ "#FF97FF",
+ "#FECB52"
+ ],
+ "font": {
+ "color": "#2a3f5f"
+ },
+ "geo": {
+ "bgcolor": "white",
+ "lakecolor": "white",
+ "landcolor": "#E5ECF6",
+ "showlakes": true,
+ "showland": true,
+ "subunitcolor": "white"
+ },
+ "hoverlabel": {
+ "align": "left"
+ },
+ "hovermode": "closest",
+ "mapbox": {
+ "style": "light"
+ },
+ "paper_bgcolor": "white",
+ "plot_bgcolor": "#E5ECF6",
+ "polar": {
+ "angularaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "bgcolor": "#E5ECF6",
+ "radialaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ }
+ },
+ "scene": {
+ "xaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ },
+ "yaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ },
+ "zaxis": {
+ "backgroundcolor": "#E5ECF6",
+ "gridcolor": "white",
+ "gridwidth": 2,
+ "linecolor": "white",
+ "showbackground": true,
+ "ticks": "",
+ "zerolinecolor": "white"
+ }
+ },
+ "shapedefaults": {
+ "line": {
+ "color": "#2a3f5f"
+ }
+ },
+ "ternary": {
+ "aaxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "baxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ },
+ "bgcolor": "#E5ECF6",
+ "caxis": {
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": ""
+ }
+ },
+ "title": {
+ "x": 0.05
+ },
+ "xaxis": {
+ "automargin": true,
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": "",
+ "title": {
+ "standoff": 15
+ },
+ "zerolinecolor": "white",
+ "zerolinewidth": 2
+ },
+ "yaxis": {
+ "automargin": true,
+ "gridcolor": "white",
+ "linecolor": "white",
+ "ticks": "",
+ "title": {
+ "standoff": 15
+ },
+ "zerolinecolor": "white",
+ "zerolinewidth": 2
+ }
+ }
+ },
+ "xaxis": {
+ "anchor": "y",
+ "domain": [
+ 0,
+ 1
+ ],
+ "title": {
+ "text": "month_end"
+ }
+ },
+ "yaxis": {
+ "anchor": "x",
+ "domain": [
+ 0,
+ 1
+ ],
+ "title": {
+ "text": "Total Return"
+ }
+ }
+ }
+ }
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# running solution\n",
+ "df_returns = pd.concat(objs=[df_returns_train, df_returns_test], ignore_index=True)\n",
+ "df_weights_index = equalise_weights(df_returns)\n",
+ "df_returns, df_weights_portfolio = generate_portfolio(df_returns_train, df_returns_test)\n",
+ "fig1, df_rtn = plot_total_return(\n",
+ " df_returns,\n",
+ " df_weights_index=df_weights_index,\n",
+ " df_weights_portfolio=df_weights_portfolio,\n",
+ ")\n",
+ "fig1"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.10.11"
+ },
+ "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/solution_skeleton.py b/solution_skeleton.py
index 7fc2fa5..6957fff 100644
--- a/solution_skeleton.py
+++ b/solution_skeleton.py
@@ -1,173 +1,270 @@
-# %%
import numpy as np
import pandas as pd
import datetime
import plotly.express as px
+from keras.models import Sequential
+from keras.layers import LSTM, Dense, Dropout
+from sklearn.preprocessing import MinMaxScaler
+from sklearn.model_selection import train_test_split
+import matplotlib.pyplot as plt
+print("---Python script Start---", str(datetime.datetime.now()))
-print('---Python script Start---', str(datetime.datetime.now()))
-
-# %%
+df = pd.read_csv(
+ "C:\\Users\\terre\OneDrive - University of Cape Town\\Terrence\\Code\\prescient-coding-challenge-2023\\data\\returns_train.csv"
+)
# data reads
-df_returns_train = pd.read_csv('data/returns_train.csv')
-df_returns_test = pd.read_csv('data/returns_test.csv')
-df_returns_train['month_end'] = pd.to_datetime(arg=df_returns_train['month_end']).apply(lambda d: d.date())
-df_returns_test['month_end'] = pd.to_datetime(arg=df_returns_test['month_end']).apply(lambda d: d.date())
+df_returns_train = pd.read_csv("data/returns_train.csv")
+df_returns_test = pd.read_csv("data/returns_test.csv")
+df_returns_train["month_end"] = pd.to_datetime(arg=df_returns_train["month_end"]).apply(
+ lambda d: d.date()
+)
+df_returns_test["month_end"] = pd.to_datetime(arg=df_returns_test["month_end"]).apply(
+ lambda d: d.date()
+)
-# %%
+# Ignoring the month_end from training set
-def equalise_weights(df: pd.DataFrame):
+# Get column names as a list but ignore the first column
+header_list = df.columns[1:].tolist()
+print(header_list)
+
+
+def process_dataframe(dataframe):
+ # Create a new dataframe without the 'month_end' column
+ new_dataframe = dataframe.drop(["month_end"], axis=1)
+ return new_dataframe
- '''
- Function to generate the equal weights, i.e. 1/p for each active stock within a month
- Args:
- df: A return data frame. First column is month end and remaining columns are stocks
+clean_df = process_dataframe(df_returns_train)
+
+
+def equalise_weights(df: pd.DataFrame):
+ """
+ Function to generate the equal weights, i.e. 1/p for each active stock within a month
+
+ Args:
+ df: A return data frame. First column is month end and remaining columns are stocks
- Returns:
- A dataframe of the same dimension but with values 1/p on active funds within a month
+ Returns:
+ A dataframe of the same dimension but with values 1/p on active funds within a month
- '''
+ """
# create df to house weights
n_length = len(df)
df_returns = df
df_weights = df_returns[:n_length].copy()
- df_weights.set_index('month_end', inplace=True)
+ df_weights.set_index("month_end", inplace=True)
# list of stock names
list_stocks = list(df_returns.columns)
- list_stocks.remove('month_end')
+ list_stocks.remove("month_end")
# assign 1/p
- df_weights[list_stocks] = 1/len(list_stocks)
+ df_weights[list_stocks] = 1 / len(list_stocks)
return df_weights
-# %%
+# Normalization
+scaler = MinMaxScaler(feature_range=(0, 1))
+scaled_data = scaler.fit_transform(clean_df.values)
-def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame):
+# Create a data structure with 60 time-steps and 1 output for each stock
+lookback = 60
+
+X, y = [], []
+for i in range(lookback, len(scaled_data)):
+ X.append(scaled_data[i - lookback : i])
+ y.append(scaled_data[i])
+X, y = np.array(X), np.array(y)
+
+# Split the data into training and validation sets
+X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
+
+# Initialize the LSTM model
+model = Sequential()
+
+model.add(
+ LSTM(
+ units=50,
+ return_sequences=True,
+ input_shape=(X_train.shape[1], X_train.shape[2]),
+ )
+)
+model.add(Dropout(0.2))
+
+model.add(LSTM(units=50, return_sequences=True))
+model.add(Dropout(0.2))
+
+model.add(LSTM(units=50, return_sequences=True))
+model.add(Dropout(0.2))
- '''
- Function to generate stocks weight allocation for time t+1 using historic data. Initial weights generated as 1/p for active stock within a month
+model.add(LSTM(units=50))
+model.add(Dropout(0.2))
- Args:
- df_train: The training set of returns. First column is month end and remaining columns are stocks
- df_test: The testing set of returns. First column is month end and remaining columns are stocks
+model.add(
+ Dense(units=clean_df.shape[1])
+) # number of units in the output layer should be equal to the number of stocks
- Returns:
- The returns dataframe and the weights
- '''
+# Compile and train the model
+model.compile(optimizer="adam", loss="mean_squared_error")
+model.fit(X_train, y_train, epochs=50, batch_size=20, validation_data=(X_val, y_val))
- print('---> training set spans', df_train['month_end'].min(), df_train['month_end'].max())
- print('---> training set spans', df_test['month_end'].min(), df_test['month_end'].max())
+
+def generate_portfolio(df_train: pd.DataFrame, df_test: pd.DataFrame):
+ """
+ Function to generate stocks weight allocation for time t+1 using historic data. Initial weights generated as 1/p for active stock within a month
+
+ Args:
+ df_train: The training set of returns. First column is month end and remaining columns are stocks
+ df_test: The testing set of returns. First column is month end and remaining columns are stocks
+
+ Returns:
+ The returns dataframe and the weights
+ """
+
+ print(
+ "---> training set spans",
+ df_train["month_end"].min(),
+ df_train["month_end"].max(),
+ )
+ print(
+ "---> training set spans",
+ df_test["month_end"].min(),
+ df_test["month_end"].max(),
+ )
# initialise data
n_train = len(df_train)
df_returns = pd.concat(objs=[df_train, df_test], ignore_index=True)
- df_weights = equalise_weights(df_returns[:n_train]) # df to store weights and create initial
+ df_weights = equalise_weights(
+ df_returns[:n_train]
+ ) # df to store weights and create initial
# list of stock names
list_stocks = list(df_returns.columns)
- list_stocks.remove('month_end')
+ list_stocks.remove("month_end")
- # <<--------------------- YOUR CODE GOES BELOW THIS LINE --------------------->>
+ # Only positive predicted stock are considered
+ # Higher volitility have higher weighting
+ # Higher prediction through my machine learning algorithm (LSTM) will have higher weighting
+ for i in range(len(df_test)):
+ df_latest = df_returns[(df_returns["month_end"] < df_test.loc[i, "month_end"])]
- # This is your playground. Delete/modify any of the code here and replace with
- # your methodology. Below we provide a simple, naive estimation to illustrate
- # how we think you should go about structuring your submission and your comments:
+ if len(df_latest) >= lookback:
+ latest_returns = df_latest[-lookback:][list_stocks].values
+ else:
+ continue
- # We use a static Inverse Volatility Weighting (https://en.wikipedia.org/wiki/Inverse-variance_weighting)
- # strategy to generate portfolio weights.
- # Use the latest available data at that point in time
-
- for i in range(len(df_test)):
+ # reshape the latest returns to be suitable for the LSTM model
+ latest_returns = np.reshape(latest_returns, (1, lookback, len(list_stocks)))
- # latest data at this point
- df_latest = df_returns[(df_returns['month_end'] < df_test.loc[i, 'month_end'])]
-
- # vol calc
- df_w = pd.DataFrame()
- df_w['vol'] = df_latest.std(numeric_only=True) # calculate stock volatility
- df_w['inv_vol'] = 1/df_w['vol'] # calculate the inverse volatility
- df_w['tot_inv_vol'] = df_w['inv_vol'].sum() # calculate the total inverse volatility
- df_w['weight'] = df_w['inv_vol']/df_w['tot_inv_vol'] # calculate weight based on inverse volatility
- df_w.reset_index(inplace=True, names='name')
-
- # add to all weights
- df_this = pd.DataFrame(data=[[df_test.loc[i, 'month_end']] + df_w['weight'].to_list()], columns=df_latest.columns)
- df_weights = pd.concat(objs=[df_weights, df_this], ignore_index=True)
-
- # <<--------------------- YOUR CODE GOES ABOVE THIS LINE --------------------->>
-
- # 10% limit check
- if len(np.array(df_weights[list_stocks])[np.array(df_weights[list_stocks]) > 0.101]):
+ # predict the future returns using the LSTM model
+ predicted_returns = model.predict(latest_returns)
- raise Exception(r'---> 10% limit exceeded')
+ # Filter out the stocks with positive predicted returns
+ positive_returns_indices = np.where(predicted_returns[0] > 0)[0]
+ positive_returns = predicted_returns[0][positive_returns_indices]
+ positive_stock_names = np.array(list_stocks)[positive_returns_indices]
- return df_returns, df_weights
+ # Apply exponential weighting to the positive returns
+ exp_returns = np.exp(positive_returns)
+ # Calculate the recent volatility for each stock
+ volatilities = np.std(latest_returns[0], axis=0)
-# %%
+ # Scale the weights of each stock correspondto its recent volatility
+ volatility_scaled_weights = exp_returns * volatilities[positive_returns_indices]
+ # Normalize the weights to sum to 1
+ weights = volatility_scaled_weights / np.sum(volatility_scaled_weights)
+
+ # Create a new weight dataframe
+ weights_dict = dict(zip(positive_stock_names, weights))
+ weights_dict["month_end"] = df_test.loc[i, "month_end"]
+ df_this = pd.DataFrame(data=[weights_dict], columns=df_weights.columns)
+ df_this = df_this.fillna(0) # fill NaNs for stocks that have been excluded
+
+ # Append the weights to the df_weights dataframe
+ df_weights = pd.concat(objs=[df_weights, df_this], ignore_index=True)
+
+ # 10% limit check
+ if len(
+ np.array(df_weights[list_stocks])[np.array(df_weights[list_stocks]) > 0.101]
+ ):
+ raise Exception(r"---> 10% limit exceeded")
+
+ return df_returns, df_weights
-def plot_total_return(df_returns: pd.DataFrame, df_weights_index: pd.DataFrame, df_weights_portfolio: pd.DataFrame):
- '''
- Function to generate the two total return indices.
+def plot_total_return(
+ df_returns: pd.DataFrame,
+ df_weights_index: pd.DataFrame,
+ df_weights_portfolio: pd.DataFrame,
+):
+ """
+ Function to generate the two total return indices.
- Args:
- df_returns: Ascending date ordered combined training and test returns data.
- df_weights_index: Index weights. Equally weighted
- df_weights_index: Portfolio weights. Your portfolio should use equally weighted for the training date range. If blank will be ignored
+ Args:
+ df_returns: Ascending date ordered combined training and test returns data.
+ df_weights_index: Index weights. Equally weighted
+ df_weights_index: Portfolio weights. Your portfolio should use equally weighted for the training date range. If blank will be ignored
- Returns:
- A plot of the two total return indices and the total return indices as a dataframe
- '''
+ Returns:
+ A plot of the two total return indices and the total return indices as a dataframe
+ """
# list of stock names
list_stocks = list(df_returns.columns)
- list_stocks.remove('month_end')
+ list_stocks.remove("month_end")
# replace nans with 0 in return array
ar_returns = np.array(df_returns[list_stocks])
np.nan_to_num(x=ar_returns, copy=False, nan=0)
# calc index
- ar_rtn_index = np.array(df_weights_index[list_stocks])*ar_returns
- ar_rtn_port = np.array(df_weights_portfolio[list_stocks])*ar_returns
+ ar_rtn_index = np.array(df_weights_index[list_stocks]) * ar_returns
+ ar_rtn_port = np.array(df_weights_portfolio[list_stocks]) * ar_returns
v_rtn_index = np.sum(ar_rtn_index, axis=1)
v_rtn_port = np.sum(ar_rtn_port, axis=1)
# add return series to dataframe
- df_rtn = pd.DataFrame(data=df_returns['month_end'], columns=['month_end'])
- df_rtn['index'] = v_rtn_index
- df_rtn['portfolio'] = v_rtn_port
+ df_rtn = pd.DataFrame(data=df_returns["month_end"], columns=["month_end"])
+ df_rtn["index"] = v_rtn_index
+ df_rtn["portfolio"] = v_rtn_port
df_rtn
# create total return
base_price = 100
- df_rtn.sort_values(by = 'month_end', inplace = True)
- df_rtn['index_tr'] = ((1 + df_rtn['index']).cumprod()) * base_price
- df_rtn['portfolio_tr'] = ((1 + df_rtn['portfolio']).cumprod()) * base_price
+ df_rtn.sort_values(by="month_end", inplace=True)
+ df_rtn["index_tr"] = ((1 + df_rtn["index"]).cumprod()) * base_price
+ df_rtn["portfolio_tr"] = ((1 + df_rtn["portfolio"]).cumprod()) * base_price
df_rtn
- df_rtn_long = df_rtn[['month_end', 'index_tr', 'portfolio_tr']].melt(id_vars='month_end', var_name='series', value_name='Total Return')
+ df_rtn_long = df_rtn[["month_end", "index_tr", "portfolio_tr"]].melt(
+ id_vars="month_end", var_name="series", value_name="Total Return"
+ )
# plot
- fig1 = px.line(data_frame=df_rtn_long, x='month_end', y='Total Return', color='series')
+ fig1 = px.line(
+ data_frame=df_rtn_long, x="month_end", y="Total Return", color="series"
+ )
return fig1, df_rtn
-# %%
# running solution
df_returns = pd.concat(objs=[df_returns_train, df_returns_test], ignore_index=True)
df_weights_index = equalise_weights(df_returns)
df_returns, df_weights_portfolio = generate_portfolio(df_returns_train, df_returns_test)
-fig1, df_rtn = plot_total_return(df_returns, df_weights_index=df_weights_index, df_weights_portfolio=df_weights_portfolio)
+fig1, df_rtn = plot_total_return(
+ df_returns,
+ df_weights_index=df_weights_index,
+ df_weights_portfolio=df_weights_portfolio,
+)
fig1
From c3b992bc3ddee3c8a5bfc3f55355222adf4f8133 Mon Sep 17 00:00:00 2001
From: terrenceshang <90186971+terrenceshang@users.noreply.github.com>
Date: Sat, 5 Aug 2023 13:54:37 +0200
Subject: [PATCH 2/2] Zenan Shang
---
Challenge - Copy.ipynb | 1066 +++++++---------------------------------
solution_skeleton.py | 3 +
2 files changed, 174 insertions(+), 895 deletions(-)
diff --git a/Challenge - Copy.ipynb b/Challenge - Copy.ipynb
index 66b5857..94a4f6e 100644
--- a/Challenge - Copy.ipynb
+++ b/Challenge - Copy.ipynb
@@ -2,14 +2,14 @@
"cells": [
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "---Python script Start--- 2023-08-05 13:43:56.409716\n"
+ "---Python script Start--- 2023-08-05 13:45:05.658109\n"
]
}
],
@@ -29,380 +29,18 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 14,
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " month_end | \n",
- " Stock1 | \n",
- " Stock10 | \n",
- " Stock11 | \n",
- " Stock14 | \n",
- " Stock16 | \n",
- " Stock18 | \n",
- " Stock19 | \n",
- " Stock20 | \n",
- " Stock21 | \n",
- " ... | \n",
- " Stock78 | \n",
- " Stock79 | \n",
- " Stock80 | \n",
- " Stock81 | \n",
- " Stock84 | \n",
- " Stock85 | \n",
- " Stock86 | \n",
- " Stock87 | \n",
- " Stock88 | \n",
- " Stock9 | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " | 0 | \n",
- " 2010-01-31 | \n",
- " 0.042603 | \n",
- " -0.076059 | \n",
- " -0.149741 | \n",
- " -0.031251 | \n",
- " -0.053032 | \n",
- " -0.113752 | \n",
- " -0.071671 | \n",
- " 0.005430 | \n",
- " 0.005715 | \n",
- " ... | \n",
- " -0.028168 | \n",
- " 0.017445 | \n",
- " -0.100000 | \n",
- " 0.018014 | \n",
- " 0.044749 | \n",
- " 0.016824 | \n",
- " -0.111084 | \n",
- " -0.035229 | \n",
- " -0.033204 | \n",
- " 0.030927 | \n",
- "
\n",
- " \n",
- " | 1 | \n",
- " 2010-02-28 | \n",
- " -0.015034 | \n",
- " -0.100305 | \n",
- " -0.023279 | \n",
- " 0.002484 | \n",
- " 0.077088 | \n",
- " 0.010849 | \n",
- " 0.022383 | \n",
- " 0.095480 | \n",
- " 0.067745 | \n",
- " ... | \n",
- " 0.082448 | \n",
- " -0.106195 | \n",
- " 0.066669 | \n",
- " 0.000556 | \n",
- " -0.010800 | \n",
- " 0.006326 | \n",
- " -0.026405 | \n",
- " -0.013759 | \n",
- " 0.095241 | \n",
- " -0.010000 | \n",
- "
\n",
- " \n",
- " | 2 | \n",
- " 2010-03-31 | \n",
- " 0.111545 | \n",
- " 0.097933 | \n",
- " 0.121501 | \n",
- " 0.064357 | \n",
- " 0.107439 | \n",
- " 0.017883 | \n",
- " 0.000892 | \n",
- " 0.032425 | \n",
- " 0.018012 | \n",
- " ... | \n",
- " 0.036357 | \n",
- " 0.220049 | \n",
- " 0.098957 | \n",
- " 0.088889 | \n",
- " 0.088630 | \n",
- " 0.047296 | \n",
- " 0.153527 | \n",
- " 0.034416 | \n",
- " 0.041795 | \n",
- " 0.024809 | \n",
- "
\n",
- " \n",
- " | 3 | \n",
- " 2010-04-30 | \n",
- " -0.040491 | \n",
- " -0.034262 | \n",
- " -0.032848 | \n",
- " -0.030232 | \n",
- " 0.022388 | \n",
- " 0.085504 | \n",
- " -0.007159 | \n",
- " 0.052763 | \n",
- " 0.017920 | \n",
- " ... | \n",
- " 0.040579 | \n",
- " 0.004259 | \n",
- " -0.052133 | \n",
- " 0.005099 | \n",
- " -0.016164 | \n",
- " 0.012845 | \n",
- " -0.004702 | \n",
- " 0.019786 | \n",
- " 0.042046 | \n",
- " 0.030303 | \n",
- "
\n",
- " \n",
- " | 4 | \n",
- " 2010-05-31 | \n",
- " -0.069359 | \n",
- " -0.073188 | \n",
- " 0.004349 | \n",
- " 0.010792 | \n",
- " -0.025548 | \n",
- " -0.001887 | \n",
- " -0.012534 | \n",
- " 0.068973 | \n",
- " -0.026794 | \n",
- " ... | \n",
- " -0.025069 | \n",
- " -0.062221 | \n",
- " 0.004332 | \n",
- " -0.023857 | \n",
- " -0.085645 | \n",
- " -0.041085 | \n",
- " -0.083320 | \n",
- " 0.095238 | \n",
- " -0.124253 | \n",
- " -0.010784 | \n",
- "
\n",
- " \n",
- " | ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- "
\n",
- " \n",
- " | 87 | \n",
- " 2017-04-30 | \n",
- " 0.057631 | \n",
- " 0.089651 | \n",
- " -0.090908 | \n",
- " -0.045544 | \n",
- " 0.033207 | \n",
- " -0.003331 | \n",
- " 0.036885 | \n",
- " -0.017510 | \n",
- " 0.097012 | \n",
- " ... | \n",
- " 0.039548 | \n",
- " 0.009388 | \n",
- " 0.096569 | \n",
- " 0.086140 | \n",
- " 0.097051 | \n",
- " 0.036655 | \n",
- " -0.059447 | \n",
- " -0.005197 | \n",
- " -0.111087 | \n",
- " 0.044074 | \n",
- "
\n",
- " \n",
- " | 88 | \n",
- " 2017-05-31 | \n",
- " -0.013557 | \n",
- " -0.027089 | \n",
- " -0.050713 | \n",
- " -0.052443 | \n",
- " -0.132316 | \n",
- " -0.013774 | \n",
- " -0.071147 | \n",
- " -0.045192 | \n",
- " -0.031881 | \n",
- " ... | \n",
- " -0.042451 | \n",
- " -0.032799 | \n",
- " 0.069729 | \n",
- " -0.018660 | \n",
- " -0.054422 | \n",
- " 0.071153 | \n",
- " -0.083055 | \n",
- " 0.092917 | \n",
- " -0.039052 | \n",
- " -0.031945 | \n",
- "
\n",
- " \n",
- " | 89 | \n",
- " 2017-06-30 | \n",
- " -0.022060 | \n",
- " -0.098539 | \n",
- " -0.016556 | \n",
- " 0.005218 | \n",
- " -0.008810 | \n",
- " -0.125433 | \n",
- " -0.028937 | \n",
- " 0.069444 | \n",
- " -0.055806 | \n",
- " ... | \n",
- " -0.001562 | \n",
- " -0.055437 | \n",
- " -0.062808 | \n",
- " -0.019475 | \n",
- " 0.034172 | \n",
- " -0.077723 | \n",
- " -0.002616 | \n",
- " 0.020783 | \n",
- " 0.038300 | \n",
- " 0.011196 | \n",
- "
\n",
- " \n",
- " | 90 | \n",
- " 2017-07-31 | \n",
- " 0.036795 | \n",
- " 0.002527 | \n",
- " 0.059680 | \n",
- " 0.074563 | \n",
- " 0.135041 | \n",
- " 0.056864 | \n",
- " 0.038476 | \n",
- " 0.109808 | \n",
- " 0.023922 | \n",
- " ... | \n",
- " 0.096860 | \n",
- " 0.089980 | \n",
- " 0.142830 | \n",
- " 0.001359 | \n",
- " 0.005916 | \n",
- " 0.064159 | \n",
- " 0.234903 | \n",
- " 0.084005 | \n",
- " 0.112443 | \n",
- " 0.027391 | \n",
- "
\n",
- " \n",
- " | 91 | \n",
- " 2017-08-31 | \n",
- " 0.032189 | \n",
- " 0.001031 | \n",
- " 0.101082 | \n",
- " 0.008990 | \n",
- " 0.010417 | \n",
- " -0.035204 | \n",
- " 0.112929 | \n",
- " 0.046901 | \n",
- " 0.082138 | \n",
- " ... | \n",
- " 0.073335 | \n",
- " 0.083564 | \n",
- " 0.011163 | \n",
- " 0.016842 | \n",
- " 0.026141 | \n",
- " 0.022422 | \n",
- " 0.116454 | \n",
- " 0.019769 | \n",
- " 0.171767 | \n",
- " -0.005104 | \n",
- "
\n",
- " \n",
- "
\n",
- "
92 rows × 55 columns
\n",
- "
"
- ],
- "text/plain": [
- " month_end Stock1 Stock10 Stock11 Stock14 Stock16 Stock18 \n",
- "0 2010-01-31 0.042603 -0.076059 -0.149741 -0.031251 -0.053032 -0.113752 \\\n",
- "1 2010-02-28 -0.015034 -0.100305 -0.023279 0.002484 0.077088 0.010849 \n",
- "2 2010-03-31 0.111545 0.097933 0.121501 0.064357 0.107439 0.017883 \n",
- "3 2010-04-30 -0.040491 -0.034262 -0.032848 -0.030232 0.022388 0.085504 \n",
- "4 2010-05-31 -0.069359 -0.073188 0.004349 0.010792 -0.025548 -0.001887 \n",
- ".. ... ... ... ... ... ... ... \n",
- "87 2017-04-30 0.057631 0.089651 -0.090908 -0.045544 0.033207 -0.003331 \n",
- "88 2017-05-31 -0.013557 -0.027089 -0.050713 -0.052443 -0.132316 -0.013774 \n",
- "89 2017-06-30 -0.022060 -0.098539 -0.016556 0.005218 -0.008810 -0.125433 \n",
- "90 2017-07-31 0.036795 0.002527 0.059680 0.074563 0.135041 0.056864 \n",
- "91 2017-08-31 0.032189 0.001031 0.101082 0.008990 0.010417 -0.035204 \n",
- "\n",
- " Stock19 Stock20 Stock21 ... Stock78 Stock79 Stock80 Stock81 \n",
- "0 -0.071671 0.005430 0.005715 ... -0.028168 0.017445 -0.100000 0.018014 \\\n",
- "1 0.022383 0.095480 0.067745 ... 0.082448 -0.106195 0.066669 0.000556 \n",
- "2 0.000892 0.032425 0.018012 ... 0.036357 0.220049 0.098957 0.088889 \n",
- "3 -0.007159 0.052763 0.017920 ... 0.040579 0.004259 -0.052133 0.005099 \n",
- "4 -0.012534 0.068973 -0.026794 ... -0.025069 -0.062221 0.004332 -0.023857 \n",
- ".. ... ... ... ... ... ... ... ... \n",
- "87 0.036885 -0.017510 0.097012 ... 0.039548 0.009388 0.096569 0.086140 \n",
- "88 -0.071147 -0.045192 -0.031881 ... -0.042451 -0.032799 0.069729 -0.018660 \n",
- "89 -0.028937 0.069444 -0.055806 ... -0.001562 -0.055437 -0.062808 -0.019475 \n",
- "90 0.038476 0.109808 0.023922 ... 0.096860 0.089980 0.142830 0.001359 \n",
- "91 0.112929 0.046901 0.082138 ... 0.073335 0.083564 0.011163 0.016842 \n",
- "\n",
- " Stock84 Stock85 Stock86 Stock87 Stock88 Stock9 \n",
- "0 0.044749 0.016824 -0.111084 -0.035229 -0.033204 0.030927 \n",
- "1 -0.010800 0.006326 -0.026405 -0.013759 0.095241 -0.010000 \n",
- "2 0.088630 0.047296 0.153527 0.034416 0.041795 0.024809 \n",
- "3 -0.016164 0.012845 -0.004702 0.019786 0.042046 0.030303 \n",
- "4 -0.085645 -0.041085 -0.083320 0.095238 -0.124253 -0.010784 \n",
- ".. ... ... ... ... ... ... \n",
- "87 0.097051 0.036655 -0.059447 -0.005197 -0.111087 0.044074 \n",
- "88 -0.054422 0.071153 -0.083055 0.092917 -0.039052 -0.031945 \n",
- "89 0.034172 -0.077723 -0.002616 0.020783 0.038300 0.011196 \n",
- "90 0.005916 0.064159 0.234903 0.084005 0.112443 0.027391 \n",
- "91 0.026141 0.022422 0.116454 0.019769 0.171767 -0.005104 \n",
- "\n",
- "[92 rows x 55 columns]"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"df = pd.read_csv(\n",
" \"C:\\\\Users\\\\terre\\OneDrive - University of Cape Town\\\\Terrence\\\\Code\\\\prescient-coding-challenge-2023\\\\data\\\\returns_train.csv\"\n",
- ")\n",
- "display(df)"
+ ")"
]
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
@@ -419,7 +57,7 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 16,
"metadata": {},
"outputs": [
{
@@ -428,367 +66,6 @@
"text": [
"['Stock1', 'Stock10', 'Stock11', 'Stock14', 'Stock16', 'Stock18', 'Stock19', 'Stock20', 'Stock21', 'Stock22', 'Stock26', 'Stock3', 'Stock30', 'Stock31', 'Stock33', 'Stock34', 'Stock35', 'Stock38', 'Stock39', 'Stock4', 'Stock40', 'Stock41', 'Stock43', 'Stock44', 'Stock46', 'Stock47', 'Stock49', 'Stock5', 'Stock50', 'Stock54', 'Stock56', 'Stock59', 'Stock6', 'Stock61', 'Stock63', 'Stock64', 'Stock66', 'Stock69', 'Stock7', 'Stock70', 'Stock73', 'Stock75', 'Stock76', 'Stock77', 'Stock78', 'Stock79', 'Stock80', 'Stock81', 'Stock84', 'Stock85', 'Stock86', 'Stock87', 'Stock88', 'Stock9']\n"
]
- },
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " Stock1 | \n",
- " Stock10 | \n",
- " Stock11 | \n",
- " Stock14 | \n",
- " Stock16 | \n",
- " Stock18 | \n",
- " Stock19 | \n",
- " Stock20 | \n",
- " Stock21 | \n",
- " Stock22 | \n",
- " ... | \n",
- " Stock78 | \n",
- " Stock79 | \n",
- " Stock80 | \n",
- " Stock81 | \n",
- " Stock84 | \n",
- " Stock85 | \n",
- " Stock86 | \n",
- " Stock87 | \n",
- " Stock88 | \n",
- " Stock9 | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " | 0 | \n",
- " 0.042603 | \n",
- " -0.076059 | \n",
- " -0.149741 | \n",
- " -0.031251 | \n",
- " -0.053032 | \n",
- " -0.113752 | \n",
- " -0.071671 | \n",
- " 0.005430 | \n",
- " 0.005715 | \n",
- " 0.001399 | \n",
- " ... | \n",
- " -0.028168 | \n",
- " 0.017445 | \n",
- " -0.100000 | \n",
- " 0.018014 | \n",
- " 0.044749 | \n",
- " 0.016824 | \n",
- " -0.111084 | \n",
- " -0.035229 | \n",
- " -0.033204 | \n",
- " 0.030927 | \n",
- "
\n",
- " \n",
- " | 1 | \n",
- " -0.015034 | \n",
- " -0.100305 | \n",
- " -0.023279 | \n",
- " 0.002484 | \n",
- " 0.077088 | \n",
- " 0.010849 | \n",
- " 0.022383 | \n",
- " 0.095480 | \n",
- " 0.067745 | \n",
- " 0.082493 | \n",
- " ... | \n",
- " 0.082448 | \n",
- " -0.106195 | \n",
- " 0.066669 | \n",
- " 0.000556 | \n",
- " -0.010800 | \n",
- " 0.006326 | \n",
- " -0.026405 | \n",
- " -0.013759 | \n",
- " 0.095241 | \n",
- " -0.010000 | \n",
- "
\n",
- " \n",
- " | 2 | \n",
- " 0.111545 | \n",
- " 0.097933 | \n",
- " 0.121501 | \n",
- " 0.064357 | \n",
- " 0.107439 | \n",
- " 0.017883 | \n",
- " 0.000892 | \n",
- " 0.032425 | \n",
- " 0.018012 | \n",
- " 0.031663 | \n",
- " ... | \n",
- " 0.036357 | \n",
- " 0.220049 | \n",
- " 0.098957 | \n",
- " 0.088889 | \n",
- " 0.088630 | \n",
- " 0.047296 | \n",
- " 0.153527 | \n",
- " 0.034416 | \n",
- " 0.041795 | \n",
- " 0.024809 | \n",
- "
\n",
- " \n",
- " | 3 | \n",
- " -0.040491 | \n",
- " -0.034262 | \n",
- " -0.032848 | \n",
- " -0.030232 | \n",
- " 0.022388 | \n",
- " 0.085504 | \n",
- " -0.007159 | \n",
- " 0.052763 | \n",
- " 0.017920 | \n",
- " 0.007674 | \n",
- " ... | \n",
- " 0.040579 | \n",
- " 0.004259 | \n",
- " -0.052133 | \n",
- " 0.005099 | \n",
- " -0.016164 | \n",
- " 0.012845 | \n",
- " -0.004702 | \n",
- " 0.019786 | \n",
- " 0.042046 | \n",
- " 0.030303 | \n",
- "
\n",
- " \n",
- " | 4 | \n",
- " -0.069359 | \n",
- " -0.073188 | \n",
- " 0.004349 | \n",
- " 0.010792 | \n",
- " -0.025548 | \n",
- " -0.001887 | \n",
- " -0.012534 | \n",
- " 0.068973 | \n",
- " -0.026794 | \n",
- " -0.056697 | \n",
- " ... | \n",
- " -0.025069 | \n",
- " -0.062221 | \n",
- " 0.004332 | \n",
- " -0.023857 | \n",
- " -0.085645 | \n",
- " -0.041085 | \n",
- " -0.083320 | \n",
- " 0.095238 | \n",
- " -0.124253 | \n",
- " -0.010784 | \n",
- "
\n",
- " \n",
- " | ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- "
\n",
- " \n",
- " | 87 | \n",
- " 0.057631 | \n",
- " 0.089651 | \n",
- " -0.090908 | \n",
- " -0.045544 | \n",
- " 0.033207 | \n",
- " -0.003331 | \n",
- " 0.036885 | \n",
- " -0.017510 | \n",
- " 0.097012 | \n",
- " -0.000908 | \n",
- " ... | \n",
- " 0.039548 | \n",
- " 0.009388 | \n",
- " 0.096569 | \n",
- " 0.086140 | \n",
- " 0.097051 | \n",
- " 0.036655 | \n",
- " -0.059447 | \n",
- " -0.005197 | \n",
- " -0.111087 | \n",
- " 0.044074 | \n",
- "
\n",
- " \n",
- " | 88 | \n",
- " -0.013557 | \n",
- " -0.027089 | \n",
- " -0.050713 | \n",
- " -0.052443 | \n",
- " -0.132316 | \n",
- " -0.013774 | \n",
- " -0.071147 | \n",
- " -0.045192 | \n",
- " -0.031881 | \n",
- " -0.000167 | \n",
- " ... | \n",
- " -0.042451 | \n",
- " -0.032799 | \n",
- " 0.069729 | \n",
- " -0.018660 | \n",
- " -0.054422 | \n",
- " 0.071153 | \n",
- " -0.083055 | \n",
- " 0.092917 | \n",
- " -0.039052 | \n",
- " -0.031945 | \n",
- "
\n",
- " \n",
- " | 89 | \n",
- " -0.022060 | \n",
- " -0.098539 | \n",
- " -0.016556 | \n",
- " 0.005218 | \n",
- " -0.008810 | \n",
- " -0.125433 | \n",
- " -0.028937 | \n",
- " 0.069444 | \n",
- " -0.055806 | \n",
- " -0.002845 | \n",
- " ... | \n",
- " -0.001562 | \n",
- " -0.055437 | \n",
- " -0.062808 | \n",
- " -0.019475 | \n",
- " 0.034172 | \n",
- " -0.077723 | \n",
- " -0.002616 | \n",
- " 0.020783 | \n",
- " 0.038300 | \n",
- " 0.011196 | \n",
- "
\n",
- " \n",
- " | 90 | \n",
- " 0.036795 | \n",
- " 0.002527 | \n",
- " 0.059680 | \n",
- " 0.074563 | \n",
- " 0.135041 | \n",
- " 0.056864 | \n",
- " 0.038476 | \n",
- " 0.109808 | \n",
- " 0.023922 | \n",
- " 0.023766 | \n",
- " ... | \n",
- " 0.096860 | \n",
- " 0.089980 | \n",
- " 0.142830 | \n",
- " 0.001359 | \n",
- " 0.005916 | \n",
- " 0.064159 | \n",
- " 0.234903 | \n",
- " 0.084005 | \n",
- " 0.112443 | \n",
- " 0.027391 | \n",
- "
\n",
- " \n",
- " | 91 | \n",
- " 0.032189 | \n",
- " 0.001031 | \n",
- " 0.101082 | \n",
- " 0.008990 | \n",
- " 0.010417 | \n",
- " -0.035204 | \n",
- " 0.112929 | \n",
- " 0.046901 | \n",
- " 0.082138 | \n",
- " -0.010214 | \n",
- " ... | \n",
- " 0.073335 | \n",
- " 0.083564 | \n",
- " 0.011163 | \n",
- " 0.016842 | \n",
- " 0.026141 | \n",
- " 0.022422 | \n",
- " 0.116454 | \n",
- " 0.019769 | \n",
- " 0.171767 | \n",
- " -0.005104 | \n",
- "
\n",
- " \n",
- "
\n",
- "
92 rows × 54 columns
\n",
- "
"
- ],
- "text/plain": [
- " Stock1 Stock10 Stock11 Stock14 Stock16 Stock18 Stock19 \n",
- "0 0.042603 -0.076059 -0.149741 -0.031251 -0.053032 -0.113752 -0.071671 \\\n",
- "1 -0.015034 -0.100305 -0.023279 0.002484 0.077088 0.010849 0.022383 \n",
- "2 0.111545 0.097933 0.121501 0.064357 0.107439 0.017883 0.000892 \n",
- "3 -0.040491 -0.034262 -0.032848 -0.030232 0.022388 0.085504 -0.007159 \n",
- "4 -0.069359 -0.073188 0.004349 0.010792 -0.025548 -0.001887 -0.012534 \n",
- ".. ... ... ... ... ... ... ... \n",
- "87 0.057631 0.089651 -0.090908 -0.045544 0.033207 -0.003331 0.036885 \n",
- "88 -0.013557 -0.027089 -0.050713 -0.052443 -0.132316 -0.013774 -0.071147 \n",
- "89 -0.022060 -0.098539 -0.016556 0.005218 -0.008810 -0.125433 -0.028937 \n",
- "90 0.036795 0.002527 0.059680 0.074563 0.135041 0.056864 0.038476 \n",
- "91 0.032189 0.001031 0.101082 0.008990 0.010417 -0.035204 0.112929 \n",
- "\n",
- " Stock20 Stock21 Stock22 ... Stock78 Stock79 Stock80 Stock81 \n",
- "0 0.005430 0.005715 0.001399 ... -0.028168 0.017445 -0.100000 0.018014 \\\n",
- "1 0.095480 0.067745 0.082493 ... 0.082448 -0.106195 0.066669 0.000556 \n",
- "2 0.032425 0.018012 0.031663 ... 0.036357 0.220049 0.098957 0.088889 \n",
- "3 0.052763 0.017920 0.007674 ... 0.040579 0.004259 -0.052133 0.005099 \n",
- "4 0.068973 -0.026794 -0.056697 ... -0.025069 -0.062221 0.004332 -0.023857 \n",
- ".. ... ... ... ... ... ... ... ... \n",
- "87 -0.017510 0.097012 -0.000908 ... 0.039548 0.009388 0.096569 0.086140 \n",
- "88 -0.045192 -0.031881 -0.000167 ... -0.042451 -0.032799 0.069729 -0.018660 \n",
- "89 0.069444 -0.055806 -0.002845 ... -0.001562 -0.055437 -0.062808 -0.019475 \n",
- "90 0.109808 0.023922 0.023766 ... 0.096860 0.089980 0.142830 0.001359 \n",
- "91 0.046901 0.082138 -0.010214 ... 0.073335 0.083564 0.011163 0.016842 \n",
- "\n",
- " Stock84 Stock85 Stock86 Stock87 Stock88 Stock9 \n",
- "0 0.044749 0.016824 -0.111084 -0.035229 -0.033204 0.030927 \n",
- "1 -0.010800 0.006326 -0.026405 -0.013759 0.095241 -0.010000 \n",
- "2 0.088630 0.047296 0.153527 0.034416 0.041795 0.024809 \n",
- "3 -0.016164 0.012845 -0.004702 0.019786 0.042046 0.030303 \n",
- "4 -0.085645 -0.041085 -0.083320 0.095238 -0.124253 -0.010784 \n",
- ".. ... ... ... ... ... ... \n",
- "87 0.097051 0.036655 -0.059447 -0.005197 -0.111087 0.044074 \n",
- "88 -0.054422 0.071153 -0.083055 0.092917 -0.039052 -0.031945 \n",
- "89 0.034172 -0.077723 -0.002616 0.020783 0.038300 0.011196 \n",
- "90 0.005916 0.064159 0.234903 0.084005 0.112443 0.027391 \n",
- "91 0.026141 0.022422 0.116454 0.019769 0.171767 -0.005104 \n",
- "\n",
- "[92 rows x 54 columns]"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
}
],
"source": [
@@ -805,13 +82,12 @@
" return new_dataframe\n",
"\n",
"\n",
- "clean_df = process_dataframe(df_returns_train)\n",
- "clean_df"
+ "clean_df = process_dataframe(df_returns_train)"
]
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
@@ -845,7 +121,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 18,
"metadata": {},
"outputs": [
{
@@ -853,114 +129,114 @@
"output_type": "stream",
"text": [
"Epoch 1/50\n",
- "2/2 [==============================] - 10s 2s/step - loss: 0.2509 - val_loss: 0.2397\n",
+ "2/2 [==============================] - 9s 2s/step - loss: 0.2450 - val_loss: 0.2347\n",
"Epoch 2/50\n",
- "2/2 [==============================] - 0s 105ms/step - loss: 0.2147 - val_loss: 0.2121\n",
+ "2/2 [==============================] - 0s 105ms/step - loss: 0.2135 - val_loss: 0.1985\n",
"Epoch 3/50\n",
- "2/2 [==============================] - 0s 117ms/step - loss: 0.1903 - val_loss: 0.1808\n",
+ "2/2 [==============================] - 0s 96ms/step - loss: 0.1829 - val_loss: 0.1570\n",
"Epoch 4/50\n",
- "2/2 [==============================] - 0s 96ms/step - loss: 0.1641 - val_loss: 0.1486\n",
+ "2/2 [==============================] - 0s 120ms/step - loss: 0.1517 - val_loss: 0.1229\n",
"Epoch 5/50\n",
- "2/2 [==============================] - 0s 96ms/step - loss: 0.1360 - val_loss: 0.1195\n",
+ "2/2 [==============================] - 0s 112ms/step - loss: 0.1333 - val_loss: 0.1003\n",
"Epoch 6/50\n",
- "2/2 [==============================] - 0s 100ms/step - loss: 0.1208 - val_loss: 0.0971\n",
+ "2/2 [==============================] - 0s 117ms/step - loss: 0.1227 - val_loss: 0.0869\n",
"Epoch 7/50\n",
- "2/2 [==============================] - 0s 100ms/step - loss: 0.1078 - val_loss: 0.0818\n",
+ "2/2 [==============================] - 0s 127ms/step - loss: 0.1106 - val_loss: 0.0791\n",
"Epoch 8/50\n",
- "2/2 [==============================] - 0s 112ms/step - loss: 0.0949 - val_loss: 0.0715\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0945 - val_loss: 0.0737\n",
"Epoch 9/50\n",
- "2/2 [==============================] - 0s 100ms/step - loss: 0.0883 - val_loss: 0.0639\n",
+ "2/2 [==============================] - 0s 101ms/step - loss: 0.0902 - val_loss: 0.0688\n",
"Epoch 10/50\n",
- "2/2 [==============================] - 0s 95ms/step - loss: 0.0831 - val_loss: 0.0575\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0913 - val_loss: 0.0627\n",
"Epoch 11/50\n",
- "2/2 [==============================] - 0s 110ms/step - loss: 0.0875 - val_loss: 0.0530\n",
+ "2/2 [==============================] - 0s 96ms/step - loss: 0.0879 - val_loss: 0.0580\n",
"Epoch 12/50\n",
- "2/2 [==============================] - 0s 103ms/step - loss: 0.0811 - val_loss: 0.0515\n",
+ "2/2 [==============================] - 0s 109ms/step - loss: 0.0801 - val_loss: 0.0553\n",
"Epoch 13/50\n",
- "2/2 [==============================] - 0s 104ms/step - loss: 0.0749 - val_loss: 0.0518\n",
+ "2/2 [==============================] - 0s 116ms/step - loss: 0.0763 - val_loss: 0.0533\n",
"Epoch 14/50\n",
- "2/2 [==============================] - 0s 108ms/step - loss: 0.0713 - val_loss: 0.0506\n",
+ "2/2 [==============================] - 0s 116ms/step - loss: 0.0735 - val_loss: 0.0517\n",
"Epoch 15/50\n",
- "2/2 [==============================] - 0s 100ms/step - loss: 0.0681 - val_loss: 0.0487\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0768 - val_loss: 0.0507\n",
"Epoch 16/50\n",
- "2/2 [==============================] - 0s 98ms/step - loss: 0.0710 - val_loss: 0.0490\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0767 - val_loss: 0.0503\n",
"Epoch 17/50\n",
- "2/2 [==============================] - 0s 108ms/step - loss: 0.0638 - val_loss: 0.0493\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0686 - val_loss: 0.0504\n",
"Epoch 18/50\n",
- "2/2 [==============================] - 0s 108ms/step - loss: 0.0657 - val_loss: 0.0488\n",
+ "2/2 [==============================] - 0s 97ms/step - loss: 0.0700 - val_loss: 0.0505\n",
"Epoch 19/50\n",
- "2/2 [==============================] - 0s 104ms/step - loss: 0.0716 - val_loss: 0.0481\n",
+ "2/2 [==============================] - 0s 101ms/step - loss: 0.0653 - val_loss: 0.0503\n",
"Epoch 20/50\n",
- "2/2 [==============================] - 0s 105ms/step - loss: 0.0637 - val_loss: 0.0471\n",
+ "2/2 [==============================] - 0s 91ms/step - loss: 0.0664 - val_loss: 0.0502\n",
"Epoch 21/50\n",
- "2/2 [==============================] - 0s 105ms/step - loss: 0.0627 - val_loss: 0.0468\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0647 - val_loss: 0.0498\n",
"Epoch 22/50\n",
- "2/2 [==============================] - 0s 102ms/step - loss: 0.0602 - val_loss: 0.0474\n",
+ "2/2 [==============================] - 0s 92ms/step - loss: 0.0640 - val_loss: 0.0490\n",
"Epoch 23/50\n",
- "2/2 [==============================] - 0s 104ms/step - loss: 0.0602 - val_loss: 0.0491\n",
+ "2/2 [==============================] - 0s 103ms/step - loss: 0.0667 - val_loss: 0.0478\n",
"Epoch 24/50\n",
- "2/2 [==============================] - 0s 108ms/step - loss: 0.0628 - val_loss: 0.0494\n",
+ "2/2 [==============================] - 0s 101ms/step - loss: 0.0621 - val_loss: 0.0468\n",
"Epoch 25/50\n",
- "2/2 [==============================] - 0s 97ms/step - loss: 0.0612 - val_loss: 0.0483\n",
+ "2/2 [==============================] - 0s 109ms/step - loss: 0.0646 - val_loss: 0.0470\n",
"Epoch 26/50\n",
- "2/2 [==============================] - 0s 112ms/step - loss: 0.0612 - val_loss: 0.0471\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0616 - val_loss: 0.0481\n",
"Epoch 27/50\n",
- "2/2 [==============================] - 0s 102ms/step - loss: 0.0645 - val_loss: 0.0476\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0628 - val_loss: 0.0501\n",
"Epoch 28/50\n",
- "2/2 [==============================] - 0s 102ms/step - loss: 0.0639 - val_loss: 0.0469\n",
+ "2/2 [==============================] - 0s 105ms/step - loss: 0.0622 - val_loss: 0.0505\n",
"Epoch 29/50\n",
- "2/2 [==============================] - 0s 111ms/step - loss: 0.0590 - val_loss: 0.0468\n",
+ "2/2 [==============================] - 0s 99ms/step - loss: 0.0704 - val_loss: 0.0480\n",
"Epoch 30/50\n",
- "2/2 [==============================] - 0s 112ms/step - loss: 0.0622 - val_loss: 0.0467\n",
+ "2/2 [==============================] - 0s 95ms/step - loss: 0.0595 - val_loss: 0.0460\n",
"Epoch 31/50\n",
- "2/2 [==============================] - 0s 103ms/step - loss: 0.0599 - val_loss: 0.0466\n",
+ "2/2 [==============================] - 0s 109ms/step - loss: 0.0567 - val_loss: 0.0453\n",
"Epoch 32/50\n",
- "2/2 [==============================] - 0s 106ms/step - loss: 0.0624 - val_loss: 0.0470\n",
+ "2/2 [==============================] - 0s 109ms/step - loss: 0.0621 - val_loss: 0.0453\n",
"Epoch 33/50\n",
- "2/2 [==============================] - 0s 109ms/step - loss: 0.0562 - val_loss: 0.0482\n",
+ "2/2 [==============================] - 0s 102ms/step - loss: 0.0590 - val_loss: 0.0460\n",
"Epoch 34/50\n",
- "2/2 [==============================] - 0s 105ms/step - loss: 0.0608 - val_loss: 0.0503\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0606 - val_loss: 0.0487\n",
"Epoch 35/50\n",
- "2/2 [==============================] - 0s 102ms/step - loss: 0.0577 - val_loss: 0.0526\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0588 - val_loss: 0.0516\n",
"Epoch 36/50\n",
- "2/2 [==============================] - 0s 109ms/step - loss: 0.0533 - val_loss: 0.0491\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0599 - val_loss: 0.0497\n",
"Epoch 37/50\n",
- "2/2 [==============================] - 0s 108ms/step - loss: 0.0571 - val_loss: 0.0460\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0608 - val_loss: 0.0468\n",
"Epoch 38/50\n",
- "2/2 [==============================] - 0s 107ms/step - loss: 0.0573 - val_loss: 0.0454\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0551 - val_loss: 0.0456\n",
"Epoch 39/50\n",
- "2/2 [==============================] - 0s 106ms/step - loss: 0.0586 - val_loss: 0.0456\n",
+ "2/2 [==============================] - 0s 97ms/step - loss: 0.0578 - val_loss: 0.0452\n",
"Epoch 40/50\n",
- "2/2 [==============================] - 0s 97ms/step - loss: 0.0576 - val_loss: 0.0463\n",
+ "2/2 [==============================] - 0s 105ms/step - loss: 0.0603 - val_loss: 0.0452\n",
"Epoch 41/50\n",
- "2/2 [==============================] - 0s 104ms/step - loss: 0.0551 - val_loss: 0.0471\n",
+ "2/2 [==============================] - 0s 104ms/step - loss: 0.0609 - val_loss: 0.0454\n",
"Epoch 42/50\n",
- "2/2 [==============================] - 0s 104ms/step - loss: 0.0578 - val_loss: 0.0476\n",
+ "2/2 [==============================] - 0s 103ms/step - loss: 0.0598 - val_loss: 0.0461\n",
"Epoch 43/50\n",
- "2/2 [==============================] - 0s 97ms/step - loss: 0.0584 - val_loss: 0.0464\n",
+ "2/2 [==============================] - 0s 106ms/step - loss: 0.0589 - val_loss: 0.0474\n",
"Epoch 44/50\n",
- "2/2 [==============================] - 0s 100ms/step - loss: 0.0577 - val_loss: 0.0451\n",
+ "2/2 [==============================] - 0s 112ms/step - loss: 0.0555 - val_loss: 0.0498\n",
"Epoch 45/50\n",
- "2/2 [==============================] - 0s 100ms/step - loss: 0.0546 - val_loss: 0.0449\n",
+ "2/2 [==============================] - 0s 92ms/step - loss: 0.0559 - val_loss: 0.0509\n",
"Epoch 46/50\n",
- "2/2 [==============================] - 0s 100ms/step - loss: 0.0561 - val_loss: 0.0454\n",
+ "2/2 [==============================] - 0s 100ms/step - loss: 0.0587 - val_loss: 0.0500\n",
"Epoch 47/50\n",
- "2/2 [==============================] - 0s 108ms/step - loss: 0.0594 - val_loss: 0.0467\n",
+ "2/2 [==============================] - 0s 98ms/step - loss: 0.0595 - val_loss: 0.0484\n",
"Epoch 48/50\n",
- "2/2 [==============================] - 0s 108ms/step - loss: 0.0540 - val_loss: 0.0466\n",
+ "2/2 [==============================] - 0s 108ms/step - loss: 0.0571 - val_loss: 0.0487\n",
"Epoch 49/50\n",
- "2/2 [==============================] - 0s 100ms/step - loss: 0.0555 - val_loss: 0.0464\n",
+ "2/2 [==============================] - 0s 97ms/step - loss: 0.0571 - val_loss: 0.0488\n",
"Epoch 50/50\n",
- "2/2 [==============================] - 0s 93ms/step - loss: 0.0568 - val_loss: 0.0460\n"
+ "2/2 [==============================] - 0s 103ms/step - loss: 0.0598 - val_loss: 0.0485\n"
]
},
{
"data": {
"text/plain": [
- ""
+ ""
]
},
- "execution_count": 9,
+ "execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
@@ -1014,7 +290,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
@@ -1107,7 +383,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
@@ -1170,7 +446,7 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 21,
"metadata": {},
"outputs": [
{
@@ -1179,67 +455,67 @@
"text": [
"---> training set spans 2010-01-31 2017-08-31\n",
"---> training set spans 2017-09-30 2022-09-30\n",
- "1/1 [==============================] - 1s 1s/step\n",
- "1/1 [==============================] - 0s 33ms/step\n",
- "1/1 [==============================] - 0s 27ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 30ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 2s 2s/step\n",
+ "1/1 [==============================] - 0s 40ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 31ms/step\n",
- "1/1 [==============================] - 0s 33ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 34ms/step\n",
+ "1/1 [==============================] - 0s 37ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 45ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 38ms/step\n",
+ "1/1 [==============================] - 0s 40ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 39ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 35ms/step\n",
+ "1/1 [==============================] - 0s 30ms/step\n",
"1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 37ms/step\n",
+ "1/1 [==============================] - 0s 41ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 33ms/step\n",
- "1/1 [==============================] - 0s 34ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 31ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
"1/1 [==============================] - 0s 33ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 44ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 26ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
"1/1 [==============================] - 0s 33ms/step\n",
- "1/1 [==============================] - 0s 29ms/step\n",
- "1/1 [==============================] - 0s 30ms/step\n",
- "1/1 [==============================] - 0s 29ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 33ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
"1/1 [==============================] - 0s 31ms/step\n",
+ "1/1 [==============================] - 0s 35ms/step\n",
+ "1/1 [==============================] - 0s 35ms/step\n",
+ "1/1 [==============================] - 0s 34ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 35ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 33ms/step\n",
+ "1/1 [==============================] - 0s 34ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 36ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 27ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 31ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 37ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
"1/1 [==============================] - 0s 36ms/step\n",
- "1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 33ms/step\n",
- "1/1 [==============================] - 0s 31ms/step\n",
- "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 39ms/step\n",
"1/1 [==============================] - 0s 36ms/step\n",
+ "1/1 [==============================] - 0s 40ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 35ms/step\n",
+ "1/1 [==============================] - 0s 28ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 37ms/step\n",
"1/1 [==============================] - 0s 32ms/step\n",
- "1/1 [==============================] - 0s 29ms/step\n"
+ "1/1 [==============================] - 0s 32ms/step\n",
+ "1/1 [==============================] - 0s 29ms/step\n",
+ "1/1 [==============================] - 0s 92ms/step\n"
]
},
{
@@ -1841,67 +1117,67 @@
278.34458913811073,
293.49195242698454,
302.7447105318491,
- 291.81297808172434,
- 309.10626996662864,
- 317.93151464087606,
- 316.6340106209101,
- 315.6415940400645,
- 306.9990052206068,
- 288.99117695611534,
- 297.8908567145109,
- 271.40585926689664,
- 270.4620400595724,
- 285.3018763187234,
- 283.9997975387666,
- 282.3058534912338,
- 282.8168081839594,
- 278.16168529764997,
- 291.8389991142531,
- 300.6581473947394,
- 311.92051019766234,
- 301.82806882343345,
- 306.22837025547545,
- 300.3526848452781,
- 316.38453460148776,
- 304.12513571919254,
- 300.04769585835874,
- 296.0351715215138,
- 310.85006622435736,
- 302.69789270338794,
- 310.1422986996012,
- 297.82505214543795,
- 269.1808516515679,
- 210.10671693995008,
- 253.26534288438398,
- 247.6935163444137,
- 281.9952379928254,
- 289.24786169036423,
- 281.9380660561305,
- 278.33650157223,
- 266.88642285113906,
- 308.0500163369409,
- 344.0453446329626,
- 378.91887117526875,
- 412.92074334641126,
- 445.0244159795605,
- 470.3391193740556,
- 492.58036311326003,
- 474.47257453624434,
- 498.92778402772774,
- 532.832242306276,
- 536.4466618709841,
- 549.1603759815245,
- 562.5357729617074,
- 622.2389260616599,
- 634.3166868960342,
- 638.2339235013269,
- 658.1326681390495,
- 616.1023879730394,
- 607.1833690205967,
- 552.4377707205268,
- 577.9142474664799,
- 559.3520550083838,
- 546.2490099454914
+ 291.81447239388893,
+ 308.7977586581792,
+ 317.46640467209306,
+ 315.980565008889,
+ 315.17931083241166,
+ 306.5477692742863,
+ 288.40980922995055,
+ 297.170071544132,
+ 270.633374974646,
+ 269.6388932710465,
+ 284.41860050083585,
+ 282.9270799109806,
+ 280.95760560937583,
+ 281.4385654325379,
+ 276.84088762582905,
+ 290.3424196043114,
+ 299.03272616079323,
+ 310.09030552319416,
+ 299.9343063556587,
+ 304.28861170233637,
+ 298.51836535718417,
+ 314.30109394554137,
+ 302.15817828592753,
+ 297.85961950688727,
+ 293.81205231426037,
+ 308.5001351912185,
+ 300.4854063001455,
+ 307.7659838198207,
+ 295.66474834398684,
+ 267.56228891731695,
+ 208.70302217050755,
+ 251.59548311327993,
+ 246.08365459547525,
+ 280.4480052539967,
+ 287.68621870949613,
+ 280.36611883863156,
+ 276.8989957223652,
+ 265.30743125700576,
+ 306.17412151924503,
+ 341.61536683363937,
+ 376.77794483038076,
+ 410.6183513249361,
+ 442.736848162654,
+ 467.70631568237746,
+ 489.4961534170436,
+ 471.7811090467055,
+ 495.75721153606116,
+ 530.232647687731,
+ 534.3392603616905,
+ 546.8094508585345,
+ 560.036164610925,
+ 619.8281330411401,
+ 632.1136715947626,
+ 635.7435405146244,
+ 655.6112545518024,
+ 613.9870246720898,
+ 605.2064966770056,
+ 550.9149051677855,
+ 576.2396043068396,
+ 557.3222873353085,
+ 544.2583292772424
],
"yaxis": "y"
}
diff --git a/solution_skeleton.py b/solution_skeleton.py
index 6957fff..ee39af2 100644
--- a/solution_skeleton.py
+++ b/solution_skeleton.py
@@ -1,3 +1,5 @@
+# %%
+
import numpy as np
import pandas as pd
import datetime
@@ -267,4 +269,5 @@ def plot_total_return(
df_weights_index=df_weights_index,
df_weights_portfolio=df_weights_portfolio,
)
+
fig1