Files

164 lines
5.7 KiB
Python
Raw Permalink Normal View History

2018-05-19 02:18:43 -07:00
import os
import math
import numpy as np
import pandas as pd
from scipy.stats import norm
import matplotlib.pyplot as plt
from backend.config import currencies
file = 'history/AUD_JPY_D.csv'
folder = 'history/'
def monteCarloSimulation(file, n_days, n_iters):
"""
file: csv file containing at least a 'Close' column with asset prices inside
n_days: the number of days to simulate retruns for
n_iters: the number of different simulations to run
returns the price_matrix of the simulation
"""
# import data
df = pd.read_csv(file)
prices = df['Close']
# set formula's variables
log_returns = np.log(1 + prices.pct_change())
u = log_returns.mean()
var = log_returns.var()
drift = u - (0.5 * var)
std = log_returns.std()
drift = pd.Series(drift)
std = pd.Series(std)
z = norm.ppf(np.random.rand(n_days, n_iters))
# generate future daily returns
daily_returns = np.exp(drift.values + std.values * z)
p0 = prices.iloc[-1] # last price in our original data is the first price in our simulation
price_matrix = np.zeros_like(daily_returns)
price_matrix[0] = p0
# start the simulation
for t in range(1, n_days):
price_matrix[t] = price_matrix[t-1] * daily_returns[t]
plt.plot(price_matrix)
plt.show()
return price_matrix
# Brownian motion
def Brownian(seed, N):
np.random.seed(seed)
dt = 1/N # timestep
b = np.random.normal(0., 1., int(N)) * np.sqrt(dt) # Brownian normal increments
W = np.cumsum(b) #Brownian path
return W, b
# Geometric Brownian Motion
def GBM(p0, mu, sigma, W, T, N):
t = np.linspace(0., 1., N+1)
P = list()
P.append(p0)
for i in range(1, int(N + 1)):
drift = (mu - 0.5 * sigma ** 2) * t[i]
diffusion = sigma * W[i-1]
p_temp = p0 * np.exp(drift + diffusion)
P.append(p_temp)
return P, t
# Euler Maruyama Approximation
def eulerApprox(p0, mu, sigma, b, T, N, M):
dt = M * (1/N) # step size
L = N / M
wi = [p0]
for i in range(0, int(L)):
Winc = np.sum(b[(M * (i - 1) + M) : (M * i + M)])
w_i_new = wi[i] + mu * wi[i] * dt + sigma * wi[i] * Winc
wi.append(w_i_new)
return wi, dt
# plot these stochastic compared to a given asset
def plot_stochastics(file, seed1, seed2, seed3):
df = pd.read_csv(file)
n = len(df) - 1
returns = df['Close'].pct_change()
p0 = df['Close'][n]
N = 2.0 ** 6
W1 = Brownian(seed1, N)[0]
W2 = Brownian(seed2, N)[0]
W3 = Brownian(seed3, N)[0]
T = 1.0
mu = np.mean(returns) * 252.0
sigma = np.std(returns) * np.sqrt(252.0)
gbm1 = GBM(p0, mu, sigma, W1, T, N)[0]
gbm2 = GBM(p0, mu, sigma, W2, T, N)[0]
gbm3 = GBM(p0, mu, sigma, W3, T, N)[0]
t = GBM(p0, mu, sigma, W1, T, N)[1]
plt.plot(t, gbm1, label='GMB1', ls='--')
plt.plot(t, gbm2, label='GBM2', ls='--')
plt.plot(t, gbm3, label='GBM3', ls='--')
plt.plot(t, df['Close'][-65:], label='Actual')
plt.ylabel('Asset Price, $')
plt.title('Geometric Brownian Motion')
plt.legend(loc='upper left')
plt.show()
# Markowitz Portfolio optimization, efficient frontier, MPT, etc.
def optimalPortfolio(asset_list, n_portfolios=2500):
"""
asset_list: list of asset symbols to extract
type: CSV or GET; CSV from local file or GET from yahoo
"""
data = pd.DataFrame()
# get asset pricing from local data
if type == 'csv':
for asset in asset_list:
folder = 'history/'
name_window = '%s_D' % asset
for files in os.walk(folder):
for f in files[2]:
if name_window in f:
f = os.path.join(folder, f)
df = pd.read_csv(f)
data[asset] = df['Close']
elif type == 'GET':
for asset in asset_list:
s = stock(asset).chart_table(range='1y')
data[asset] = s['close']
# convert prices to returns and calculate daily mean returns and covariance
returns = data.pct_change()
n = returns.shape[1]
mean_daily_returns = returns.mean()
cov_matrix = returns.cov()
# set array to hold results
results = np.zeros((3+n, n_portfolios))
# calculate the n portfolios
for i in range(n_portfolios):
# set random weights; rebalance weights to sum 1
weights = np.random.random(n)
weights /= np.sum(weights)
# calculate portfolio return and volatility
port_return = np.sum(mean_daily_returns * weights) * 252
port_std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252)
# store results and calculate/store Sharpe ratio
results[0,i] = port_return
results[1,i] = port_std
results[2,i] = results[0,i] / results[1,i]
# iterate through weight vector and add weights to the results
for j in range(len(weights)):
results[j+3,i] = weights[j]
# plot results
cols = ['Returns', 'Std', 'Sharpe'] + asset_list
results_frame = pd.DataFrame(results.T, columns=cols)
max_sharpe_port = results_frame.iloc[results_frame['Sharpe'].idxmax()]
min_vol_port = results_frame.iloc[results_frame['Std'].idxmin()]
plt.scatter(results_frame.Std, results_frame.Returns, c=results_frame.Sharpe, cmap='RdYlBu')
plt.colorbar()
plt.ylabel('Returns')
plt.xlabel('Volatility')
plt.title('Portfolio optimization test for %d portfolios with %d assets' % (n_portfolios, n))
plt.scatter(max_sharpe_port[1], max_sharpe_port[0], marker=(5,1,0), color='r', s=1000)
plt.scatter(min_vol_port[1], min_vol_port[0], marker=(5,1,0), color='g', s=1000)
plt.show()
print("Portfolio weights with the best returns: ", max_sharpe_port)
print("Portfolio weights with the lowest volatility: ", min_vol_port)