# Box 8.1
import numpy as np
import pandas as pd
# import matplotlib.pyplot as plt
# import statsmodels.formula.api as sm
# import statsmodels.tsa.stattools as ts
# import statsmodels.tsa.vector_ar.vecm as vm
from scipy.optimize import minimize
# from scipy.stats import describe
from scipy.stats import pearson3

df = pd.read_csv('AUDCAD_unequal_ret.csv')

skew_, loc_, scale_ = pearson3.fit(df)
print('skew=%f loc=%f scale=%f' % (skew_, loc_, scale_))
mean, var, skew, kurt = pearson3.stats(skew_, loc_, scale_, moments='mvks')
print('mean=%f var=%f skew=%f kurt=%f' % (mean, var, skew, kurt))

ret_sim = pearson3.rvs(skew_, loc_, scale_, size=100000, random_state=0)


def g(f, R):
    return np.sum(np.log(1 + f * R), axis=0) / R.shape[0]


myf = range(1, 24)
myg = np.full(24, np.NaN)

for f in myf:
    myg[f] = g(f, ret_sim)

myg = myg[1:]
myg = pd.DataFrame(myg)
myg.plot()

minusG = lambda f: -g(f, df)
minusGsim = lambda f: -g(f, ret_sim)

# optimal leverage based on simulated returns
res = minimize(minusGsim, 0, method='Nelder-Mead')
optimalF = res.x
print('Optimal leverage=%f optimal growth rate=%f' % (optimalF, -res.fun))
# Optimal leverage=25.512625 optimal growth rate=0.005767

minR = np.min(ret_sim)
print('minR=%f' % (minR))
# minR=-0.018201

# max drawdown with optimal leverage
from calculateMaxDD import calculateMaxDD

maxDD, maxDDD, i = calculateMaxDD((np.cumproduct(1 + optimalF * ret_sim) - 1))
print('Max DD=%f with optimal leverage=%f' % (maxDD, optimalF))
# Max DD=-0.996312 with optimal leverage=25.512625

# max drawdown with half of optimal leverage
maxDD, maxDDD, i = calculateMaxDD((np.cumproduct(1 + optimalF / 2 * ret_sim) - 1))
print('Max DD=%f with half optimal leverage=%f' % (maxDD, optimalF / 2))
# Max DD=-0.900276 with half optimal leverage=12.756313

# max drawdown with 1/7 of optimal leverage
maxDD, maxDDD, i = calculateMaxDD((np.cumproduct(1 + optimalF / 7 * ret_sim) - 1))
print('Max DD=%f with half optimal leverage=%f' % (maxDD, optimalF / 7))
# Max DD=-0.429629 with half optimal leverage=3.644661

# max drawdown with 1/1.4 of optimal leverage for historical returns
maxDD, maxDDD, i = calculateMaxDD((np.cumproduct(1 + optimalF / 1.4 * df.values) - 1))
print('Max DD=%f with historical returns=%f' % (maxDD, optimalF / 1.4))
# Max DD=-0.625894 with historical returns=18.223304

D = 0.5
print('Growth rate on simulated returns using D=%3.1f of optimal leverage on full account=%f' % (
D, -minusGsim(optimalF * D)))
# Growth rate on simulated returns using D=0.5 of optimal leverage on full account=0.004317
maxDD, maxDDD, i = calculateMaxDD((np.cumproduct(1 + optimalF * D * ret_sim) - 1))
print('MaxDD on simulated returns using D of optimal leverage on full account=%f' % (maxDD))
# MaxDD on simulated returns using D of optimal leverage on full account=-0.900276

# CPPI
g_cppi = 0
drawdown = 0
for t in range(ret_sim.shape[0]):
    g_cppi += np.log(1 + ret_sim[t] * D * optimalF * (1 + drawdown))
    drawdown = min([0, (1 + drawdown) * (1 + ret_sim[t]) - 1])

g_cppi = g_cppi / len(ret_sim)
print('Growth rate on simulated returns using CPPI=%f' % g_cppi)
# Growth rate on simulated returns using CPPI=0.004264
print('Growth rate on historical returns using D of optimal leverage on full account=%f' % (-minusG(optimalF * D)))
# Growth rate on historical returns using D of optimal leverage on full account=0.004053
maxDD, maxDDD, i = calculateMaxDD((np.cumproduct(1 + optimalF * D * df.values) - 1))
print('MaxDD on historical returns using D of optimal leverage on full account=%f' % (maxDD))
# MaxDD on historical returns using D of optimal leverage on full account=-0.303448

# CPPI
g_cppi = 0
drawdown = 0
for t in range(df.shape[0]):
    g_cppi += np.log(1 + df.iloc[t,] * D * optimalF * (1 + drawdown))
    drawdown = np.min([0, (1 + drawdown) * (1 + df.iloc[t,]) - 1])

g_cppi = g_cppi / len(df)
print('Growth rate on historical returns CPPI=%f' % (g_cppi))
