def rebalance(context, data):
    # Wait for 756 trading days (3 yrs) of historical prices before trading
    if context.day < context.min_data_window - 1:
        return
    # Get expanding window of past prices and compute returns
    context.today = get_datetime().date() 
    prices = data.history(context.assets, "price", context.day, "1d")
    if context.first_rebal_date is None:
        context.first_rebal_date = context.today
        context.first_rebal_idx = context.day
        print('Starting dynamic allocation simulation...')
    # Get investment horizon in days ie number of trading days next month
    context.tau = rnr.get_num_days_nxt_month(context.today.month, context.today.year)
    # Calculate HFP distribution
    asset_rets = np.array(prices.pct_change(context.tau).iloc[context.tau:, :])
    num_scenarios = len(asset_rets)
    # Set Flexible Probabilities Using Exponential Smoothing
    half_life_prjn = 252 * 2 # in days
    lambda_prjn = np.log(2) / half_life_prjn
    probs_prjn = np.exp(-lambda_prjn * (np.arange(0, num_scenarios)[::-1]))
    probs_prjn = probs_prjn / sum(probs_prjn)
    mu_pc, sigma2_pc = rnr.fp_mean_cov(asset_rets.T, probs_prjn)
    # Perform shrinkage to mitigate estimation risk
    mu_shrk, sigma2_shrk = rnr.simple_shrinkage(mu_pc, sigma2_pc)
    weights, _, _ = rnr.efficient_frontier_qp_rets(context.n_portfolio, 
                                                          sigma2_shrk, mu_shrk)
    print('Optimal weights calculated 1 day before month end on %s (day=%s)' \
        % (context.today, context.day))
    #print(weights)
    min_var_weights = weights[0,:]
    # Rebalance portfolio accordingly
    for stock, weight in zip(prices.columns, min_var_weights):
        order_target_percent(stock, np.asscalar(weight))
    context.weights = min_var_weights
Exemplo n.º 2
0
n_scenarios = len(pnl_portfolio)

# Equal probs
equal_probs = np.ones(n_scenarios) / n_scenarios

# Time-conditioned flexible probs with exponential decay
half_life = 252 * 2  # half life of 2 years
es_lambda = math.log(2) / half_life
exp_probs = np.exp(-es_lambda * (np.arange(0, n_scenarios)[::-1]))
exp_probs = exp_probs / sum(exp_probs)
# effective number of scenarios
ens_exp_probs = np.exp(sum(-exp_probs * np.log(exp_probs)))

# Projected Distribution of Portfolio P&L at Horizon  with flexible probabilities
import rnr_meucci_functions as rnr
mu_port, sigma2_port = rnr.fp_mean_cov(pnl_portfolio.T, equal_probs)
mu_port_e, sigma2_port_e = rnr.fp_mean_cov(pnl_portfolio.T, exp_probs)

print(
    'Ex-ante portfolio $P&L mean over horizon (equal probs) : {:,.0f}'.format(
        mu_port))
print('Ex-ante portfolio $P&L volatility over horizon (equal probs) : {:,.0f}'.
      format(np.sqrt(sigma2_port)))
print('')
print('Ex-ante portfolio $P&L mean over horizon (flex probs) : {:,.0f}'.format(
    mu_port_e))
print('Ex-ante portfolio $P&L volatility over horizon (flex probs) : {:,.0f}'.
      format(np.sqrt(sigma2_port_e)))

fig = plt.figure(figsize=(9, 8))
ax = fig.add_subplot(111)
# distribution directly as input into mean-variance optimizer

# Projected linear returns to the horizon - historical simulation
asset_rets = np.array(prices.pct_change(tau).ix[tau:, asset_tickers])

# Mean-variance inputs
# Distribution of asset returns at horizon with flexible probabilities
# Time-conditioned flexible probs with exponential decay
half_life = 252 * 2  # half life of 2 years
es_lambda = math.log(2) / half_life
exp_probs = np.exp(-es_lambda * (np.arange(0, n_scenarios)[::-1]))
exp_probs = exp_probs / sum(exp_probs)

# Apply flexible probabilities to asset return scenarios
import rnr_meucci_functions as rnr
mu_pc, sigma2_pc = rnr.fp_mean_cov(asset_rets.T, exp_probs)

# Perform shrinkage to mitigate estimation risk
mu_shrk, cov_shrk = rnr.simple_shrinkage(mu_pc, sigma2_pc)

# Step 1: m-v quadratic optimization for efficient frontier
n_portfolio = 40
weights_pc, rets_pc, vols_pc = rnr.efficient_frontier_qp_rets(
    n_portfolio, cov_shrk, mu_shrk)

