├── .DS_Store ├── .ipynb_checkpoints ├── Custom Portfolio test-checkpoint.ipynb ├── Debugging HRP-checkpoint.ipynb ├── Optimization and ML benchmark | Cryptocurrency-checkpoint.ipynb ├── Optimization and ML benchmark | ETF-checkpoint.ipynb └── Reinforcement Learning-checkpoint.ipynb ├── Debugging HRP.ipynb ├── Optimization and ML benchmark | Cryptocurrency.ipynb ├── Optimization and ML benchmark | ETF.ipynb ├── README.md ├── Reinforcement Learning.ipynb ├── __pycache__ ├── agent.cpython-36.pyc ├── environment.cpython-36.pyc ├── hrp_routines.cpython-36.pyc └── utils.cpython-36.pyc ├── agent.py ├── data ├── crypto_portfolio.csv ├── data.csv ├── portfolio.csv ├── prices.txt ├── returns.txt └── volumes.txt ├── environment.py ├── hrp_routines.py └── utils.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rachnog/Deep-Portfolio-Management/07154e391309f7e7e8045efb23bd6eb422aad53d/.DS_Store -------------------------------------------------------------------------------- /.ipynb_checkpoints/Custom Portfolio test-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 2 6 | } 7 | -------------------------------------------------------------------------------- /.ipynb_checkpoints/Debugging HRP-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 13, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import warnings\n", 10 | "warnings.filterwarnings('ignore')\n", 11 | "\n", 12 | "import numpy as np\n", 13 | "import pandas as pd\n", 14 | "import os\n", 15 | "\n", 16 | "import random\n", 17 | "import matplotlib.pylab as plt" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 14, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "from environment import ETFEnvironment, CryptoEnvironment\n", 27 | "from utils import *" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 65, 33 | "metadata": { 34 | "scrolled": true 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "N_ASSETS = 26 # 53\n", 39 | "WINDOW_FIT = 30\n", 40 | "WINDOW_HOLD = 7\n", 41 | "env = CryptoEnvironment('./data/portfolio.csv') # ETFEnvironment" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 66, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "from agent import HRPAgent, SmoothingAgent" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 67, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "agent_hrp = SmoothingAgent(N_ASSETS, allow_short=True)\n", 60 | "agent_smooth = HRPAgent(N_ASSETS, allow_short=True)" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 68, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "actions_equal, actions_hrp, actions_smooth = [], [], []\n", 70 | "result_equal, result_hrp, result_smooth = [], [], []\n", 71 | "\n", 72 | "for i in range(WINDOW_FIT, len(env.data), WINDOW_HOLD):\n", 73 | " \n", 74 | " state = env.get_state(i, WINDOW_FIT, is_cov_matrix=False)\n", 75 | " \n", 76 | " action_equal = np.ones(N_ASSETS) / N_ASSETS\n", 77 | " action_hrp = agent_hrp.act(state)\n", 78 | " action_smooth = agent_smooth.act(state)\n", 79 | "\n", 80 | " state_action = env.get_state(i+WINDOW_HOLD, WINDOW_HOLD, is_cov_matrix=False)\n", 81 | " \n", 82 | " r = np.dot(state_action, action_equal)\n", 83 | " result_equal.append(r.tolist())\n", 84 | " actions_equal.append(action_equal)\n", 85 | " \n", 86 | " r = np.dot(state_action, action_hrp)\n", 87 | " result_hrp.append(r.tolist())\n", 88 | " actions_hrp.append(action_hrp)\n", 89 | " \n", 90 | " r = np.dot(state_action, action_smooth)\n", 91 | " result_smooth.append(r.tolist())\n", 92 | " actions_smooth.append(action_smooth)" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 69, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "result_equal_vis = [item for sublist in result_equal for item in sublist]\n", 102 | "result_hrp_vis = [item for sublist in result_hrp for item in sublist]\n", 103 | "result_smooth_vis = [item for sublist in result_smooth for item in sublist]" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 73, 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "data": { 113 | "image/png": "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\n", 114 | "text/plain": [ 115 | "
" 116 | ] 117 | }, 118 | "metadata": {}, 119 | "output_type": "display_data" 120 | } 121 | ], 122 | "source": [ 123 | "plt.figure(figsize = (12, 3))\n", 124 | "plt.plot(np.array(result_equal_vis).cumsum(), label = 'Benchmark', color = 'black')\n", 125 | "plt.plot(np.array(result_hrp_vis).cumsum(), label = 'HRP', color = 'red')\n", 126 | "# plt.plot(np.array(result_smooth_vis).cumsum(), label = 'Forecasting', color = 'blue')\n", 127 | "plt.legend()\n", 128 | "plt.show()" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 74, 134 | "metadata": { 135 | "scrolled": true 136 | }, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "2.6832722188103326\n", 143 | "-0.6466666029275073\n" 144 | ] 145 | } 146 | ], 147 | "source": [ 148 | "print(sharpe(np.array(result_equal_vis).cumsum()))\n", 149 | "print(sharpe(np.array(result_hrp_vis).cumsum()))\n", 150 | "# print(sharpe(np.array(result_smooth_vis).cumsum()))" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 75, 156 | "metadata": { 157 | "scrolled": false 158 | }, 159 | "outputs": [ 160 | { 161 | "data": { 162 | "image/png": "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\n", 163 | "text/plain": [ 164 | "
" 165 | ] 166 | }, 167 | "metadata": {}, 168 | "output_type": "display_data" 169 | } 170 | ], 171 | "source": [ 172 | "plt.figure(figsize = (12, 3))\n", 173 | "for a in actions_hrp: \n", 174 | " plt.bar(np.arange(N_ASSETS), a, color = 'grey', alpha = 0.25)\n", 175 | " plt.xticks(np.arange(N_ASSETS), env.data.columns, rotation='vertical')\n", 176 | "plt.show()" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": null, 182 | "metadata": {}, 183 | "outputs": [], 184 | "source": [] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": null, 196 | "metadata": {}, 197 | "outputs": [], 198 | "source": [] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": null, 203 | "metadata": {}, 204 | "outputs": [], 205 | "source": [] 206 | } 207 | ], 208 | "metadata": { 209 | "kernelspec": { 210 | "display_name": "Python 3", 211 | "language": "python", 212 | "name": "python3" 213 | }, 214 | "language_info": { 215 | "codemirror_mode": { 216 | "name": "ipython", 217 | "version": 3 218 | }, 219 | "file_extension": ".py", 220 | "mimetype": "text/x-python", 221 | "name": "python", 222 | "nbconvert_exporter": "python", 223 | "pygments_lexer": "ipython3", 224 | "version": "3.6.5" 225 | } 226 | }, 227 | "nbformat": 4, 228 | "nbformat_minor": 2 229 | } 230 | -------------------------------------------------------------------------------- /Debugging HRP.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 13, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import warnings\n", 10 | "warnings.filterwarnings('ignore')\n", 11 | "\n", 12 | "import numpy as np\n", 13 | "import pandas as pd\n", 14 | "import os\n", 15 | "\n", 16 | "import random\n", 17 | "import matplotlib.pylab as plt" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 14, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "from environment import ETFEnvironment, CryptoEnvironment\n", 27 | "from utils import *" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 65, 33 | "metadata": { 34 | "scrolled": true 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "N_ASSETS = 26 # 53\n", 39 | "WINDOW_FIT = 30\n", 40 | "WINDOW_HOLD = 7\n", 41 | "env = CryptoEnvironment('./data/portfolio.csv') # ETFEnvironment" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 66, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "from agent import HRPAgent, SmoothingAgent" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 67, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "agent_hrp = SmoothingAgent(N_ASSETS, allow_short=True)\n", 60 | "agent_smooth = HRPAgent(N_ASSETS, allow_short=True)" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 68, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "actions_equal, actions_hrp, actions_smooth = [], [], []\n", 70 | "result_equal, result_hrp, result_smooth = [], [], []\n", 71 | "\n", 72 | "for i in range(WINDOW_FIT, len(env.data), WINDOW_HOLD):\n", 73 | " \n", 74 | " state = env.get_state(i, WINDOW_FIT, is_cov_matrix=False)\n", 75 | " \n", 76 | " action_equal = np.ones(N_ASSETS) / N_ASSETS\n", 77 | " action_hrp = agent_hrp.act(state)\n", 78 | " action_smooth = agent_smooth.act(state)\n", 79 | "\n", 80 | " state_action = env.get_state(i+WINDOW_HOLD, WINDOW_HOLD, is_cov_matrix=False)\n", 81 | " \n", 82 | " r = np.dot(state_action, action_equal)\n", 83 | " result_equal.append(r.tolist())\n", 84 | " actions_equal.append(action_equal)\n", 85 | " \n", 86 | " r = np.dot(state_action, action_hrp)\n", 87 | " result_hrp.append(r.tolist())\n", 88 | " actions_hrp.append(action_hrp)\n", 89 | " \n", 90 | " r = np.dot(state_action, action_smooth)\n", 91 | " result_smooth.append(r.tolist())\n", 92 | " actions_smooth.append(action_smooth)" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 69, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "result_equal_vis = [item for sublist in result_equal for item in sublist]\n", 102 | "result_hrp_vis = [item for sublist in result_hrp for item in sublist]\n", 103 | "result_smooth_vis = [item for sublist in result_smooth for item in sublist]" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 73, 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "data": { 113 | "image/png": "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\n", 114 | "text/plain": [ 115 | "
" 116 | ] 117 | }, 118 | "metadata": {}, 119 | "output_type": "display_data" 120 | } 121 | ], 122 | "source": [ 123 | "plt.figure(figsize = (12, 3))\n", 124 | "plt.plot(np.array(result_equal_vis).cumsum(), label = 'Benchmark', color = 'black')\n", 125 | "plt.plot(np.array(result_hrp_vis).cumsum(), label = 'HRP', color = 'red')\n", 126 | "# plt.plot(np.array(result_smooth_vis).cumsum(), label = 'Forecasting', color = 'blue')\n", 127 | "plt.legend()\n", 128 | "plt.show()" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 74, 134 | "metadata": { 135 | "scrolled": true 136 | }, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "2.6832722188103326\n", 143 | "-0.6466666029275073\n" 144 | ] 145 | } 146 | ], 147 | "source": [ 148 | "print(sharpe(np.array(result_equal_vis).cumsum()))\n", 149 | "print(sharpe(np.array(result_hrp_vis).cumsum()))\n", 150 | "# print(sharpe(np.array(result_smooth_vis).cumsum()))" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 75, 156 | "metadata": { 157 | "scrolled": false 158 | }, 159 | "outputs": [ 160 | { 161 | "data": { 162 | "image/png": "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\n", 163 | "text/plain": [ 164 | "
" 165 | ] 166 | }, 167 | "metadata": {}, 168 | "output_type": "display_data" 169 | } 170 | ], 171 | "source": [ 172 | "plt.figure(figsize = (12, 3))\n", 173 | "for a in actions_hrp: \n", 174 | " plt.bar(np.arange(N_ASSETS), a, color = 'grey', alpha = 0.25)\n", 175 | " plt.xticks(np.arange(N_ASSETS), env.data.columns, rotation='vertical')\n", 176 | "plt.show()" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": null, 182 | "metadata": {}, 183 | "outputs": [], 184 | "source": [] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": null, 196 | "metadata": {}, 197 | "outputs": [], 198 | "source": [] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": null, 203 | "metadata": {}, 204 | "outputs": [], 205 | "source": [] 206 | } 207 | ], 208 | "metadata": { 209 | "kernelspec": { 210 | "display_name": "Python 3", 211 | "language": "python", 212 | "name": "python3" 213 | }, 214 | "language_info": { 215 | "codemirror_mode": { 216 | "name": "ipython", 217 | "version": 3 218 | }, 219 | "file_extension": ".py", 220 | "mimetype": "text/x-python", 221 | "name": "python", 222 | "nbconvert_exporter": "python", 223 | "pygments_lexer": "ipython3", 224 | "version": "3.6.5" 225 | } 226 | }, 227 | "nbformat": 4, 228 | "nbformat_minor": 2 229 | } 230 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deep-Portfolio-Management 2 | 3 | Experiments on portfolio management and asset allocations algorithms as: 4 | 5 | 1) Classic optimization (Markowitz, Inverse Risk etc) 6 | 2) PCA portfolios 7 | 3) Autoencoder portfolios 8 | 4) Hierarchical risk parity 9 | 5) Forecasting-based portfolios 10 | 6) Reinforcement learning portfolios 11 | -------------------------------------------------------------------------------- /__pycache__/agent.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rachnog/Deep-Portfolio-Management/07154e391309f7e7e8045efb23bd6eb422aad53d/__pycache__/agent.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/environment.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rachnog/Deep-Portfolio-Management/07154e391309f7e7e8045efb23bd6eb422aad53d/__pycache__/environment.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/hrp_routines.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rachnog/Deep-Portfolio-Management/07154e391309f7e7e8045efb23bd6eb422aad53d/__pycache__/hrp_routines.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/utils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rachnog/Deep-Portfolio-Management/07154e391309f7e7e8045efb23bd6eb422aad53d/__pycache__/utils.cpython-36.pyc -------------------------------------------------------------------------------- /agent.py: -------------------------------------------------------------------------------- 1 | import scipy.optimize as sco 2 | from sklearn.decomposition import PCA 3 | import pandas as pd 4 | import numpy as np 5 | 6 | from keras.layers import Input, Dense 7 | from keras.models import Model 8 | from keras import regularizers 9 | from keras.models import load_model 10 | 11 | from statsmodels.tsa.api import ExponentialSmoothing, SimpleExpSmoothing, Holt 12 | from utils import portfolio 13 | 14 | from hrp_routines import * 15 | 16 | class HRPAgent: 17 | 18 | def __init__( 19 | self, 20 | portfolio_size, 21 | allow_short = True, 22 | ): 23 | 24 | self.portfolio_size = portfolio_size 25 | self.allow_short = allow_short 26 | self.input_shape = (portfolio_size, portfolio_size, ) 27 | 28 | def act(self, returns): 29 | 30 | corr = returns.corr() 31 | cov = returns.cov() 32 | optimal_weights = getHRP(cov, corr) 33 | 34 | if self.allow_short: 35 | optimal_weights /= sum(np.abs(optimal_weights)) 36 | else: 37 | optimal_weights += np.abs(np.min(optimal_weights)) 38 | optimal_weights /= sum(optimal_weights) 39 | 40 | return optimal_weights 41 | 42 | class AutoencoderAgent: 43 | 44 | def __init__( 45 | self, 46 | portfolio_size, 47 | allow_short = True, 48 | encoding_dim = 25 49 | ): 50 | 51 | self.portfolio_size = portfolio_size 52 | self.allow_short = allow_short 53 | self.encoding_dim = encoding_dim 54 | 55 | 56 | def model(self): 57 | input_img = Input(shape=(self.portfolio_size, )) 58 | encoded = Dense(self.encoding_dim, activation='relu', kernel_regularizer=regularizers.l2(1e-6))(input_img) 59 | decoded = Dense(self.portfolio_size, activation= 'linear', kernel_regularizer=regularizers.l2(1e-6))(encoded) 60 | autoencoder = Model(input_img, decoded) 61 | autoencoder.compile(optimizer='adam', loss='mse') 62 | return autoencoder 63 | 64 | 65 | def act(self, returns): 66 | data = returns 67 | autoencoder = self.model() 68 | autoencoder.fit(data, data, shuffle=False, epochs=25, batch_size=32, verbose=False) 69 | reconstruct = autoencoder.predict(data) 70 | 71 | communal_information = [] 72 | 73 | for i in range(0, len(returns.columns)): 74 | diff = np.linalg.norm((returns.iloc[:,i] - reconstruct[:,i])) # 2 norm difference 75 | communal_information.append(float(diff)) 76 | 77 | optimal_weights = np.array(communal_information) / sum(communal_information) 78 | 79 | if self.allow_short: 80 | optimal_weights /= sum(np.abs(optimal_weights)) 81 | else: 82 | optimal_weights += np.abs(np.min(optimal_weights)) 83 | optimal_weights /= sum(optimal_weights) 84 | 85 | return optimal_weights 86 | 87 | class SmoothingAgent: 88 | 89 | def __init__( 90 | self, 91 | portfolio_size, 92 | allow_short = True, 93 | forecast_horizon = 252, 94 | ): 95 | 96 | self.portfolio_size = portfolio_size 97 | self.allow_short = allow_short 98 | self.forecast_horizon = forecast_horizon 99 | 100 | def act(self, timeseries): 101 | 102 | optimal_weights = [] 103 | 104 | for asset in timeseries.columns: 105 | ts = timeseries[asset] 106 | fit1 = Holt(ts).fit() 107 | forecast = fit1.forecast(self.forecast_horizon) 108 | prediction = forecast.values[-1] - forecast.values[0] 109 | optimal_weights.append(prediction) 110 | 111 | if self.allow_short: 112 | optimal_weights /= sum(np.abs(optimal_weights)) 113 | else: 114 | optimal_weights += np.abs(np.min(optimal_weights)) 115 | optimal_weights /= sum(optimal_weights) 116 | 117 | return optimal_weights 118 | 119 | class PCAAgent: 120 | 121 | 122 | def __init__( 123 | self, 124 | portfolio_size, 125 | pc_id = 0, 126 | pca_max = 10, 127 | allow_short = False, 128 | ): 129 | 130 | self.portfolio_size = portfolio_size 131 | self.allow_short = allow_short 132 | self.input_shape = (portfolio_size, portfolio_size, ) 133 | self.pc_id = pc_id 134 | self.pc_max = pca_max 135 | 136 | def act(self, returns): 137 | C = self.pc_max 138 | pca = PCA(C) 139 | returns_pca = pca.fit_transform(returns) 140 | pcs = pca.components_ 141 | 142 | pc1 = pcs[self.pc_id, :] 143 | 144 | if self.allow_short: 145 | optimal_weights = pc1 / sum(np.abs(pc1)) 146 | else: 147 | optimal_weights += np.abs(np.min(optimal_weights)) 148 | optimal_weights /= sum(optimal_weights) 149 | 150 | return optimal_weights 151 | 152 | class MaxReturnsAgent: 153 | 154 | def __init__( 155 | self, 156 | portfolio_size, 157 | allow_short = False, 158 | ): 159 | 160 | self.portfolio_size = portfolio_size 161 | self.allow_short = allow_short 162 | self.input_shape = (portfolio_size, portfolio_size, ) 163 | 164 | 165 | def act(self, returns): 166 | 167 | def loss(weights): 168 | return -portfolio(returns, weights)[0] 169 | 170 | n_assets = len(returns.columns) 171 | 172 | if self.allow_short: 173 | bnds = tuple((-1.0, 1.0) for x in range(n_assets)) 174 | cons =({'type': 'eq', 'fun': lambda x : 1.0 - np.sum(np.abs(x))}) 175 | else: 176 | bnds = tuple((0.0, 1.0) for x in range(n_assets)) 177 | cons =({'type': 'eq', 'fun': lambda x : 1.0 - np.sum(x)}) 178 | 179 | 180 | opt_S = sco.minimize( 181 | loss, 182 | n_assets * [1.0 / n_assets], 183 | method = 'SLSQP', bounds = bnds, 184 | constraints = cons) 185 | 186 | optimal_weights = opt_S['x'] 187 | 188 | # sometimes optimization fails with constraints, need to be fixed by hands 189 | if self.allow_short: 190 | optimal_weights /= sum(np.abs(optimal_weights)) 191 | else: 192 | optimal_weights += np.abs(np.min(optimal_weights)) 193 | optimal_weights /= sum(optimal_weights) 194 | 195 | return optimal_weights 196 | 197 | class MinVarianceAgent: 198 | 199 | def __init__( 200 | self, 201 | portfolio_size, 202 | allow_short = False, 203 | ): 204 | 205 | self.portfolio_size = portfolio_size 206 | self.allow_short = allow_short 207 | self.input_shape = (portfolio_size, portfolio_size, ) 208 | 209 | 210 | def act(self, returns): 211 | 212 | def loss(weights): 213 | return portfolio(returns, weights)[1]**2 214 | 215 | n_assets = len(returns.columns) 216 | 217 | if self.allow_short: 218 | bnds = tuple((-1.0, 1.0) for x in range(n_assets)) 219 | cons =({'type': 'eq', 'fun': lambda x : 1.0 - np.sum(np.abs(x))}) 220 | else: 221 | bnds = tuple((0.0, 1.0) for x in range(n_assets)) 222 | cons =({'type': 'eq', 'fun': lambda x : 1.0 - np.sum(x)}) 223 | 224 | 225 | opt_S = sco.minimize( 226 | loss, 227 | n_assets * [1.0 / n_assets], 228 | method = 'SLSQP', bounds = bnds, 229 | constraints = cons) 230 | 231 | optimal_weights = opt_S['x'] 232 | 233 | # sometimes optimization fails with constraints, need to be fixed by hands 234 | if self.allow_short: 235 | optimal_weights /= sum(np.abs(optimal_weights)) 236 | else: 237 | optimal_weights += np.abs(np.min(optimal_weights)) 238 | optimal_weights /= sum(optimal_weights) 239 | 240 | return optimal_weights 241 | 242 | 243 | class MaxSharpeAgent: 244 | 245 | def __init__( 246 | self, 247 | portfolio_size, 248 | allow_short = False, 249 | ): 250 | 251 | self.portfolio_size = portfolio_size 252 | self.allow_short = allow_short 253 | self.input_shape = (portfolio_size, portfolio_size, ) 254 | 255 | 256 | def act(self, returns): 257 | 258 | def loss(weights): 259 | return -portfolio(returns, weights)[2] 260 | 261 | n_assets = len(returns.columns) 262 | 263 | if self.allow_short: 264 | bnds = tuple((-1.0, 1.0) for x in range(n_assets)) 265 | cons =({'type': 'eq', 'fun': lambda x : 1.0 - np.sum(np.abs(x))}) 266 | else: 267 | bnds = tuple((0.0, 1.0) for x in range(n_assets)) 268 | cons =({'type': 'eq', 'fun': lambda x : 1.0 - np.sum(x)}) 269 | 270 | 271 | opt_S = sco.minimize( 272 | loss, 273 | n_assets * [1.0 / n_assets], 274 | method = 'SLSQP', bounds = bnds, 275 | constraints = cons) 276 | 277 | optimal_weights = opt_S['x'] 278 | 279 | # sometimes optimization fails with constraints, need to be fixed by hands 280 | if self.allow_short: 281 | optimal_weights /= sum(np.abs(optimal_weights)) 282 | else: 283 | optimal_weights += np.abs(np.min(optimal_weights)) 284 | optimal_weights /= sum(optimal_weights) 285 | 286 | return optimal_weights 287 | 288 | 289 | class MaxDecorrelationAgent: 290 | 291 | def __init__( 292 | self, 293 | portfolio_size, 294 | allow_short = False, 295 | ): 296 | 297 | self.portfolio_size = portfolio_size 298 | self.allow_short = allow_short 299 | self.input_shape = (portfolio_size, portfolio_size, ) 300 | 301 | 302 | def act(self, returns): 303 | 304 | def loss(weights): 305 | weights = np.array(weights) 306 | return np.sqrt(np.dot(weights.T, np.dot(returns.corr(), weights))) 307 | 308 | n_assets = len(returns.columns) 309 | 310 | if self.allow_short: 311 | bnds = tuple((-1.0, 1.0) for x in range(n_assets)) 312 | cons =({'type': 'eq', 'fun': lambda x : 1.0 - np.sum(np.abs(x))}) 313 | else: 314 | bnds = tuple((0.0, 1.0) for x in range(n_assets)) 315 | cons =({'type': 'eq', 'fun': lambda x : 1.0 - np.sum(x)}) 316 | 317 | 318 | opt_S = sco.minimize( 319 | loss, 320 | n_assets * [1.0 / n_assets], 321 | method = 'SLSQP', bounds = bnds, 322 | constraints = cons) 323 | 324 | optimal_weights = opt_S['x'] 325 | 326 | # sometimes optimization fails with constraints, need to be fixed by hands 327 | if self.allow_short: 328 | optimal_weights /= sum(np.abs(optimal_weights)) 329 | else: 330 | optimal_weights += np.abs(np.min(optimal_weights)) 331 | optimal_weights /= sum(optimal_weights) 332 | 333 | return optimal_weights -------------------------------------------------------------------------------- /data/portfolio.csv: -------------------------------------------------------------------------------- 1 | date,AAPL,AMZN,BAC,CBF,DIS,FB,FL,GE,GM,GOOGL,IBM,MCD,MSFT,NFLX,NKE,NVDA,SBUX,TSLA,TSN,TWTR,TWX,UA,WWE,BTC,ETH,XRP 2 | 2017-05-19,152.34188069275,959.84,22.858201952615,37.282727985367,106.71460674157,148.06,57.775215012294,27.543057770198,32.032108817056,954.65,148.90648308041,146.37924465211,66.992286485551,157.02,51.417182555585,135.8829388257,60.75844640266,310.83,58.124191445161,18.35,96.473561183015,17.86,19.442111277587,1970.0,125.79,0.318 3 | 2017-05-22,153.36771840924,970.7,22.84828516218,37.482100862294,106.82378277154,148.24,59.300276035269,27.670708305318,32.227904103224,964.07,149.5531357902,146.41876655414,67.744452798582,157.16,51.218545574493,138.78044266831,60.62972088062,310.35,58.005084495478,18.43,96.740363001303,17.92,19.58055967936,1981.9,137.0,0.28001 4 | 2017-05-23,153.17848620911,971.54,23.195372827404,37.731316958453,106.21835205993,148.07,58.906711900307,27.768901024642,32.521597032476,970.55,148.95547192206,146.05318896034,67.972082077525,157.95,51.844252064932,136.91205225945,60.55050517475,303.86,57.985233337198,18.15,97.066454112543,18.04,19.541002993139,2228.0,167.02,0.3209 5 | 2017-05-24,152.72034509301,980.35,23.165622456099,37.482100862294,106.9031835206,150.04,58.670573419331,27.327033787687,32.502017503859,977.61,149.42576480191,147.7131088457,68.061154404068,157.75,51.655546932895,138.4507267138,61.283250454052,310.22,57.995158916338,17.98,97.234440442576,18.11,19.531113821584,2379.6,188.24,0.29187 6 | 2017-05-25,153.24820333547,993.38,23.056537761314,37.531944081526,106.46647940075,151.96,58.700090729453,26.993178541987,31.914631645355,991.86,150.10181081668,147.98976215992,68.902393043641,163.05,51.99322980075,138.14099354442,62.283348740667,316.83,57.667614804711,17.95,98.192950678646,18.01,19.689340566468,2377.0,177.09,0.25162 7 | 2017-05-26,152.98925400898,995.78,23.046620970879,37.282727985367,107.59794007491,152.13,58.857516383437,26.953901454258,32.37475056785,993.27,149.40616926524,148.06880596399,69.248785424642,162.43,52.231594178061,141.71791208116,62.679427270019,325.14,57.905828704076,18.23,98.294730631549,18.07,19.689340566468,2113.2,152.68,0.25375 8 | 2017-05-30,153.04901154586,996.7,22.719366886525,37.08335510844,107.52846441948,152.38,58.700090729453,26.865528006867,32.825079726036,996.17,148.66153887216,148.13796929254,69.684250132186,163.22,52.559345196862,144.74530402705,62.62991745385,335.1,57.732131069122,18.43,98.165747942722,18.01,19.808010625131,2106.0,220.08,0.19819 9 | 2017-05-31,152.14268890314,994.62,22.297903293039,36.983668669976,107.13146067416,151.46,58.454113145102,26.885166550732,33.216670298371,987.09,149.54333802187,149.08649494132,69.120125397413,163.07,52.628868140244,144.22575161389,62.986388130267,341.01,57.134283664195,18.32,98.711443933913,17.83,20.18379914423,2195.6,218.65,0.23316 10 | 2017-06-01,152.56099166132,995.95,22.516802834514,37.681473739221,107.39943820225,151.53,58.404917628232,27.219021796431,33.706158513791,988.29,149.58252909519,151.49733096529,69.377445451871,162.99,52.12234383846,144.12573777436,63.125015615541,340.37,58.270193733557,18.53,98.919800585095,18.39,20.678257721991,2287.8,212.3,0.31699 11 | 2017-06-02,154.82181847338,1006.73,22.337703209671,37.232884766135,106.37715355805,153.61,57.10615598286,27.376130147348,33.725738042408,996.12,148.97506745872,152.8394229451,71.020335030332,165.18,52.800033968673,143.51636274208,63.936976600713,339.85,57.682310452045,18.31,98.403869829787,18.72,20.470585119331,2390.0,215.86,0.2904 12 | 2017-06-05,153.30796087235,1011.34,22.297903293039,37.282727985367,105.72209737828,153.63,56.673235434403,27.474322866672,33.735527806716,1003.88,149.3277871186,151.8949878482,71.534975139247,165.06,52.829932062653,147.88260129112,63.639917703699,347.32,58.060947141832,18.23,98.919800585095,18.95,20.361804232224,2618.91043963,242.77,0.28471 13 | 2017-06-06,153.82585952534,1002.97,22.118803668195,36.834139012281,104.70973782772,152.81,54.193781384148,27.42522650701,33.706158513791,996.68,149.28859604528,150.34412600486,71.772501343362,165.17,52.30173240234,147.21317798955,63.530996108127,352.85,59.157000717532,17.57,98.721365679208,18.97,20.22335583045,2828.7,259.99,0.27937 14 | 2017-06-07,154.74214175754,1010.07,22.48695289704,37.282727985367,105.1265917603,153.12,54.400402555002,27.179744708702,33.990061678734,1001.59,147.9267062474,151.04996697202,71.643841316133,165.61,53.04918475184,148.99164586536,62.877466534695,359.65,60.253054293231,17.44,98.562617754497,19.22,20.20357748734,2674.8,250.12,0.27244 15 | 2017-06-08,154.36367735728,1009.94,22.855102125886,38.279592370003,103.53857677903,154.71,53.013088979264,27.091371261311,33.762405470636,1004.28,149.02405630037,150.54295444631,71.203428146004,165.88,53.01928665786,159.81432228712,61.629819167235,370.0,60.302874910309,17.59,98.126060961544,19.6,20.332136717558,2775.6,256.21,0.28562 16 | 2017-06-09,148.37796407954,978.31,23.551600666945,39.176770316175,104.82883895131,149.63,53.898608282927,27.435045778942,33.990061678734,970.12,150.98360996639,150.59266155668,69.595177805643,158.03,53.278403472353,149.47123270827,61.580309351066,357.32,60.532049748864,16.9,98.413791575081,20.21,20.173909972674,2808.6,278.12,0.28274 17 | 2017-06-12,144.7327543297,964.83,23.661050437682,39.126927096943,106.23820224719,148.44,53.977321109919,28.416972972176,34.32659694288,961.81,152.04176894603,147.60029351281,69.060743846385,151.44,53.846467257973,149.84091423302,60.689132660023,359.01,61.050184166467,17.04,99.167844217455,21.2,20.539809320218,2543.8,367.52,0.237 18 | 2017-06-13,145.99762219371,980.79,23.651100458524,38.578651685393,105.76179775281,150.68,54.213459590896,27.935828647492,34.158329310807,970.5,151.13057649134,148.94238549262,69.921776336301,152.72,54.12551613512,151.2696833692,60.322760020372,375.95,62.156201865582,16.97,98.423713320376,21.25,20.806816952209,2681.0,376.98,0.25739 19 | 2017-06-14,144.57340089801,976.47,23.641150479366,38.728181343089,105.34494382022,150.25,52.90485884215,28.171491173868,34.25731027085,967.93,150.69947468481,149.79734779086,69.545693179786,152.2,54.474327231553,151.58940793114,59.679132410175,380.66,62.285735469983,16.76,98.364182848609,21.09,20.597953110911,2374.2,330.44,0.25297 20 | 2017-06-15,143.70691661321,964.17,23.422250937891,38.429122027698,105.1861423221,149.8,51.979983124991,28.652635498552,34.247412174846,960.18,151.10118318635,150.28447747242,69.179506948442,151.76,52.72030571806,152.23884844759,59.500897071966,375.34,61.737708682133,16.83,98.344339358021,20.33,20.737195671776,2385.2,337.07,0.24362 21 | 2017-06-16,141.69507953817,987.71,23.312801167153,38.080219493076,104.71966292135,150.64,51.202693958443,28.712039718659,33.940571198713,958.62,152.23772431264,151.09967408238,69.278476200157,152.38,50.92642007926,151.48949400553,59.550406888135,371.4,61.388964362593,16.67,98.423713320376,19.68,20.796871055005,2423.7,345.05,0.24398 22 | 2017-06-19,145.7486324567,995.17,23.790400166736,37.731316958453,104.58071161049,152.87,50.622186859376,28.514025651634,33.999959774739,975.22,151.70864482281,152.24293762074,70.139508690073,153.4,51.843294961313,157.18458776514,60.283944324496,369.8,61.339143745515,17.06,99.118235490983,19.67,20.588007213706,2568.0,354.4,0.26824 23 | 2017-06-20,144.4240070558,992.59,23.372501042101,37.482100862294,103.16142322097,152.25,49.520207281484,27.8506785271,34.04945025476,968.99,151.81642027444,153.1674898735,69.189403873614,152.05,51.384857520287,156.95478573624,59.273151917588,372.24,61.169753647453,16.91,98.741209169796,19.01,20.040982867448,2747.3,347.68,0.31225 24 | 2017-06-21,145.28053175112,1002.23,23.014301792414,37.08335510844,104.01498127341,153.91,47.050592334603,27.504153909806,33.782201662644,978.59,150.67987914815,152.82948152303,69.545693179786,155.03,52.411358746933,159.33273716569,59.372171549926,376.4,61.159789524037,17.78,98.473322046848,18.75,20.269738503156,2601.1,307.76,0.26369 25 | 2017-06-22,145.04150160359,1001.3,22.815302209254,37.08335510844,103.4393258427,153.4,46.735741026634,27.276437732727,33.84159023867,976.62,151.27754301629,153.8932136848,69.535796254614,154.89,52.222004151727,158.23368398401,58.926583204405,382.61,61.498569720163,18.15,98.622148226264,19.24,20.100658250676,2675.0,318.51,0.2754 26 | 2017-06-23,145.75859204618,1003.74,22.705852438516,37.183041546904,103.57827715356,155.07,47.257213505458,27.296239139429,33.851488334674,986.09,150.99340773472,153.73415093164,70.476004145902,158.03,52.670475561427,153.97735075315,59.223642101419,383.45,62.564730925616,18.5,98.919800585095,19.65,20.29957619477,2692.1,325.98,0.29179 27 | 2017-06-26,145.23073380372,993.98,22.775502292622,37.382414423831,104.77921348315,153.59,47.591743020175,27.335841952834,34.168227406811,972.09,152.09075778768,153.0581342307,69.803013234243,157.5,53.099014908473,152.01903781125,59.055308726445,377.49,62.53483855537,18.29,99.038861528628,19.92,20.528331830478,2397.5,246.51,0.2429 28 | 2017-06-27,143.15913919179,976.78,23.153601500625,37.382414423831,104.62041198502,150.58,47.719651364037,26.939813818784,33.861386430678,948.09,151.62046490784,152.81954010095,68.496619111612,151.03,52.770135874693,146.45383215493,58.381975226545,362.37,61.478641473332,18.12,98.532852518614,19.9,20.269738503156,2495.6,275.7,0.25298 29 | 2017-06-28,145.2406933932,990.33,23.760550229262,37.681473739221,106.0595505618,153.24,47.926272534892,26.811104675217,34.227615982837,961.01,152.17893770265,153.39614258117,69.080537696728,153.41,53.178743159087,151.61938210882,58.599818417689,371.24,61.349107868931,17.95,98.850348368035,20.0,20.578061316501,2511.7,311.03,0.2618 30 | 2017-06-29,143.09938165491,975.93,24.198349312213,38.279592370003,104.91816479401,151.04,47.916433431518,26.75170045511,34.504762670957,937.82,151.01300327138,152.23299619867,67.784040499267,150.09,52.98938856388,146.55374608054,57.787857432517,360.75,61.349107868931,17.65,98.999174547451,19.8,20.428872858431,2490.3,291.29,0.25252 31 | 2017-06-30,143.43800769724,968.0,24.138649437266,37.980533054612,105.45411985019,150.98,48.487101427211,26.741799751758,34.574049342987,929.68,150.71907022147,152.26282046488,68.219505206811,149.41,58.799584827326,144.43557085767,57.738347616348,361.61,62.405304950969,17.87,99.624244500997,20.16,20.259792605951,2426.0,268.32,0.24412 32 | 2017-07-03,142.92010904426,953.66,24.556548561901,38.678338123857,106.65505617978,148.43,49.825219486079,27.177430699214,35.207527487262,919.46,152.43367967924,151.60668660809,67.467338893781,146.17,58.450773730893,139.21007254842,57.678935836945,352.62,62.355484333891,17.65,100.58665379455,20.52,20.220009017133,2550.5,276.26,0.25245 33 | 2017-07-05,143.5077248236,971.4,24.795348061692,38.379278808466,104.83876404494,150.34,49.490689971362,27.078423665701,34.653234111022,932.26,150.56230592819,152.17334766623,68.367959084383,147.61,57.364476316286,142.926870581,57.371974976697,327.09,61.349107868931,17.82,100.77516695515,20.4,20.379143372408,2601.2,265.8,0.25203 34 | 2017-07-06,142.15322065427,965.14,24.586398499375,38.080219493076,103.35,148.82,49.274229697134,26.04875051717,34.514660766962,927.69,149.27879827695,152.19323051038,67.863215900639,146.25,56.965835063219,143.35650046111,57.035308226747,308.89,59.99398708443,17.92,101.10556107345,19.1,20.399035166817,2597.5,265.35,0.24983 35 | 2017-07-07,143.59736112893,978.76,24.705798249271,38.279592370003,103.32,151.44,49.175838663393,25.89033926355,34.583947438992,940.81,149.8470688401,155.35460272948,68.744042240898,150.18,57.783049632006,146.63367722103,57.470994609035,313.22,60.003951207845,18.02,100.84657145888,19.22,20.44876465284,2453.8,235.0,0.228 36 | 2017-07-10,144.47380500321,996.47,24.765498124218,38.130062712307,103.59,153.5,47.621260330297,25.781431526686,34.831399839099,951.0,150.31736171994,154.60899607403,69.258682349814,152.67,58.530501981506,153.56770365816,57.243249454657,316.05,59.067323606793,18.08,100.15925286636,19.13,20.478602344454,2311.4,203.34,0.192 37 | 2017-07-11,144.94190570879,994.13,24.476948728637,38.030376273844,103.84,155.27,47.542547503305,26.118055440629,35.039259855189,953.53,150.09201304835,154.0025693276,69.268579274985,154.33,57.982370258539,155.7458272364,57.332367123762,327.22,58.369834967711,18.64,99.461973134818,18.92,20.418926961226,2315.6,191.68,0.17749 38 | 2017-07-12,145.15105708788,1006.51,24.228199249687,37.831003396917,104.38,158.9,47.768846880907,26.316069507654,35.138240815232,967.66,150.59169923318,155.66278681373,70.416622594873,158.75,58.022234383846,162.37012050415,57.966092770725,329.52,59.705027505381,19.25,99.342439466554,18.58,20.488548241659,2364.1,220.14,0.18859 39 | 2017-07-13,147.17285375241,999.855,24.496848686953,38.229749150771,104.29,159.26,48.095623818526,26.523984278031,35.494572271386,968.7175,150.52311485487,154.13180781454,71.030231955503,158.17,57.743185506699,160.49173870274,57.807661358984,323.41,60.67154747668,19.32,98.744771125233,18.63,20.568115419297,2335.7,204.75,0.1909 40 | 2017-07-14,148.43772161642,1001.81,24.088899541476,38.429122027698,105.09,159.97,47.947088846881,26.514083574679,35.979578975597,976.91,151.12077872301,154.37040194429,72.02982139782,161.12,57.802981694659,164.80802028896,58.183935961869,327.78,61.169753647453,19.64,99.402206300686,18.93,20.776979260595,2203.0,194.94,0.17988 41 | 2017-07-17,148.9556202694,1010.04,23.899849937474,38.329435589234,104.79,159.73,48.471912413359,26.553686388084,36.00927326361,975.96,149.91565321841,154.35051910014,72.593946132593,161.7,57.593695036799,164.10862280971,57.758151542815,319.57,61.448749103085,19.94,98.824460237409,18.82,20.568115419297,2194.9,186.78,0.1689 42 | 2017-07-18,149.47351892239,1024.38,23.780450187578,38.279592370003,105.75,162.86,48.105526149968,26.622991311543,36.058763743631,986.95,150.88563228309,153.0581342307,72.544461506735,183.6,57.454170598226,165.8171509376,57.63932798401,328.24,60.621726859603,19.98,98.714887708167,18.68,20.697412082958,2295.2,225.33,0.17601 43 | 2017-07-19,150.40972033355,1026.87,23.939649854106,38.279592370003,106.82,164.14,48.065916824197,26.6724948283,36.098356127648,992.77,144.54647617353,152.98854427619,73.098689316337,183.86,57.573762974146,164.95789117737,57.540308351672,325.26,60.910686438651,20.12,98.764693403277,18.91,21.174815148783,2253.3,192.61,0.16332 44 | 2017-07-20,149.73246824888,1028.7,23.82025010421,38.429122027698,107.36,164.53,47.51138626339,26.424977244518,36.038967551622,992.19,144.67384716182,153.30666978251,73.474772472852,183.6,58.899245140593,167.33584260682,57.461092645801,329.92,60.711403970342,20.53,99.033644156871,19.05,21.174815148783,2844.9,221.7,0.19324 45 | 2017-07-21,149.66275112251,1025.67,23.680950395998,38.179905931539,107.09,164.43,46.748906742281,25.65272238312,35.702432287477,993.84,144.10557659868,153.01836854241,73.029410840136,188.54,59.746357803359,167.95530894559,57.411582829632,328.4,61.65799569481,20.11,99.083449851981,18.84,21.095247971145,2698.0,219.9,0.187 46 | 2017-07-24,151.47539640795,1038.95,23.790400166736,38.429122027698,107.0,166.0,44.610003150599,25.177488622259,35.454979887369,998.31,143.0376198507,150.96049417337,72.841369261879,187.91,58.749754670693,166.00698739625,57.451190682567,342.52,61.388964362593,20.0,99.72096274939,18.26,21.652218214608,2772.5,226.81,0.1915 47 | 2017-07-25,152.12276972418,1039.87,24.357548978741,38.977397439247,106.42,165.28,45.303166351607,25.18738932561,35.207527487262,969.03,143.2335752173,158.13820090983,73.425287846995,186.97,59.188260049066,165.20767599139,57.975994733959,339.6,62.494982061708,19.97,99.42212857873,18.12,21.622380522994,2542.1,198.0,0.17265 48 | 2017-07-26,152.83986016677,1052.8,24.088899541476,37.980533054612,106.94,165.61,45.649747952111,25.335899875879,35.257017967283,965.31,142.4203604459,155.59319685923,73.286730894594,189.08,58.161758822419,167.11603197049,57.371974976697,343.85,62.803869887587,19.61,101.25497815878,17.55,21.562705139766,2511.0,201.4,0.17237 49 | 2017-07-27,149.95157921745,1046.0,23.989399749896,37.93068983538,110.0,170.44,46.788516068053,25.533913942904,35.573757039421,952.51,142.13622516433,156.03061943042,72.405904554335,182.68,57.952472164559,161.60078327698,58.916681241171,334.46,63.132685960297,16.84,102.79895470719,17.37,21.771568981064,2679.5,204.87,0.17421 50 | 2017-07-28,148.89586273252,1020.04,23.909799916632,37.482100862294,109.96,172.45,45.570529300567,25.276495655772,35.405489407348,958.33,141.37199923459,154.93706300243,72.287141452278,184.04,58.470705793546,164.24850230556,53.470601462576,335.07,62.77397751734,16.75,102.33078117316,17.36,21.264328223625,2787.5,191.3,0.161 51 | 2017-07-31,148.24848941629,987.78,23.999349729054,37.880846616148,109.93,169.25,46.729102079395,25.355701282582,35.613349423438,945.5,141.74431443113,154.23122203527,71.970439846791,181.66,58.849414983959,162.37012050415,53.450797536108,323.47,63.132685960297,16.09,102.02198586348,18.11,21.045518485122,2848.0,198.95,0.1649 52 | 2017-08-01,149.44364015394,996.19,24.327699041267,38.179905931539,110.61,169.86,46.41222747322,25.18738932561,34.405781710914,946.56,142.36157383592,153.13766560728,71.831882894391,182.03,59.636731458766,164.34841623117,54.193444778644,319.57,62.674336283186,16.21,102.02198586348,16.23,21.174815148783,2706.0,224.15,0.17798 53 | 2017-08-02,156.50498909557,995.89,24.466998749479,38.329435589234,108.67,169.25,47.184609325772,25.26659495242,34.46517028694,947.64,141.52876352787,155.67272823581,71.515181288904,180.74,59.586901302132,164.24850230556,54.88658220501,325.89,63.401717292514,16.07,102.1215972537,16.47,20.93611361587,2689.2,218.32,0.17269 54 | 2017-08-03,154.94133354715,986.92,24.248099208003,38.15,109.12,168.59,48.07581915564,25.504211832851,34.415679806919,940.3,142.00885417604,153.81368230822,71.406315112019,179.23,59.935712398566,166.33670335075,55.134131285856,347.09,63.013116479311,16.18,101.95225789032,16.34,21.115139765555,2804.9,225.19,0.1765 55 | 2017-08-04,155.75801988454,987.58,24.845097957482,38.3,107.69,169.62,48.521424070573,25.524013239553,34.910584607133,945.79,142.2244050793,152.91895432168,71.930852146105,180.27,59.557003208152,167.06607500769,54.896484168244,356.91,63.072901219804,16.29,102.1215972537,16.61,20.876438232642,2854.0,221.1,0.17369 56 | 2017-08-08,159.43310840282,989.84,24.775448103376,38.5,106.98,171.23,49.551266540643,25.306197765825,35.029361759185,944.19,140.70575098814,154.01251074967,72.039718322991,178.36,59.258022268353,170.15341530895,54.233052631579,365.22,64.786730447261,16.15,101.77295738793,17.21,20.7869251578,3450.7,294.83,0.19253 57 | 2017-08-09,160.40914817191,982.01,24.616248436849,38.15,102.83,171.18,49.313610586011,25.454708316094,34.920482703138,940.08,140.36911067194,154.01251074967,71.723016717505,175.78,59.696527646726,171.96185736243,53.457157894737,363.525,64.428022004305,16.14,101.88252991717,17.17,20.727249774572,3292.3,291.97,0.18237 58 | 2017-08-10,155.27,956.92,23.999349729054,37.7,101.35,167.4,48.61054505356,25.048779478693,34.524558862966,923.59,140.43841897233,155.70255250203,70.673942649331,169.14,58.869347046613,164.59820104519,52.790684210526,355.13,64.63726859603,15.75,101.54385119042,16.82,21.174815148783,3425.6,301.15,0.1804 59 | 2017-08-11,157.48,967.99,23.740650270946,37.4,101.99,168.08,48.818494013863,24.94977244518,34.574049342987,930.09,140.43841897233,156.37856920297,71.752707493019,171.4,58.769686733346,155.81576698432,52.900105263158,357.715,65.31482898828,15.92,101.50400663433,16.8,20.946059513075,3663.2,307.85,0.17946 60 | 2017-08-14,159.85,983.3,24.297849103793,38.2,101.4,170.75,48.838298676749,25.1081836988,35.108546527219,938.93,140.91367588933,156.33880351468,72.831472336707,171.0,59.576935270806,168.25505072241,52.939894736842,363.8,65.613752690744,16.09,101.89249105619,17.11,20.926167718665,4247.9,297.4,0.167 61 | 2017-08-15,161.6,982.74,24.347598999583,37.95,101.51,171.0,46.669688090737,24.890368225072,35.177833199249,938.08,140.66614624506,156.69669470929,72.85126618705,168.5,58.361079448953,166.83627297879,52.870263157895,362.33,65.723358048314,15.95,101.30478385389,16.66,21.015680793508,4182.1,285.0,0.15653 62 | 2017-08-16,160.95,978.18,24.06899958316,37.9,102.2,170.0,48.095623818526,24.850765411667,35.385693215339,944.27,141.0918972332,157.96919673459,73.279100719424,169.98,58.341147386299,165.00784814018,53.218421052632,362.91,65.414470222435,16.16,101.52392891237,16.68,21.433408476105,4324.7,300.0,0.15831 63 | 2017-08-17,157.87,960.57,23.521750729471,36.95,101.38,166.91,47.234120982987,24.504240794373,34.643336015017,927.66,139.30968379447,156.96511310525,72.035395683453,166.09,57.264816003019,161.33101567784,52.760842105263,351.92,64.667160966276,15.87,101.21513360269,16.28,20.985843101894,4315.2,301.13,0.15998 64 | 2017-08-18,157.5,958.47,23.501850771155,37.05,100.7,167.41,34.044215500945,24.306226727348,34.475068382944,926.18,138.31956521739,156.83587461831,72.124942446043,166.54,54.763342140026,161.36098985552,52.422631578947,347.46,64.906299928247,15.99,100.79676576377,15.64,20.7869251578,4101.5,292.68,0.15701 65 | 2017-08-21,157.21,953.29,23.263051271363,37.05,101.17,167.78,31.509218651544,24.24682250724,34.554253150979,920.87,138.94333992095,157.43235994267,71.786654676259,166.76,53.427893942253,158.98303842607,52.870263157895,337.86,64.876407558,16.11,101.71319055379,15.15,20.677520288548,4007.7,320.01,0.198 66 | 2017-08-22,159.78,966.9,23.710800333472,37.1,102.77,169.64,32.855935727788,24.355730244104,34.940278895146,940.4,139.61662055336,158.70486196797,72.791568345324,169.34,53.94612757124,162.51,54.163421052632,341.35,64.716981583353,16.63,101.40439524411,15.42,20.866492335437,4038.0,315.61,0.2358 67 | 2017-08-23,159.98,958.0,23.641150479366,37.35,101.5,168.71,34.905718336484,24.147815473728,35.128342719228,942.58,140.73545454545,157.87972393594,72.353784172662,169.06,53.427893942253,165.8,53.795368421053,352.77,64.328380770151,16.96,101.25497815878,15.55,20.637736699729,4143.2,316.79,0.26333 68 | 2017-08-24,159.27,952.45,23.72075031263,37.55,101.52,167.74,34.430406427221,24.058709143566,35.158037007241,936.89,141.52754940711,157.48206705303,72.323935251799,168.13,53.657112662767,165.19,53.656105263158,352.93,63.630892131069,16.89,100.92626057105,15.73,20.846600541028,4331.2,325.09,0.21799 69 | 2017-08-25,159.86,945.26,23.651100458524,37.95,102.41,166.32,35.529565217391,24.24682250724,35.237221775275,930.5,142.31964426877,157.88966535801,72.45328057554,165.95,53.716908850727,163.81,54.073894736842,348.05,63.023080602727,16.65,101.02587196127,15.94,20.776979260595,4363.8,329.69,0.21699 70 | 2017-08-28,161.47,946.02,23.601350562734,37.8,102.56,167.24,35.351323251418,24.227021100538,35.148138911236,928.13,141.10179841897,158.73468623419,72.463230215827,167.12,53.547486318173,164.97,54.113684210526,345.66,62.325591963645,16.77,101.30478385389,15.78,21.373733092876,4369.9,345.91,0.2257 71 | 2017-08-29,162.91,954.06,23.462050854523,37.75,102.57,168.05,34.816597353497,24.197318990484,35.158037007241,935.75,141.72557312253,158.44638499408,72.682122302158,168.81,52.550883185507,164.7,53.815263157895,347.36,61.956919397273,16.93,100.98602740519,15.34,21.154923354373,4602.7,375.67,0.21807 72 | 2017-08-30,163.35,967.59,23.87,37.8,102.87,169.92,34.895816005041,24.038907736864,35.454979887369,943.63,141.15130434783,159.53,73.637287769784,174.69,52.381460652953,165.68,54.233052631579,353.18,62.49,16.93,100.9461828491,15.18,21.483137962128,4571.5,385.1,0.2288 73 | 2017-08-31,164.0,980.6,23.89,37.6,101.2,172.0,34.885913673598,24.306226727348,36.167642799678,955.24,141.61666007905,159.97,74.393460431655,174.71,52.81,169.44,54.571263157895,355.9,63.3,16.91,100.70711551257,15.1,21.682055906222,4725.7,386.26,0.25856 74 | 2017-09-01,164.05,978.25,24.09,37.8,101.5,172.02,35.985072463768,24.890368225072,36.97928667203,951.99,142.65628458498,159.81,73.56764028777,174.74,53.36,170.46,54.640894736842,355.4,64.53,16.86,101.20517246367,15.39,22.030162308386,4863.8,389.08,0.2538 75 | 2017-09-05,162.08,965.27,23.31,36.25,101.6,170.72,35.975170132325,24.514141497724,36.850611423974,941.48,141.62656126482,159.1,73.239302158273,174.52,53.01,165.91,54.839842105263,349.59,64.47,16.65,100.82664918083,15.62,21.821298467087,4448.0,320.4,0.21566 76 | 2017-09-06,161.91,967.8,23.41,36.45,101.5,172.09,36.341556395715,24.672552751345,37.286127648163,942.02,142.39885375494,158.22,73.03035971223,179.25,52.76,165.81,54.024157894737,344.53,64.95,16.83,100.40828134191,15.8,21.980432822362,4614.4,335.9,0.23049 77 | 2017-09-07,161.26,979.47,22.97,35.65,97.06,173.21,35.806830497795,23.781489449731,36.91,949.89,141.48794466403,159.9,73.965625899281,179.0,52.39,166.58,53.188578947368,350.61,64.65,17.22,100.07956375418,15.98,21.91081154193,4622.0,335.37,0.22859 78 | 2017-09-08,158.63,965.9,22.89,36.25,97.07,170.95,35.381030245747,23.583475382706,37.0,941.41,141.04239130435,159.71,73.607438848921,176.42,52.2,163.69,53.228368421053,343.4,65.39,17.45,99.810613000588,16.12,21.493083859333,4314.7,306.27,0.211 79 | 2017-09-11,161.5,977.96,23.36,37.3,97.09,173.51,34.648257718967,23.484468349193,37.35,943.29,143.4285770751,161.53,74.383510791367,181.74,53.03,169.0,53.735684210526,363.69,65.5,17.66,100.1791751444,16.34,21.443354373309,4208.5,297.07,0.21779 80 | 2017-09-12,160.82,982.58,23.95,38.2,97.89,172.96,35.351323251418,23.672581712867,37.89,946.65,144.31968379447,156.33,74.303913669065,185.15,53.4,169.61,53.258210526316,362.75,65.82,18.17,100.60750412235,16.25,21.761623083859,4169.5,296.01,0.21074 81 | 2017-09-13,159.65,999.6,24.33,38.35,98.82,173.05,35.747416509137,23.870595779892,38.21,950.44,144.54741106719,157.0,74.831244604317,183.64,53.52,170.37,54.004263157895,366.23,65.95,18.2,100.90633829301,16.87,21.940649233544,3935.1,280.3,0.20051 82 | 2017-09-14,158.28,992.21,24.24,38.25,97.9,170.96,36.262337744171,24.019106330161,38.79,940.13,144.10185770751,157.0,74.393460431655,182.63,53.73,169.4,54.243,377.64,66.32,18.21,100.61746526137,16.52,22.06,3296.6,228.97,0.17381 83 | 2017-09-15,159.88,986.79,24.38,38.45,98.52,171.58,36.569310018904,23.93,38.88,935.29,143.38897233202,156.92,74.930741007194,182.1,53.87,180.11,54.382263157895,379.81,66.87,18.01,101.47412321726,16.46,22.44,3741.4,260.32,0.18659 84 | 2017-09-18,158.67,974.19,24.7,38.7,98.1,170.01,35.905853812224,24.46,38.59,929.75,143.12164031621,156.68,74.781496402878,184.62,53.5,187.55,54.402157894737,385.0,67.41,17.6,101.57373460748,16.14,22.83,4049.0,293.36,0.19335 85 | 2017-09-19,158.73,969.86,24.86,38.5,98.43,172.52,34.707671707624,24.2,38.7,936.86,142.96322134387,157.43,75.060086330935,185.68,53.33,187.35,54.332526315789,375.1,66.21,17.76,102.38058686827,15.7,22.52,3917.7,282.91,0.1843 86 | 2017-09-20,156.07,973.21,25.06,38.9,99.21,172.17,34.232359798362,24.32,38.88,947.54,144.43849802372,159.88,74.562604316547,185.51,53.56,185.84,54.859736842105,373.91,65.78,17.62,102.49015939751,15.24,22.52,3949.0,288.21,0.184 87 | 2017-09-21,153.39,964.65,25.16,39.0,98.89,171.11,33.370856962823,24.75,39.1,947.55,143.82462450593,159.03,73.83628057554,188.78,53.19,180.7799,54.720473684211,366.48,65.33,17.58,102.09171383663,15.13,22.5,3620.1,258.85,0.17194 88 | 2017-09-22,151.89,955.1,25.02,39.05,98.6,170.54,33.271833648393,24.87,39.42,943.26,143.69590909091,158.91,74.035273381295,187.35,53.24,179.0,54.800052631579,351.09,65.41,17.61,102.00206358543,15.04,22.6,3604.1,261.13,0.17137 89 | 2017-09-25,150.55,939.79,24.76,39.25,99.57,162.87,34.321480781348,25.11,40.3,934.28,144.42859683794,156.26,72.891064748201,178.55,53.23,171.0,54.660789473684,344.99,65.65,16.98,102.81887698524,15.39,22.54,3924.5,294.62,0.1855 90 | 2017-09-26,153.14,938.6,24.81,39.85,98.63,164.21,34.776988027725,24.93,40.26,937.43,145.11177865613,153.35,72.891064748201,179.38,53.7,171.96,54.839842105263,345.25,65.83,16.59,102.5300039536,15.14,22.65,3886.0,288.54,0.19294 91 | 2017-09-27,154.23,950.87,25.41,40.8,99.24,167.68,34.72747637051,24.37,40.58,959.9,144.22067193676,154.05,73.47809352518,181.97,52.67,175.73,54.700578947368,340.97,66.18,16.95,102.00206358543,15.06,23.06,4196.1,309.68,0.21 92 | 2017-09-28,153.28,956.4,25.45,40.85,98.05,168.73,34.519527410208,24.24,40.58,964.81,144.22067193676,157.49,73.497992805755,180.7,52.63,175.68,54.213157894737,339.6,65.45,16.85,101.84268536108,15.07,23.06,4180.1,301.68,0.20235 93 | 2017-09-29,154.12,961.35,25.34,41.05,98.57,170.81,34.876011342155,24.18,40.38,973.72,143.64640316206,156.68,74.114870503597,181.35,51.85,178.77,53.427315789474,341.1,70.45,16.87,102.05186928054,15.02,23.55,4162.6,292.36,0.19625 94 | 2017-10-02,153.81,959.19,25.62,41.25,99.86,169.47,34.410601764335,24.57,42.15,967.47,145.21079051383,156.96,74.23426618705,177.01,51.87,179.0,53.526789473684,341.53,70.99,17.09,102.67942103893,15.08,23.72,4374.1,295.76,0.20458 95 | 2017-10-03,154.48,957.1,25.86,41.1,100.79,169.96,34.044215500945,24.8,43.45,972.08,145.32960474308,156.86,73.886028776978,179.19,51.47,179.37,53.705842105263,348.14,71.34,17.59,102.87864381937,15.26,23.63,4310.0,291.61,0.2024 96 | 2017-10-04,153.4508,965.45,25.71,41.05,100.55,168.42,33.519391934468,24.48,43.78,966.78,145.03256916996,157.21,74.313863309353,184.45,52.08,180.87,53.646157894737,355.01,71.64,17.75,103.09778887785,15.03,23.64,4222.1,291.57,0.21194 97 | 2017-10-05,155.39,980.85,26.13,41.35,100.11,171.24,34.044215500945,24.54,43.85,985.19,145.27019762846,158.8,75.587417266187,194.39,52.18,180.77,54.312631578947,355.33,71.07,18.25,103.23724482416,15.03,23.42,4359.7,297.36,0.2387 98 | 2017-10-06,155.3,989.58,26.21,41.25,100.07,172.23,34.073922495274,24.39,44.93,993.64,145.03256916996,159.6,75.61726618705,198.02,52.42,181.3,54.879631578947,356.88,70.66,17.85,103.3,15.46,23.51,4352.0,305.2,0.235 99 | 2017-10-09,155.84,990.99,25.85,41.1,99.57,172.5,33.063884688091,23.43,45.33,992.31,145.9335770751,160.12,75.905805755396,196.87,51.52,185.39,54.730421052632,342.94,70.64,17.67,103.35,15.3,23.46,4752.2,297.41,0.24628 100 | 2017-10-10,155.9,987.2,25.93,41.4,99.58,171.59,33.271833648393,23.36,45.21,987.8,147.03260869565,160.58,75.905805755396,195.08,51.53,188.88,55.128315789474,355.59,70.11,17.41,103.35,15.51,23.29,4790.9,298.89,0.25769 101 | 2017-10-11,156.55,995.0,25.83,41.05,98.55,172.74,32.608377441714,23.07,45.47,1005.65,146.16130434783,163.15,76.035151079137,194.95,51.03,190.94,55.347157894737,354.6,70.04,17.73,103.38,15.15,23.09,4815.0,302.43,0.2627 102 | 2017-10-12,156.0,1000.93,25.45,40.7,96.93,172.55,31.43,23.05,44.89,1005.65,145.57713438735,163.91,76.731625899281,195.86,50.83,191.03,55.675421052632,355.68,70.8,18.45,101.45,15.22,22.3,5312.6,304.0,0.2524 103 | 2017-10-13,156.99,1002.94,25.83,40.8,97.38,173.74,31.65,22.98,45.88,1007.87,145.64644268775,165.37,77.099762589928,199.49,50.98,194.59,55.426736842105,355.57,70.21,18.63,100.94,14.95,22.54,5644.1,339.28,0.25778 104 | 2017-10-16,159.88,1006.34,26.24,41.4,98.13,174.52,30.95,23.36,45.76,1009.35,145.37911067194,165.01,77.258956834532,202.68,51.37,197.93,54.621,350.6,70.55,18.33,101.12,14.98,22.59,5715.0,336.41,0.25999 105 | 2017-10-17,160.47,1009.13,26.2,40.75,98.36,176.11,31.02,23.19,45.02,1011.0,145.09197628458,165.4,77.199258992806,199.48,52.0,197.75,54.223105263158,355.75,70.94,18.28,101.46,15.11,22.54,5555.0,310.5,0.2254 106 | 2017-10-18,159.76,997.0,26.48,40.9,98.25,176.03,31.18,23.12,45.12,1012.74,157.95361660079,165.77,77.219158273381,195.54,52.3,197.58,54.919421052632,359.65,71.55,18.02,101.48,14.98,22.54,5582.9,312.1,0.21699 107 | 2017-10-19,155.98,986.61,26.58,41.2,99.01,174.56,30.99,23.58,45.35,1001.84,159.31007905138,166.5,77.517647482014,195.13,52.69,197.8,55.108421052632,351.81,71.41,17.89,102.2,15.02,22.62,5709.3,308.46,0.2135 108 | 2017-10-20,156.16,982.91,27.17,41.55,99.4,174.98,31.28,23.83,45.61,1005.07,160.46851778656,166.3,78.413115107914,194.16,53.06,196.9,54.282789473684,345.1,71.54,17.87,101.83,15.91,22.62,6004.9,303.3,0.2067 109 | 2017-10-23,156.17,966.3,27.16,40.95,98.7,171.27,31.62,22.32,45.15,985.54,157.97341897233,163.34,78.433014388489,192.47,53.66,196.62,53.984368421053,337.02,71.52,17.37,101.33,15.22,22.48,5889.1,285.5,0.1925 110 | 2017-10-24,157.1,975.9,27.68,41.35,98.29,171.8,31.13,21.89,46.48,988.49,154.33968379447,163.88,78.462863309353,196.02,53.42,198.68,53.994315789474,337.34,71.16,17.25,100.5,14.83,22.06,5491.0,295.89,0.20591 111 | 2017-10-25,156.405,972.91,27.635,41.05,97.79,170.6,31.29,21.525,45.13,991.46,151.98320158103,163.55,78.234021582734,193.77,54.925,193.66,53.874947368421,325.84,71.08,17.15,98.71,14.65,21.555,5665.0,296.06,0.2022 112 | 2017-10-26,157.41,972.43,27.74,41.25,98.56,170.63,33.07,21.32,45.25,991.42,152.08221343874,164.01,78.363366906475,195.21,56.81,195.69,54.621,326.17,71.3,20.31,98.97,14.65,24.4,5876.2,295.64,0.20127 113 | 2017-10-27,163.05,1100.95,27.8,41.3,98.31,177.88,31.55,20.79,44.64,1033.67,152.1614229249,165.39,83.387935251799,199.54,55.96,201.86,54.591157894737,320.87,71.04,21.68,98.79,14.4,26.09,5771.8,295.98,0.2008 114 | 2017-10-30,166.72,1110.85,27.6,40.6,98.04,179.87,30.58,20.41,43.37,1033.13,152.83470355731,166.23,83.467532374101,198.37,55.27,203.84,54.879631578947,320.08,71.47,21.25,98.49,14.74,25.31,6094.0,305.04,0.20179 115 | 2017-10-31,169.04,1105.28,27.39,40.6,97.81,180.06,30.08,20.16,42.98,1033.04,152.53766798419,166.91,82.761107913669,196.43,54.99,206.81,54.551368421053,331.53,72.91,20.62,98.29,11.53,26.53,6387.4,304.87,0.19923 116 | 2017-11-01,166.89,1103.68,27.53,40.2,99.03,182.66,29.91,20.02,43.13,1042.6,152.50796442688,166.37,82.761107913669,198.0,55.07,207.2,54.839842105263,321.08,73.31,20.61,98.39,11.29,26.5,6659.1,292.16,0.19164 117 | 2017-11-02,168.11,1094.22,27.87,40.5,98.35,178.92,30.01,19.94,42.6,1042.97,151.83468379447,168.1,83.626726618705,199.32,55.12,205.94,54.581210526316,299.26,73.15,19.71,94.7,10.84,26.26,6987.7,283.75,0.19324 118 | 2017-11-03,172.5,1111.6,27.82,40.8,98.64,178.92,29.85,20.14,42.34,1049.99,150.08217391304,168.65,83.716273381295,200.01,55.71,208.69,55.735105263158,306.09,72.8,19.9,93.28,10.59,26.38,7247.2,301.65,0.20778 119 | 2017-11-07,174.81,1123.17,27.18,39.45,101.61,180.25,29.24,20.21,41.7,1052.39,149.85444664032,170.77,83.845618705036,195.89,55.15,212.03,56.918842105263,306.05,73.09,19.66,94.66,10.74,27.11,6956.5,296.38,0.20189 120 | 2017-11-09,175.88,1129.13,26.49,39.3,102.68,179.3,30.61,19.99,42.11,1047.72,150.3,167.0,83.666525179856,193.9,56.13,205.32,57.058105263158,302.99,73.82,19.9,87.05,10.99,27.1,7447.0,307.52,0.21747 121 | 2017-11-10,174.67,1125.35,26.51,39.2,104.78,178.46,30.34,20.49,42.66,1044.15,149.16,165.59,83.447633093525,192.02,56.09,216.14,56.739789473684,302.99,74.14,20.32,90.6,11.37,27.3,7126.4,319.52,0.21628 122 | 2017-11-13,173.97,1129.17,26.4,39.75,104.74,178.77,29.64,19.02,43.57,1041.2,148.4,167.37,83.507330935252,195.08,55.91,212.63,56.341894736842,315.4,75.59,20.17,88.49,10.95,27.64,5810.7,303.2,0.19001 123 | 2017-11-14,171.34,1136.84,26.24,40.0,103.17,178.07,30.0,17.9,43.0,1041.64,148.89,168.11,83.626726618705,195.71,55.98,214.18,56.630368421053,308.7,76.07,20.05,87.51,10.92,27.46,6476.5,313.22,0.2 124 | 2017-11-15,169.08,1126.69,26.79,39.7,103.69,177.95,31.2,18.26,42.86,1036.41,147.1,167.32,82.98,192.12,56.63,209.98,56.7,311.3,76.21,19.91,87.37,11.11,27.38,6590.0,334.28,0.20465 125 | 2017-11-16,171.1,1137.29,26.76,39.7,103.6,179.59,31.85,18.25,43.6,1048.47,149.12,168.09,83.2,195.51,57.23,211.61,57.24,312.5,77.26,20.36,88.01,11.28,27.39,7265.84095228,330.9,0.20867 126 | 2017-11-17,170.15,1129.88,26.62,39.95,103.44,179.0,40.82,18.21,43.88,1035.89,148.97,166.72,82.4,193.2,59.19,211.36,56.93,315.05,77.97,20.76,88.72,11.73,27.54,7864.2,330.91,0.2267 127 | 2017-11-20,169.98,1126.31,26.74,40.4,102.75,178.74,40.69,17.98,44.88,1034.66,150.51,166.93,82.53,194.1,59.25,214.08,56.81,308.74,78.96,21.13,87.71,12.07,27.59,8050.7,354.7,0.23264 128 | 2017-11-21,173.14,1139.49,26.73,40.4,103.0,181.86,40.69,17.83,44.97,1050.3,151.95,168.3,83.72,196.23,59.39,216.05,57.26,317.81,79.06,21.88,89.56,11.36,27.74,8248.8,368.1,0.24098 129 | 2017-11-22,174.96,1156.16,26.66,40.35,102.74,180.87,40.54,18.15,44.29,1051.92,151.77,169.05,83.11,196.32,59.07,214.93,57.14,312.6,79.63,22.27,90.01,11.67,27.56,8079.3,359.79,0.232 130 | 2017-11-24,174.97,1186.0,26.59,40.0,102.64,182.78,40.1,18.19,44.46,1056.52,151.84,169.11,83.26,195.75,59.32,216.96,56.8,315.55,80.47,22.42,89.5,11.59,28.12,7985.4,405.2,0.23878 131 | 2017-11-27,174.09,1195.83,26.59,40.1,102.79,183.03,39.4,18.12,44.17,1072.01,151.98,168.96,83.87,195.05,59.63,214.14,55.91,316.81,81.24,21.82,89.07,11.35,27.54,9303.0,469.54,0.2454 132 | 2017-11-28,173.07,1193.6,27.64,40.9,103.41,182.42,40.45,18.41,44.92,1063.29,152.47,171.34,84.88,199.18,59.58,210.71,56.66,317.55,81.15,21.83,89.62,11.51,28.01,9725.9,472.96,0.24719 133 | 2017-11-29,169.48,1161.27,28.28,42.4,105.24,175.13,42.59,18.48,43.81,1037.38,153.55,170.43,83.34,188.15,60.36,196.42,57.51,307.54,82.02,20.79,90.92,12.18,28.02,9894.9,465.56,0.27949 134 | 2017-11-30,171.85,1176.75,28.17,41.75,104.82,177.18,42.84,18.29,43.09,1036.17,153.97,171.97,84.17,187.58,60.42,200.71,57.82,308.85,82.25,20.58,91.51,11.93,28.49,9772.0,420.34,0.2357 135 | -------------------------------------------------------------------------------- /environment.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | from utils import portfolio 5 | 6 | 7 | class CryptoEnvironment: 8 | 9 | def __init__(self, prices = './data/crypto_portfolio.csv', capital = 1e6): 10 | self.prices = prices 11 | self.capital = capital 12 | self.data = self.load_data() 13 | 14 | def load_data(self): 15 | data = pd.read_csv(self.prices) 16 | try: 17 | data.index = data['Date'] 18 | data = data.drop(columns = ['Date']) 19 | except: 20 | data.index = data['date'] 21 | data = data.drop(columns = ['date']) 22 | return data 23 | 24 | def preprocess_state(self, state): 25 | return state 26 | 27 | def get_state(self, t, lookback, is_cov_matrix = True, is_raw_time_series = False): 28 | 29 | assert lookback <= t 30 | 31 | decision_making_state = self.data.iloc[t-lookback:t] 32 | decision_making_state = decision_making_state.pct_change().dropna() 33 | 34 | if is_cov_matrix: 35 | x = decision_making_state.cov() 36 | return x 37 | else: 38 | if is_raw_time_series: 39 | decision_making_state = self.data.iloc[t-lookback:t] 40 | return self.preprocess_state(decision_making_state) 41 | 42 | def get_reward(self, action, action_t, reward_t, alpha = 0.01): 43 | 44 | def local_portfolio(returns, weights): 45 | weights = np.array(weights) 46 | rets = returns.mean() # * 252 47 | covs = returns.cov() # * 252 48 | P_ret = np.sum(rets * weights) 49 | P_vol = np.sqrt(np.dot(weights.T, np.dot(covs, weights))) 50 | P_sharpe = P_ret / P_vol 51 | return np.array([P_ret, P_vol, P_sharpe]) 52 | 53 | data_period = self.data[action_t:reward_t] 54 | weights = action 55 | returns = data_period.pct_change().dropna() 56 | 57 | sharpe = local_portfolio(returns, weights)[-1] 58 | sharpe = np.array([sharpe] * len(self.data.columns)) 59 | rew = (data_period.values[-1] - data_period.values[0]) / data_period.values[0] 60 | 61 | return np.dot(returns, weights), rew 62 | 63 | 64 | 65 | class ETFEnvironment: 66 | 67 | def __init__(self, volumes = './data/volumes.txt', 68 | prices = './data/prices.txt', 69 | returns = './data/returns.txt', 70 | capital = 1e6): 71 | 72 | self.returns = returns 73 | self.prices = prices 74 | self.volumes = volumes 75 | self.capital = capital 76 | 77 | self.data = self.load_data() 78 | 79 | def load_data(self): 80 | volumes = np.genfromtxt(self.volumes, delimiter=',')[2:, 1:] 81 | prices = np.genfromtxt(self.prices, delimiter=',')[2:, 1:] 82 | returns=pd.read_csv(self.returns, index_col=0) 83 | assets=np.array(returns.columns) 84 | dates=np.array(returns.index) 85 | returns=returns.as_matrix() 86 | return pd.DataFrame(prices, 87 | columns = assets, 88 | index = dates 89 | ) 90 | 91 | def preprocess_state(self, state): 92 | return state 93 | 94 | def get_state(self, t, lookback, is_cov_matrix = True, is_raw_time_series = False): 95 | 96 | assert lookback <= t 97 | 98 | decision_making_state = self.data.iloc[t-lookback:t] 99 | decision_making_state = decision_making_state.pct_change().dropna() 100 | 101 | if is_cov_matrix: 102 | x = decision_making_state.cov() 103 | return x 104 | else: 105 | if is_raw_time_series: 106 | decision_making_state = self.data.iloc[t-lookback:t] 107 | return self.preprocess_state(decision_making_state) 108 | 109 | def get_reward(self, action, action_t, reward_t): 110 | 111 | def local_portfolio(returns, weights): 112 | weights = np.array(weights) 113 | rets = returns.mean() # * 252 114 | covs = returns.cov() # * 252 115 | P_ret = np.sum(rets * weights) 116 | P_vol = np.sqrt(np.dot(weights.T, np.dot(covs, weights))) 117 | P_sharpe = P_ret / P_vol 118 | return np.array([P_ret, P_vol, P_sharpe]) 119 | 120 | weights = action 121 | returns = self.data[action_t:reward_t].pct_change().dropna() 122 | 123 | rew = local_portfolio(returns, weights)[-1] 124 | rew = np.array([rew] * len(self.data.columns)) 125 | 126 | return np.dot(returns, weights), rew 127 | -------------------------------------------------------------------------------- /hrp_routines.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from scipy.cluster.hierarchy import dendrogram, linkage 4 | from scipy.cluster.hierarchy import cophenet 5 | from scipy.spatial.distance import pdist 6 | import pylab 7 | 8 | 9 | 10 | # On 20151227 by MLdP 11 | # Hierarchical Risk Parity 12 | 13 | 14 | def getIVP(cov, **kargs): 15 | # Compute the inverse-variance portfolio 16 | ivp = 1. / np.diag(cov) 17 | ivp /= ivp.sum() 18 | return ivp 19 | 20 | 21 | def getClusterVar(cov,cItems): 22 | # Compute variance per cluster 23 | cov_=cov.loc[cItems,cItems] # matrix slice 24 | w_=getIVP(cov_).reshape(-1,1) 25 | cVar=np.dot(np.dot(w_.T,cov_),w_)[0,0] 26 | return cVar 27 | 28 | 29 | def getQuasiDiag(link): 30 | # Sort clustered items by distance 31 | link = link.astype(int) 32 | sortIx = pd.Series([link[-1, 0], link[-1, 1]]) 33 | numItems = link[-1, 3] # number of original items 34 | while sortIx.max() >= numItems: 35 | sortIx.index = range(0, sortIx.shape[0] * 2, 2) # make space 36 | df0 = sortIx[sortIx >= numItems] # find clusters 37 | i = df0.index 38 | j = df0.values - numItems 39 | sortIx[i] = link[j, 0] # item 1 40 | df0 = pd.Series(link[j, 1], index=i + 1) 41 | sortIx = sortIx.append(df0) # item 2 42 | sortIx = sortIx.sort_index() # re-sort 43 | sortIx.index = range(sortIx.shape[0]) # re-index 44 | return sortIx.tolist() 45 | 46 | 47 | def getRecBipart(cov, sortIx): 48 | # Compute HRP alloc 49 | w = pd.Series(1, index=sortIx) 50 | cItems = [sortIx] # initialize all items in one cluster 51 | while len(cItems) > 0: 52 | cItems = [i[j:k] for i in cItems for j, k in ((0, len(i) // 2), (len(i) // 2, len(i))) if len(i) > 1] # bi-section 53 | for i in range(0, len(cItems), 2): # parse in pairs 54 | cItems0 = cItems[i] # cluster 1 55 | cItems1 = cItems[i + 1] # cluster 2 56 | cVar0 = getClusterVar(cov, cItems0) 57 | cVar1 = getClusterVar(cov, cItems1) 58 | alpha = 1 - cVar0 / (cVar0 + cVar1) 59 | w[cItems0] *= alpha # weight 1 60 | w[cItems1] *= 1 - alpha # weight 2 61 | return w 62 | 63 | 64 | def correlDist(corr): 65 | # A distance matrix based on correlation, where 0<=d[i,j]<=1 66 | # This is a proper distance metric 67 | dist = ((1 - corr) / 2.)**.5 # distance matrix 68 | return dist 69 | 70 | 71 | def getHRP(cov, corr): 72 | # Construct a hierarchical portfolio 73 | dist = correlDist(corr) 74 | link = linkage(dist, 'single') 75 | #dn = sch.dendrogram(link, labels=cov.index.values, label_rotation=90) 76 | #plt.show() 77 | sortIx = getQuasiDiag(link) 78 | sortIx = corr.index[sortIx].tolist() 79 | hrp = getRecBipart(cov, sortIx) 80 | return hrp.sort_index() -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | import statsmodels.api as sm 5 | from statsmodels import regression 6 | 7 | import matplotlib 8 | import os 9 | 10 | import matplotlib.pylab as plt 11 | 12 | current_cmap = matplotlib.cm.get_cmap() 13 | current_cmap.set_bad(color='red') 14 | 15 | def plot_results(benchmark_series, 16 | target_series, 17 | target_balances, 18 | n_assets, 19 | columns, 20 | name2plot = '', 21 | path2save = './', 22 | base_name_series = 'series'): 23 | 24 | # N = len(np.array(benchmark_series).cumsum()) 25 | N = len(np.array([item for sublist in benchmark_series for item in sublist]).cumsum()) 26 | 27 | if not os.path.exists(path2save): 28 | os.makedirs(path2save) 29 | 30 | for i in range(0, len(target_balances)): 31 | 32 | current_range = np.arange(0, N) 33 | current_ts = np.zeros(N) 34 | current_ts2 = np.zeros(N) 35 | 36 | ts_benchmark = np.array([item for sublist in benchmark_series[:i+1] for item in sublist]).cumsum() 37 | ts_target = np.array([item for sublist in target_series[:i+1] for item in sublist]).cumsum() 38 | 39 | t = len(ts_benchmark) 40 | current_ts[:t] = ts_benchmark 41 | current_ts2[:t] = ts_target 42 | 43 | current_ts[current_ts == 0] = ts_benchmark[-1] 44 | current_ts2[current_ts2 == 0] = ts_target[-1] 45 | 46 | plt.figure(figsize = (12, 10)) 47 | 48 | plt.subplot(2, 1, 1) 49 | plt.bar(np.arange(n_assets), target_balances[i], color = 'grey') 50 | plt.xticks(np.arange(n_assets), columns, rotation='vertical') 51 | 52 | plt.subplot(2, 1, 2) 53 | plt.colormaps = current_cmap 54 | plt.plot(current_range[:t], current_ts[:t], color = 'black', label = 'Benchmark') 55 | plt.plot(current_range[:t], current_ts2[:t], color = 'red', label = name2plot) 56 | plt.plot(current_range[t:], current_ts[t:], ls = '--', lw = .1, color = 'black') 57 | plt.autoscale(False) 58 | plt.ylim([-1, 1]) 59 | plt.legend() 60 | plt.savefig(path2save + base_name_series + str(i) + '.jpg') 61 | 62 | 63 | def portfolio(returns, weights): 64 | weights = np.array(weights) 65 | rets = returns.mean() * 252 66 | covs = returns.cov() * 252 67 | P_ret = np.sum(rets * weights) 68 | P_vol = np.sqrt(np.dot(weights.T, np.dot(covs, weights))) 69 | P_sharpe = P_ret / P_vol 70 | return np.array([P_ret, P_vol, P_sharpe]) 71 | 72 | def sharpe(R): 73 | r = np.diff(R) 74 | sr = r.mean()/r.std() * np.sqrt(252) 75 | return sr 76 | 77 | import statsmodels.api as sm 78 | from statsmodels import regression 79 | 80 | def print_stats(result, benchmark): 81 | 82 | sharpe_ratio = sharpe(np.array(result).cumsum()) 83 | returns = np.mean(np.array(result)) 84 | volatility = np.std(np.array(result)) 85 | 86 | X = benchmark 87 | y = result 88 | x = sm.add_constant(X) 89 | model = regression.linear_model.OLS(y, x).fit() 90 | alpha = model.params[0] 91 | beta = model.params[1] 92 | 93 | return np.round(np.array([returns, volatility, sharpe_ratio, alpha, beta]), 4).tolist() --------------------------------------------------------------------------------