def test_robust_vol_calc_min_period(self): prices = get_data("syscore.tests.pricetestdata_min_period.csv") returns = prices.diff() vol = robust_vol_calc(returns, min_periods=9) self.assertAlmostEqual(vol.iloc[-1], 0.45829858614978286) vol = robust_vol_calc(returns, min_periods=10) self.assertTrue(np.isnan(vol.iloc[-1]))
def test_robust_vol_calc_min_period(self): prices = pd_readcsv_frompackage( "syscore", "pricetestdata_min_period.csv", ["tests"]) returns = prices.diff() vol = robust_vol_calc(returns, min_periods=9) self.assertAlmostEqual(vol.iloc[-1, 0], 0.45829858614978286) vol = robust_vol_calc(returns, min_periods=10) self.assertTrue(np.isnan(vol.iloc[-1][0]))
def test_robust_vol_calc(self): prices = get_data("syscore.tests.pricetestdata.csv") returns = prices.diff() vol = robust_vol_calc(returns, days=35) self.assertAlmostEqual(vol.iloc[-1], 0.41905275480464305) vol = robust_vol_calc(returns, days=100) self.assertAlmostEqual(vol.iloc[-1], 0.43906619578902956)
def test_robust_vol_calc(self): prices = pd_readcsv_frompackage( "syscore", "pricetestdata.csv", ["tests"]) returns = prices.diff() vol = robust_vol_calc(returns, days=35) self.assertAlmostEqual(vol.iloc[-1, 0], 0.41905275480464305) vol = robust_vol_calc(returns, days=100) self.assertAlmostEqual(vol.iloc[-1, 0], 0.43906619578902956)
def test_robust_vol_calc_floor(self): prices = pd_readcsv_frompackage( "syscore.tests.pricetestdata_vol_floor.csv") returns = prices.diff() vol = robust_vol_calc(returns) self.assertAlmostEqual(vol.iloc[-1, 0], 0.54492982003602064) vol = robust_vol_calc(returns, vol_floor=False) self.assertAlmostEqual(vol.iloc[-1, 0], 0.42134038479240132) vol = robust_vol_calc(returns, floor_min_quant=.5) self.assertAlmostEqual(vol.iloc[-1, 0], 1.6582199589924964) vol = robust_vol_calc(returns, floor_min_periods=500) self.assertAlmostEqual(vol.iloc[-1, 0], 0.42134038479240132) vol = robust_vol_calc(returns, floor_days=10, floor_min_periods=5) self.assertAlmostEqual(vol.iloc[-1, 0], 0.42134038479240132)
def calc_ewmac_forecast(price, Lfast, Lslow): price=price.resample("1B", how="last") fast_ewma = pd.ewma(price, span=Lfast) slow_ewma = pd.ewma(price, span=Lslow) raw_ewmac = fast_ewma - slow_ewma vol = robust_vol_calc(price.diff()) return raw_ewmac / vol
def get_scatter_data_for_code_vol( system, instrument_code, rule_name, return_period=5, days=64): denom_price = system.rawdata.daily_denominator_price(instrument_code) x = system.rawdata.daily_returns(instrument_code) vol = robust_vol_calc(x, days) perc_vol = 100.0 * divide_df_single_column(vol, denom_price.shift(1)) volavg = pd.rolling_median(perc_vol, 1250, min_periods=10) vol_qq = (perc_vol - volavg) / volavg # work out return for the N days after the forecast norm_data = system.accounts.pandl_for_instrument_forecast( instrument_code, rule_name) (vol_qq, norm_data) = align_to_joint( vol_qq, norm_data, ffill=(True, False)) period_returns = pd.rolling_sum(norm_data, return_period, min_periods=1) ex_post_returns = period_returns.shift(-return_period) lagged_vol = vol_qq.shift(1) return (list(ex_post_returns.iloc[:, 0].values), list( lagged_vol.iloc[:, 0].values))
def sharpe(price, forecast): """ Herein the proof why this position calculation is correct (see chapters 5-11 of 'systematic trading' book) Position = forecast x instrument weight x instrument_div_mult x vol_scalar / 10.0 = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x instr value volatility) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x instr ccy volatility x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x block value x % price volatility x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x underlying price x 0.01 x value of price move x 100 x price change volatility/(underlying price) x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x value of price move x price change volatility x fx rate) Making some arbitrary assumptions (one instrument, 100% of capital, daily target DAILY_CAPITAL): = forecast x 1.0 x 1.0 x DAILY_CAPITAL / (10.0 x value of price move x price diff volatility x fx rate) = forecast x multiplier / (value of price move x price change volatility x fx rate) """ base_capital = DEFAULT_CAPITAL daily_risk_capital = DEFAULT_CAPITAL * DEFAULT_ANN_RISK_TARGET / ROOT_BDAYS_INYEAR ts_capital=pd.Series(np.ones(len(price)) * DEFAULT_CAPITAL, index=price.index) ann_risk = ts_capital * DEFAULT_ANN_RISK_TARGET daily_returns_volatility = robust_vol_calc(price.diff()) multiplier = daily_risk_capital * 1.0 * 1.0 / 10.0 numerator = forecast * multiplier positions = numerator.ffill() / daily_returns_volatility.ffill() cum_trades = positions.shift(1).ffill() price_returns = price.diff() instr_ccy_returns = cum_trades.shift(1)*price_returns instr_ccy_returns=instr_ccy_returns.cumsum().ffill().reindex(price.index).diff() mean_return = instr_ccy_returns.mean() * BUSINESS_DAYS_IN_YEAR vol = instr_ccy_returns.std() * ROOT_BDAYS_INYEAR return mean_return / vol
def ewmac_forecast_with_defaults(price, Lfast=32, Lslow=128): """ Calculate the ewmac trading fule forecast, given a price and EWMA speeds Lfast, Lslow and vol_lookback Assumes that 'price' is daily data This version recalculates the price volatility, and does not do capping or scaling :param price: The price or other series to use (assumed Tx1) :type price: pd.DataFrame :param Lfast: Lookback for fast in days :type Lfast: int :param Lslow: Lookback for slow in days :type Lslow: int :returns: pd.DataFrame -- unscaled, uncapped forecast """ # price: This is the stitched price series # We can't use the price of the contract we're trading, or the volatility will be jumpy # And we'll miss out on the rolldown. See # http://qoppac.blogspot.co.uk/2015/05/systems-building-futures-rolling.html # We don't need to calculate the decay parameter, just use the span # directly fast_ewma = pd.ewma(price, span=Lfast) slow_ewma = pd.ewma(price, span=Lslow) raw_ewmac = fast_ewma - slow_ewma vol = robust_vol_calc(price.diff()) return divide_df_single_column(raw_ewmac, vol, ffill=(False, True))
def calc_ewmac_forecast(price, Lfast, Lslow=None): """ Calculate the ewmac trading fule forecast, given a price and EWMA speeds Lfast, Lslow and vol_lookback """ # price: This is the stitched price series # We can't use the price of the contract we're trading, or the volatility will be jumpy # And we'll miss out on the rolldown. See # http://qoppac.blogspot.co.uk/2015/05/systems-building-futures-rolling.html price=price.resample("1B", how="last") if Lslow is None: Lslow = 4 * Lfast # We don't need to calculate the decay parameter, just use the span # directly fast_ewma = pd.ewma(price, span=Lfast) slow_ewma = pd.ewma(price, span=Lslow) raw_ewmac = fast_ewma - slow_ewma vol = robust_vol_calc(price.diff()) return divide_df_single_column(raw_ewmac, vol)
def _get_daily_returns_volatility(system, instrument_code): if hasattr(system, "rawdata"): returns_vol=system.rawdata.daily_returns_volatility(instrument_code) else: price = system.data.get_instrument_price(instrument_code) price = price.resample("1B", how="last") returns_vol = robust_vol_calc(price.diff()) return returns_vol
def _get_daily_returns_volatility(system, instrument_code): if hasattr(system, "rawdata"): returns_vol = system.rawdata.daily_returns_volatility( instrument_code) else: price = self.get_daily_price(instrument_code) returns_vol = robust_vol_calc(price.diff()) return returns_vol
def _get_price_volatility(system, instrument_code, this_stage_notused): if hasattr(system, "rawdata"): daily_perc_vol = system.rawdata.get_daily_percentage_volatility( instrument_code) else: price = system.data.daily_prices(instrument_code) return_vol = robust_vol_calc(price.diff()) daily_perc_vol = 100.0 * return_vol / price return daily_perc_vol
def _get_price_volatility(system, instrument_code): if hasattr(system, "rawdata"): daily_perc_vol = system.rawdata.get_daily_percentage_volatility( instrument_code) else: price = system.data.get_instrument_price(instrument_code) price = price.resample("1B", how="last") return_vol = robust_vol_calc(price.diff()) daily_perc_vol = 100.0 * divide_df_single_column(return_vol, price) return daily_perc_vol
def _get_price_volatility(system, instrument_code): if hasattr(system, "rawdata"): daily_perc_vol = system.rawdata.get_daily_percentage_volatility( instrument_code) else: price = system.data.daily_prices(instrument_code) return_vol = robust_vol_calc(price.diff()) daily_perc_vol = 100.0 * \ divide_df_single_column(return_vol, price) return daily_perc_vol
def test_robust_vol_calc_floor(self): prices = pd_readcsv_frompackage( "syscore.tests.pricetestdata_vol_floor.csv") returns = prices.diff() vol = robust_vol_calc(returns) self.assertAlmostEqual(vol.iloc[-1][0], 0.54492982003602064) vol = robust_vol_calc(returns, vol_floor=False) self.assertAlmostEqual(vol.iloc[-1][0], 0.42134038479240132) vol = robust_vol_calc(returns, floor_min_quant=.5) self.assertAlmostEqual(vol.iloc[-1][0], 1.6582199589924964) vol = robust_vol_calc(returns, floor_min_periods=500) self.assertAlmostEqual(vol.iloc[-1][0], 0.42134038479240132) vol = robust_vol_calc(returns, floor_days=10, floor_min_periods=5) self.assertAlmostEqual(vol.iloc[-1][0], 0.42134038479240132)
def skew(price, forecast): base_capital = DEFAULT_CAPITAL daily_risk_capital = DEFAULT_CAPITAL * DEFAULT_ANN_RISK_TARGET / ROOT_BDAYS_INYEAR use_fx = pd.Series([1.0] * len(price.index),index=price.index) get_daily_returns_volatility = robust_vol_calc(price.diff()) multiplier = daily_risk_capital * 1.0 * 1.0 / 10.0 denominator = get_daily_returns_volatility* use_fx numerator = forecast * multiplier positions = numerator.ffill() / denominator.ffill() cum_trades = positions.shift(1).ffill() trades_to_use=cum_trades.diff() price_returns = price.diff() instr_ccy_returns = cum_trades.shift(1)* price_returns instr_ccy_returns=instr_ccy_returns.cumsum().ffill().reindex(price.index).diff() pct = 100.0 * instr_ccy_returns / base_capital return scipy.stats.skew(pct[pd.isnull(pct) == False])
def ewmac_calc_vol(price, Lfast, Lslow, vol_days=35): """ Calculate the ewmac trading fule forecast, given a price and EWMA speeds Lfast, Lslow and vol_lookback Assumes that 'price' and vol is daily data This version recalculates the price volatility, and does not do capping or scaling :param price: The price or other series to use (assumed Tx1) :type price: pd.Series :param Lfast: Lookback for fast in days :type Lfast: int :param Lslow: Lookback for slow in days :type Lslow: int :returns: pd.DataFrame -- unscaled, uncapped forecast >>> from systems.tests.testdata import get_test_object_futures >>> from systems.basesystem import System >>> (rawdata, data, config)=get_test_object_futures() >>> system=System( [rawdata], data, config) >>> >>> ewmac(rawdata.get_daily_prices("EDOLLAR"), rawdata.daily_returns_volatility("EDOLLAR"), 64, 256).tail(2) 2015-12-10 5.327019 2015-12-11 4.927339 Freq: B, dtype: float64 """ # price: This is the stitched price series # We can't use the price of the contract we're trading, or the volatility will be jumpy # And we'll miss out on the rolldown. See # http://qoppac.blogspot.co.uk/2015/05/systems-building-futures-rolling.html # We don't need to calculate the decay parameter, just use the span # directly fast_ewma = price.ewm(span=Lfast).mean() slow_ewma = price.ewm(span=Lslow).mean() raw_ewmac = fast_ewma - slow_ewma vol = robust_vol_calc(price, vol_days) return raw_ewmac / vol.ffill()
def get_price_volatility(self, instrument_code): """ Get the daily % volatility; If a rawdata stage exists from there; otherwise work it out :param instrument_code: instrument to get values for :type instrument_code: str :returns: Tx1 pd.DataFrame KEY INPUT Note as an exception to the normal rule we cache this, as it sometimes comes from data >>> from systems.tests.testdata import get_test_object_futures_with_comb_forecasts >>> from systems.basesystem import System >>> (comb, fcs, rules, rawdata, data, config)=get_test_object_futures_with_comb_forecasts() >>> system=System([rawdata, rules, fcs, comb, PositionSizing()], data, config) >>> >>> system.positionSize.get_price_volatility("EDOLLAR").tail(2) vol 2015-12-10 0.055281 2015-12-11 0.059789 >>> >>> system2=System([ rules, fcs, comb, PositionSizing()], data, config) >>> >>> system2.positionSize.get_price_volatility("EDOLLAR").tail(2) vol 2015-12-10 0.055318 2015-12-11 0.059724 """ system = self.parent if hasattr(system, "rawdata"): daily_perc_vol = system.rawdata.get_daily_percentage_volatility( instrument_code) else: price = system.data.daily_prices(instrument_code) return_vol = robust_vol_calc(price.diff()) daily_perc_vol = 100.0 * return_vol / price return daily_perc_vol
def get_daily_returns_volatility(self, instrument_code): """ Get the daily return (not %) volatility from previous stage, or calculate KEY INPUT :param instrument_code: :type str: :returns: Tx1 pd.DataFrames """ system = self.parent if hasattr(system, "rawdata"): returns_vol = system.rawdata.daily_returns_volatility( instrument_code) else: price = self.get_daily_price(instrument_code) returns_vol = robust_vol_calc(price.diff()) return returns_vol
def ewmac_forecast_with_defaults(price, Lfast=32, Lslow=128): """ Calculate the ewmac trading fule forecast, given a price and EWMA speeds Lfast, Lslow and vol_lookback Assumes that 'price' is daily data This version recalculates the price volatility, and does not do capping or scaling :param price: The price or other series to use (assumed Tx1) :type price: pd.Series :param Lfast: Lookback for fast in days :type Lfast: int :param Lslow: Lookback for slow in days :type Lslow: int :returns: pd.DataFrame -- unscaled, uncapped forecast """ # price: This is the stitched price series # We can't use the price of the contract we're trading, or the volatility # will be jumpy # And we'll miss out on the rolldown. See # https://qoppac.blogspot.com/2015/05/systems-building-futures-rolling.html # We don't need to calculate the decay parameter, just use the span # directly fast_ewma = price.ewm(span=Lfast).mean() slow_ewma = price.ewm(span=Lslow).mean() raw_ewmac = fast_ewma - slow_ewma vol = robust_vol_calc(price.diff()) return raw_ewmac / vol
def calc_ewmac_forecast(price, Lfast, Lslow=None): """ Calculate the ewmac trading fule forecast, given a price and EWMA speeds Lfast, Lslow and vol_lookback """ # price: This is the stitched price series # We can't use the price of the contract we're trading, or the volatility # will be jumpy # And we'll miss out on the rolldown. See # http://qoppac.blogspot.co.uk/2015/05/systems-building-futures-rolling.html if Lslow is None: Lslow = 4 * Lfast # We don't need to calculate the decay parameter, just use the span # directly fast_ewma = price.ewm(span=Lfast).mean() slow_ewma = price.ewm(span=Lslow).mean() raw_ewmac = fast_ewma - slow_ewma vol = robust_vol_calc(price.diff()) return raw_ewmac / vol
Making some arbitrary assumptions (one instrument, 100% of capital, daily target DAILY_CAPITAL): = forecast x 1.0 x 1.0 x DAILY_CAPITAL / (10.0 x value of price move x price diff volatility x fx rate) = forecast x multiplier / (value of price move x price change volatility x fx rate) """ base_capital = DEFAULT_CAPITAL daily_risk_capital = DEFAULT_CAPITAL * DEFAULT_ANN_RISK_TARGET / ROOT_BDAYS_INYEAR ts_capital=pd.Series(np.ones(len(price)) * DEFAULT_CAPITAL, index=price.index) ann_risk = ts_capital * DEFAULT_ANN_RISK_TARGET daily_returns_volatility = robust_vol_calc(price.diff()) multiplier = daily_risk_capital * 1.0 * 1.0 / 10.0 numerator = forecast * multiplier positions = numerator.ffill() / daily_returns_volatility.ffill() cum_trades = positions.shift(1).ffill() price_returns = price.diff() instr_ccy_returns = cum_trades.shift(1)*price_returns instr_ccy_returns=instr_ccy_returns.cumsum().ffill().reindex(price.index).diff() mean_return = instr_ccy_returns.mean() * BUSINESS_DAYS_IN_YEAR vol = instr_ccy_returns.std() * ROOT_BDAYS_INYEAR return mean_return / vol if __name__ == "__main__": f = '../sysdata/legacycsv/EDOLLAR_price.csv' df = pd.read_csv(f,index_col=0,parse_dates=True) fast_ewma = pd.ewma(df.PRICE, span=32) slow_ewma = pd.ewma(df.PRICE, span=128) raw_ewmac = fast_ewma - slow_ewma vol = robust_vol_calc(df['PRICE'].diff()) forecast = raw_ewmac / vol print (sharpe(df.PRICE, forecast))
def test_robust_vol_calc_min_value(self): prices = pd_readcsv_frompackage( "syscore.tests.pricetestdata_zero_vol.csv") returns = prices.diff() vol = robust_vol_calc(returns, vol_abs_min=0.01) self.assertEqual(vol.iloc[-1, 0], 0.01)
""" base_capital = DEFAULT_CAPITAL daily_risk_capital = DEFAULT_CAPITAL * DEFAULT_ANN_RISK_TARGET / ROOT_BDAYS_INYEAR ts_capital = pd.Series(np.ones(len(price)) * DEFAULT_CAPITAL, index=price.index) ann_risk = ts_capital * DEFAULT_ANN_RISK_TARGET daily_returns_volatility = robust_vol_calc(price.diff()) multiplier = daily_risk_capital * 1.0 * 1.0 / 10.0 numerator = forecast * multiplier positions = numerator.ffill() / daily_returns_volatility.ffill() cum_trades = positions.shift(1).ffill() price_returns = price.diff() instr_ccy_returns = cum_trades.shift(1) * price_returns instr_ccy_returns = instr_ccy_returns.cumsum().ffill().reindex( price.index).diff() mean_return = instr_ccy_returns.mean() * BUSINESS_DAYS_IN_YEAR vol = instr_ccy_returns.std() * ROOT_BDAYS_INYEAR return mean_return / vol if __name__ == "__main__": f = '../sysdata/legacycsv/EDOLLAR_price.csv' df = pd.read_csv(f, index_col=0, parse_dates=True) fast_ewma = pd.ewma(df.PRICE, span=32) slow_ewma = pd.ewma(df.PRICE, span=128) raw_ewmac = fast_ewma - slow_ewma vol = robust_vol_calc(df['PRICE'].diff()) forecast = raw_ewmac / vol print(sharpe(df.PRICE, forecast))
def get_positions_from_forecasts(price, get_daily_returns_volatility, forecast, fx, value_of_price_point, **kwargs): """ Work out position using forecast, volatility, fx, value_of_price_point (this will be for an arbitrary daily risk target) If volatility is not provided, work out from price (uses a standard method so may differ from precise system p&l) :param price: price series :type price: Tx1 pd.DataFrame :param get_daily_returns_volatility: series of volatility estimates. NOT % volatility, price difference vol :type get_daily_returns_volatility: Tx1 pd.DataFrame or None :param forecast: series of forecasts, needed to work out positions :type forecast: Tx1 pd.DataFrame :param fx: series of fx rates from instrument currency to base currency, to work out p&l in base currency :type fx: Tx1 pd.DataFrame :param value_of_price_point: value of one unit movement in price :type value_of_price_point: float **kwargs: passed to vol calculation :returns: Tx1 pd dataframe of positions """ if forecast is None: raise Exception( "If you don't provide a series of trades or positions, I need a " "forecast") if get_daily_returns_volatility is None: get_daily_returns_volatility = robust_vol_calc(price.diff(), **kwargs) """ Herein the proof why this position calculation is correct (see chapters 5-11 of 'systematic trading' book) Position = forecast x instrument weight x instrument_div_mult x vol_scalar / 10.0 = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x instr value volatility) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x instr ccy volatility x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x block value x % price volatility x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x underlying price x 0.01 x value of price move x 100 x price diff volatility/(underlying price) x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x value of price move x price change volatility x fx rate) Making some arbitrary assumptions (one instrument, 100% of capital, daily target DAILY_CAPITAL): = forecast x 1.0 x 1.0 x DAILY_CAPITAL / (10.0 x value of price move x price diff volatility x fx rate) = forecast x multiplier / (value of price move x price change volatility x fx rate) """ multiplier = DAILY_CAPITAL * 1.0 * 1.0 / 10.0 fx = fx.reindex(get_daily_returns_volatility.index, method="ffill") denominator = (value_of_price_point * multiply_df_single_column( get_daily_returns_volatility, fx, ffill=(False, True))) position = divide_df_single_column(forecast * multiplier, denominator, ffill=(True, True)) position.columns = ['position'] return position
def get_positions_from_forecasts(price, get_daily_returns_volatility, forecast, fx, value_of_price_point, capital, ann_risk_target, **kwargs): """ Work out position using forecast, volatility, fx, value_of_price_point (this will be for an arbitrary daily risk target) If volatility is not provided, work out from price (uses a standard method so may differ from precise system p&l) :param price: price series :type price: Tx1 pd.DataFrame :param get_daily_returns_volatility: series of volatility estimates. NOT % volatility, price difference vol :type get_daily_returns_volatility: Tx1 pd.DataFrame or None :param forecast: series of forecasts, needed to work out positions :type forecast: Tx1 pd.DataFrame :param fx: series of fx rates from instrument currency to base currency, to work out p&l in base currency :type fx: Tx1 pd.DataFrame :param value_of_price_point: value of one unit movement in price :type value_of_price_point: float **kwargs: passed to vol calculation :returns: Tx1 pd dataframe of positions """ if forecast is None: raise Exception( "If you don't provide a series of trades or positions, I need a " "forecast") if get_daily_returns_volatility is None: get_daily_returns_volatility = robust_vol_calc(price.diff(), **kwargs) """ Herein the proof why this position calculation is correct (see chapters 5-11 of 'systematic trading' book) Position = forecast x instrument weight x instrument_div_mult x vol_scalar / 10.0 = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x instr value volatility) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x instr ccy volatility x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x block value x % price volatility x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x underlying price x 0.01 x value of price move x 100 x price change volatility/(underlying price) x fx rate) = forecast x instrument weight x instrument_div_mult x daily cash vol target / (10.0 x value of price move x price change volatility x fx rate) Making some arbitrary assumptions (one instrument, 100% of capital, daily target DAILY_CAPITAL): = forecast x 1.0 x 1.0 x DAILY_CAPITAL / (10.0 x value of price move x price diff volatility x fx rate) = forecast x multiplier / (value of price move x price change volatility x fx rate) """ (Unused_capital, daily_capital) = resolve_capital(forecast, capital, ann_risk_target) multiplier = daily_capital * 1.0 * 1.0 / 10.0 fx = fx.reindex(get_daily_returns_volatility.index, method="ffill") denominator = (value_of_price_point * multiply_df_single_column(get_daily_returns_volatility, fx, ffill=(False, True))) numerator = multiply_df_single_column(forecast, multiplier, ffill=(False,True)) position = divide_df_single_column(numerator, denominator, ffill=(True, True)) position.columns = ['position'] return position
def test_robust_vol_calc_min_value(self): prices = get_data("syscore.tests.pricetestdata_zero_vol.csv") returns = prices.diff() vol = robust_vol_calc(returns, vol_abs_min=0.01) self.assertEqual(vol.iloc[-1], 0.01)
import pandas as pd, numpy as np def carry(daily_ann_roll, vol, smooth_days=90): ann_stdev = vol * 256 raw_carry = daily_ann_roll / ann_stdev smooth_carry = pd.ewma(raw_carry, smooth_days) return smooth_carry #inst = "MXP"; carryoffset = 3 inst = "CORN"; carryoffset = -3 # SR 0.06 #inst = "EDOLLAR"; carryoffset = -3 # SR -0.67 carry_multiplier = 20. f = '../../sysdata/legacycsv/%s_price.csv' % inst df = pd.read_csv(f,index_col=0,parse_dates=True) f = '../../sysdata/legacycsv/%s_carrydata.csv' % inst df2 = pd.read_csv(f,index_col=0,parse_dates=True) vol = robust_vol_calc(df.PRICE.diff()) #forecast2 = np.sign(carryoffset)*(df2.CARRY-df2.PRICE) forecast2 = df2.PRICE-df2.CARRY/(carryoffset/12.) forecast2 = carry(forecast2, vol) * carry_multiplier forecast2.loc[forecast2 > 20] = 20 forecast2.loc[forecast2 < -20] = -20 account = accountCurve(df.PRICE, forecast=forecast2) print (account.sharpe())