# Step 2: evaluate satisfaction for all allocations on the frontier
satisfaction_pc = -vols_pc

# Choose the allocation that maximises satisfaction
max_sat_idx = np.asscalar(np.argmax(satisfaction_pc))
max_sat = satisfaction_pc[max_sat_idx]
n_scenarios = len(pnl_portfolio)

# Equal probs
equal_probs = np.ones(n_scenarios) / n_scenarios

# Time-conditioned flexible probs with exponential decay
half_life = 252 * 2 # half life of 2 years
es_lambda = math.log(2) / half_life
exp_probs = np.exp(-es_lambda * (np.arange(0, n_scenarios)[::-1]))
exp_probs = exp_probs / sum(exp_probs)
# effective number of scenarios
ens_exp_probs = np.exp(sum(-exp_probs * np.log(exp_probs))) 

# Projected Distribution of Portfolio P&L at Horizon  with flexible probabilities
import rnr_meucci_functions as rnr
mu_port, sigma2_port = rnr.fp_mean_cov(pnl_portfolio.T, equal_probs)  
mu_port_e, sigma2_port_e = rnr.fp_mean_cov(pnl_portfolio.T, exp_probs)  

print('Ex-ante portfolio $P&L mean over horizon (equal probs) : {:,.0f}'.format(mu_port))
print('Ex-ante portfolio $P&L volatility over horizon (equal probs) : {:,.0f}'.format(np.sqrt(sigma2_port)))
print('')
print('Ex-ante portfolio $P&L mean over horizon (flex probs) : {:,.0f}'.format(mu_port_e))
print('Ex-ante portfolio $P&L volatility over horizon (flex probs) : {:,.0f}'.format(np.sqrt(sigma2_port_e)))

fig = plt.figure(figsize=(9, 8))
ax = fig.add_subplot(111)
ax.hist(pnl_portfolio, 50, weights=exp_probs) 
ax.set_title('Ex-ante Distribution of Portfolio P&L (flexbile probabilities with exponential decay)') 
plt.show()

Exemplo n.º 5
0
ax4.plot(vix.index,
         state_probs,
         marker='o',
         markersize=3,
         linestyle='None',
         alpha=0.7)
ax4.set_title("State-conditioned Probabilities (VIX > 20)")
plt.tight_layout()
plt.show()

# Stress analysis
import rnr_meucci_functions as rnr

tmp_tickers = ['AAPL', 'JPM', 'WMT', 'SPY', 'TLT']

# HFP distribution of invariants using equal probs
mu, sigma2 = rnr.fp_mean_cov(invariants.ix[:, tmp_tickers].T, equal_probs)

# HFP distribution of invariants using state-conditioned probs (VIX > 20)
mu_s, sigma2_s = rnr.fp_mean_cov(invariants.ix[:, tmp_tickers].T, state_probs)

# Calculate correlations
from statsmodels.stats.moment_helpers import cov2corr

corr = cov2corr(sigma2)
corr_s = cov2corr(sigma2_s)

# Plot correlation heatmaps
rnr.plot_2_corr_heatmaps(corr, corr_s, tmp_tickers,
                         "HFP Correlation Heatmap - equal probs",
                         "HFP Correlation Heatmap - state probs (VIX > 20)")
# distribution directly as input into mean-variance optimizer

# Projected linear returns to the horizon - historical simulation 
asset_rets = np.array(prices.pct_change(tau).ix[tau:, asset_tickers]) 

# Mean-variance inputs
# Distribution of asset returns at horizon with flexible probabilities
# Time-conditioned flexible probs with exponential decay
half_life = 252 * 2 # half life of 2 years
es_lambda = math.log(2) / half_life
exp_probs = np.exp(-es_lambda * (np.arange(0, n_scenarios)[::-1]))
exp_probs = exp_probs / sum(exp_probs)

# Apply flexible probabilities to asset return scenarios
import rnr_meucci_functions as rnr
mu_pc, sigma2_pc = rnr.fp_mean_cov(asset_rets.T, exp_probs)

# Perform shrinkage to mitigate estimation risk
mu_shrk, cov_shrk = rnr.simple_shrinkage(mu_pc, sigma2_pc)

# Step 1: m-v quadratic optimization for efficient frontier
n_portfolio = 40
weights_pc, rets_pc, vols_pc = rnr.efficient_frontier_qp_rets(n_portfolio, 
                                                              cov_shrk, mu_shrk)

# Step 2: evaluate satisfaction for all allocations on the frontier
satisfaction_pc = -vols_pc

# Choose the allocation that maximises satisfaction
max_sat_idx = np.asscalar(np.argmax(satisfaction_pc))
max_sat = satisfaction_pc[max_sat_idx]