def bollinger_mean_revert(x, y, model=None): if model is None: model = bollinger_mean_revert_fit(x, y) lookback = model['lookback'] hedge_lookback = model['hedge_lookback'] entry_z_score = model['entry_z_score'] exit_z_score = model['exit_z_score'] static_hedges = model.get('static_hedges') or False # Setup mean reversion portfolio to use for tradable zScore strategy = rolling_hedge_mean_revert_strategy (prices, weights, units) = strategy(x, y, lookback, hedge_lookback) port = portfolio.portfolio_price(prices, weights) # Ok, now let's look at the half-life of this portfolio, this needs to be low (under 30) # TODO: Test this? Throw it out if it doesn't meet standard? halflife = mr.halflife(port) cadf = sms.adfuller(port, maxlag=1, regression='c')[0] hurst = mr.hurst_exponent(port.pct_change().fillna(0))[0] # Collect zScore and theoretical results in the form of a sharpe ratio zScore = util.rolling_z_score(port, lookback) rets = portfolio.portfolio_returns(prices, weights, -zScore)['returns'] theoretical_sharpe = returns.annual_sharpe(rets) # Collect units of this portfolio according to bollinger band strategy (buying and selling # against the given zScore) units = bollinger_band_units(zScore, entryZScore=entry_z_score, exitZScore=exit_z_score) # Random experiment - static weights. Basically, force hedge weights to be static for the duration # of any particular trade. if static_hedges == True: unit_changes = units != units.shift().fillna(0) weights[~unit_changes] = np.nan weights['x'][0] = 0 weights['y'][0] = 0 weights = weights.fillna(method='ffill') # Finally, collect the results results = { 'lookback': lookback, 'hedge_lookback': hedge_lookback, 'static_hedges': static_hedges, 'halflife': halflife, 'cadf': cadf, 'hurst': hurst, 'theoretical_sharpe': theoretical_sharpe, 'prices': prices, 'weights': weights, 'units': units } port_rets = portfolio.portfolio_returns(prices, weights, units) results.update(port_rets) rets = port_rets['returns'] results.update( returns.report(rets)) results.update( report(units)) return results
def portfolio_price_test(): port = portfolio.portfolio_price(prices, [1, -0.4]) assert_almost_equals(port.iloc[0], 5.6539, places=4) assert_almost_equals(port.iloc[1], 5.6344, places=4) assert_almost_equals(port.iloc[-2], 9.1112, places=4) assert_almost_equals(port.iloc[-1], 9.0446, places=4)