def get_economic_event_ret_over_custom_event_day(self, data_frame_in, event_dates, name, event, start, end, lagged = False, NYC_cutoff = 10): filter = Filter() event_dates = filter.filter_time_series_by_date(start, end, event_dates) data_frame = data_frame_in.copy(deep=True) # because we change the dates! timezone = Timezone() calendar = Calendar() bday = CustomBusinessDay(weekmask='Mon Tue Wed Thu Fri') event_dates_nyc = timezone.convert_index_from_UTC_to_new_york_time(event_dates) average_hour_nyc = numpy.average(event_dates_nyc.index.hour) event_dates = calendar.floor_date(event_dates) # realised is traditionally on later day eg. 3rd Jan realised ON is 2nd-3rd Jan realised # so if Fed meeting is on 2nd Jan later, then we need realised labelled on 3rd (so minus a day) # implied expires on next day eg. 3rd Jan implied ON is 3rd-4th Jan implied # TODO smarter way of adjusting dates, as sometimes events can be before/after 10am NY cut if (lagged and average_hour_nyc >= NYC_cutoff): data_frame.index = data_frame.index - bday elif (not lagged and average_hour_nyc < NYC_cutoff): # ie. implied data_frame.index = data_frame.index + bday # set as New York time and select only those ON vols at the 10am NY cut just before the event data_frame_events = data_frame.ix[event_dates.index] data_frame_events.columns = data_frame.columns.values + '-' + name + ' ' + event return data_frame_events
def get_economic_event_ret_over_custom_event_day(self, data_frame_in, event_dates, name, event, start, end, lagged = False, NYC_cutoff = 10): filter = Filter() #returns event_dates dataframe that is between those dates, returns correct # filtered dataframe them even if index is not a timestamp event_dates = filter.filter_time_series_by_date(start, end, event_dates) data_frame = data_frame_in.copy(deep=True) # because we change the dates! timezone = Timezone() calendar = Calendar() bday = CustomBusinessDay(weekmask='Mon Tue Wed Thu Fri') event_dates_nyc = timezone.convert_index_from_UTC_to_new_york_time(event_dates) average_hour_nyc = numpy.average(event_dates_nyc.index.hour) event_dates = calendar.floor_date(event_dates) # realised is traditionally on later day eg. 3rd Jan realised ON is 2nd-3rd Jan realised # so if Fed meeting is on 2nd Jan later, then we need realised labelled on 3rd (so minus a day) # implied expires on next day eg. 3rd Jan implied ON is 3rd-4th Jan implied # TODO smarter way of adjusting dates, as sometimes events can be before/after 10am NY cut if (lagged and average_hour_nyc >= NYC_cutoff): data_frame.index = data_frame.index - bday elif (not lagged and average_hour_nyc < NYC_cutoff): # ie. implied data_frame.index = data_frame.index + bday # set as New York time and select only those ON vols at the 10am NY cut just before the event data_frame_events = data_frame.ix[event_dates.index] data_frame_events.columns = data_frame.columns.values + '-' + name + ' ' + event return data_frame_events
def __init__(self, market_df=None, intraday_spot_df=None): self._market_df = market_df self._intraday_spot_df = intraday_spot_df self._calculations = Calculations() self._timezone = Timezone() self._filter = Filter()
def run_strategy_returns_stats(self, trading_model): """ run_strategy_returns_stats - Plots useful statistics for the trading strategy (using PyFolio) Parameters ---------- trading_model : TradingModel defining trading strategy """ pnl = trading_model.get_strategy_pnl() tz = Timezone() calculations = Calculations() # PyFolio assumes UTC time based DataFrames (so force this localisation) try: pnl = tz.localise_index_as_UTC(pnl) except: pass # set the matplotlib style sheet & defaults # at present this only works in Matplotlib engine try: matplotlib.rcdefaults() plt.style.use( ChartConstants().chartfactory_style_sheet['chartpy-pyfolio']) except: pass # TODO for intraday strategies, make daily # convert DataFrame (assumed to have only one column) to Series pnl = calculations.calculate_returns(pnl) pnl = pnl.dropna() pnl = pnl[pnl.columns[0]] fig = pf.create_returns_tear_sheet(pnl, return_fig=True) try: plt.savefig(trading_model.DUMP_PATH + "stats.png") except: pass plt.show()
def __init__(self, market_data_generator=None): self._market_data_generator = market_data_generator self._calculations = Calculations() self._filter = Filter() self._timezone = Timezone() self._rates = RatesFactory() return
def __init__(self, market_data_generator=None): self.logger = LoggerManager().getLogger(__name__) self.market_data_generator = market_data_generator self.calculations = Calculations() self.filter = Filter() self.timezone = Timezone() self.rates = RatesFactory() return
def run_strategy_returns_stats(self, trading_model, index=None, engine='finmarketpy'): """Plots useful statistics for the trading strategy using various backends Parameters ---------- trading_model : TradingModel defining trading strategy engine : str 'pyfolio' - use PyFolio as a backend 'finmarketpy' - use finmarketpy as a backend index: DataFrame define strategy by a time series """ if index is None: pnl = trading_model.strategy_pnl() else: pnl = index tz = Timezone() calculations = Calculations() if engine == 'pyfolio': # PyFolio assumes UTC time based DataFrames (so force this localisation) try: pnl = tz.localize_index_as_UTC(pnl) except: pass # set the matplotlib style sheet & defaults # at present this only works in Matplotlib engine try: import matplotlib import matplotlib.pyplot as plt matplotlib.rcdefaults() plt.style.use(ChartConstants(). chartfactory_style_sheet['chartpy-pyfolio']) except: pass # TODO for intraday strategies, make daily # convert DataFrame (assumed to have only one column) to Series pnl = calculations.calculate_returns(pnl) pnl = pnl.dropna() pnl = pnl[pnl.columns[0]] fig = pf.create_returns_tear_sheet(pnl, return_fig=True) try: plt.savefig(trading_model.DUMP_PATH + "stats.png") except: pass plt.show() elif engine == 'finmarketpy': # assume we have TradingModel # to do to take in a time series from chartpy import Canvas, Chart # temporarily make scale factor smaller so fits the window old_scale_factor = trading_model.SCALE_FACTOR trading_model.SCALE_FACTOR = 0.75 pnl = trading_model.plot_strategy_pnl( silent_plot=True) # plot the final strategy individual = trading_model.plot_strategy_group_pnl_trades( silent_plot=True) # plot the individual trade P&Ls pnl_comp = trading_model.plot_strategy_group_benchmark_pnl( silent_plot=True ) # plot all the cumulative P&Ls of each component ir_comp = trading_model.plot_strategy_group_benchmark_pnl_ir( silent_plot=True) # plot all the IR of each component leverage = trading_model.plot_strategy_leverage( silent_plot=True) # plot the leverage of the portfolio ind_lev = trading_model.plot_strategy_group_leverage( silent_plot=True) # plot all the individual leverages canvas = Canvas([[pnl, individual], [pnl_comp, ir_comp], [leverage, ind_lev]]) canvas.generate_canvas( page_title=trading_model.FINAL_STRATEGY + ' Return Statistics', silent_display=False, canvas_plotter='plain', output_filename=trading_model.FINAL_STRATEGY + ".html", render_pdf=False) trading_model.SCALE_FACTOR = old_scale_factor
class VolStats(object): """Arranging underlying volatility market in easier to read format. Also provides methods for calculating various volatility metrics, such as realized_vol volatility and volatility risk premium. Has extensive support for estimating implied_vol volatility addons. """ def __init__(self, market_df=None, intraday_spot_df=None): self._market_df = market_df self._intraday_spot_df = intraday_spot_df self._calculations = Calculations() self._timezone = Timezone() self._filter = Filter() def calculate_realized_vol(self, asset, spot_df=None, returns_df=None, tenor_label="ON", freq='daily', freq_min_mult=1, hour_of_day=10, minute_of_day=0, field='close', returns_calc='simple', timezone_hour_minute='America/New_York'): """Calculates rolling realized vol with daily cutoffs either using daily spot data or intraday spot data (which is assumed to be in UTC timezone) Parameters ---------- asset : str asset to be calculated spot_df : pd.DataFrame minute spot returns (freq_min_mult should be the same as the frequency and should have timezone set) tenor_label : str tenor to calculate freq_min_mult : int frequency multiply for data (1 = 1 min) hour_of_day : closing time of data in the timezone specified eg. 10 which is 1000 time (default = 10) minute_of_day : closing time of data in the timezone specified eg. 0 which is 0 time (default = 0) field : str By default 'close' returns_calc : str 'simple' calculate simple returns 'log' calculate log returns timezone_hour_minute : str The timezone for the closing hour/minute (default: 'America/New_York') Returns ------- pd.DataFrame of realized volatility """ if returns_df is None: if spot_df is None: if freq == 'daily': spot_df = self._market_df[asset + "." + field] else: spot_df = self._intraday_spot_df[asset + "." + field] if returns_calc == 'simple': returns_df = self._calculations.calculate_returns(spot_df) else: returns_df = self._calculations.calculate_log_returns(spot_df) cal = Calendar() tenor_days = cal.get_business_days_tenor(tenor_label) if freq == 'intraday': # Annualization factor (1440 is number of minutes in the day) mult = int(1440.0 / float(freq_min_mult)) realized_rolling = self._calculations.rolling_volatility( returns_df, tenor_days * mult, obs_in_year=252 * mult) # Convert to NYC time (or whatever timezone hour is specified in) realized_rolling = self._timezone.convert_index_aware_to_alt( realized_rolling, timezone_hour_minute) realized_vol = self._filter.filter_time_series_by_time_of_day( hour_of_day, minute_of_day, realized_rolling) realized_vol = self._timezone.convert_index_aware_to_UTC_time( realized_vol) realized_vol = self._timezone.set_as_no_timezone(realized_vol) elif freq == 'daily': realized_vol = self._calculations.rolling_volatility( spot_df, tenor_days, obs_in_year=252) # Strip the time off the date realized_vol.index = realized_vol.index.date realized_vol = pd.DataFrame(realized_vol) realized_vol.columns = [asset + 'H' + tenor_label + '.close'] return realized_vol def calculate_vol_risk_premium(self, asset, tenor_label="ON", implied_vol=None, realized_vol=None, field='close', adj_ON_friday=False): """Calculates volatility risk premium given implied and realized quotes (ie. implied - realized) and tenor Calculates both a version which is aligned (VRP), where the implied and realized volatilities cover the same period (note: you will have a gap for recent points, where you can't grab future implied volatilities), and an unaligned version (VRPV), which is the typical one used in the market Parameters ---------- asset : str asset to calculate value for tenor_label : str tenor to calculate implied_vol : pd.DataFrame implied vol quotes where columns are of the form eg. EURUSDV1M.close realized_vol : pd.DataFrame realized vol eg. EURUSDH1M.close field : str the field of the data to use (default: 'close') Returns ------- pd.DataFrame of vrp (both lagged - VRPV & contemporanous - VRP) """ cal = Calendar() tenor_days = cal.get_business_days_tenor(tenor_label) if tenor_label == 'ON' and adj_ON_friday: implied_vol = self.adjust_implied_ON_fri_vol(implied_vol) # Add x business days to implied_vol to make it equivalent to realized_vol (better than "shift") # approximation for options which are not ON or 1W # bday = CustomBusinessDay(weekmask='Mon Tue Wed Thu Fri') implied_vol = implied_vol.copy(deep=True) implied_unaligned = implied_vol.copy(deep=True) cols_to_change = implied_vol.columns.values new_cols = [] for i in range(0, len(cols_to_change)): temp_col = list(cols_to_change[i]) temp_col[6] = 'U' new_cols.append(''.join(temp_col)) implied_vol.columns = new_cols ## Construct volatility risk premium such that implied covers the same period as realized # Add by number of days (note: for overnight tenors/1 week in FX we can add business days like this) # For because they are always +1 business days, +5 business days (exc. national holidays and only including # weekend). For longer dates like 1 month this is an approximation implied_vol.index = [ pd.Timestamp(x) + pd.tseries.offsets.BDay(tenor_days) for x in implied_vol.index ] vrp = implied_vol.join(realized_vol, how='outer') vrp[asset + "VRP" + tenor_label + ".close"] = vrp[asset + "U" + tenor_label + "." + field] \ - vrp[asset + "H" + tenor_label + "." + field] ## Construct "traditional" volatility risk premium, # so implied does not cover the same period as realized volatility vrp = vrp.join(implied_unaligned, how='outer') vrp[asset + "VRPV" + tenor_label + ".close"] = \ vrp[asset + "V" + tenor_label + "." + field] - vrp[asset + "H" + tenor_label + "." + field] return vrp def calculate_implied_vol_addon(self, asset, implied_vol=None, tenor_label='ON', model_window=20, model_algo='weighted-median-model', field='close', adj_ON_friday=True): """Calculates the implied volatility add on for specific tenors. The implied volatility addon can be seen as a proxy for the event weights of large scheduled events for that day, such as the US employment report. If there are multiple large events in the same period covered by the option, then this approach is not going to be able to disentangle this. Parameters ---------- asset : str Asset to be traded (eg. EURUSD) tenor: str eg. ON Returns ------ Implied volatility addon """ part = 'V' if implied_vol is None: implied_vol = self._market_df[asset + "V" + tenor_label + "." + field] implied_vol = implied_vol.copy(deep=True) implied_vol = pd.DataFrame(implied_vol) # So we eliminate impact of holidays on addons if tenor_label == 'ON' and adj_ON_friday: implied_vol = self.adjust_implied_ON_fri_vol(implied_vol) implied_vol = implied_vol.dropna( ) # otherwise the moving averages get corrupted # vol_data_avg_by_weekday = vol_data.groupby(vol_data.index.weekday).transform(lambda x: pandas.rolling_mean(x, window=10)) # Create a simple estimate for recent implied_vol volatility using multiple tenors # vol_data_20D_avg = time_series_calcs.rolling_average(vol_data,window1) # vol_data_10D_avg = time_series_calcs.rolling_average(vol_data,window1) # vol_data_5D_avg = time_series_calcs.rolling_average(vol_data, window1) if model_algo == 'weighted-median-model': vol_data_20D_avg = self._calculations.rolling_median( implied_vol, model_window) vol_data_10D_avg = self._calculations.rolling_median( implied_vol, model_window) vol_data_5D_avg = self._calculations.rolling_median( implied_vol, model_window) vol_data_avg = (vol_data_20D_avg + vol_data_10D_avg + vol_data_5D_avg) / 3 vol_data_addon = implied_vol - vol_data_avg elif model_algo == 'weighted-mean-model': vol_data_20D_avg = self._calculations.rolling_average( implied_vol, model_window) vol_data_10D_avg = self._calculations.rolling_average( implied_vol, model_window) vol_data_5D_avg = self._calculations.rolling_average( implied_vol, model_window) vol_data_avg = (vol_data_20D_avg + vol_data_10D_avg + vol_data_5D_avg) / 3 vol_data_addon = implied_vol - vol_data_avg # TODO add other implied vol addon models vol_data_addon = pd.DataFrame(vol_data_addon) implied_vol = pd.DataFrame(implied_vol) new_cols = implied_vol.columns.values new_cols = [ w.replace(part + tenor_label, 'ADD' + tenor_label) for w in new_cols ] vol_data_addon.columns = new_cols return vol_data_addon def adjust_implied_ON_fri_vol(self, data_frame): cols_ON = [x for x in data_frame.columns if 'VON' in x] for c in cols_ON: data_frame[c][data_frame.index.dayofweek == 4] = data_frame[c][ data_frame.index.dayofweek == 4] * math.sqrt(3) # data_frame[data_frame.index.dayofweek == 4] = data_frame[data_frame.index.dayofweek == 4] * math.sqrt(3) return data_frame
def run_strategy_returns_stats(self, trading_model, index = None, engine = 'pyfolio'): """Plots useful statistics for the trading strategy (using PyFolio) Parameters ---------- trading_model : TradingModel defining trading strategy index: DataFrame define strategy by a time series """ if index is None: pnl = trading_model.get_strategy_pnl() else: pnl = index tz = Timezone() calculations = Calculations() if engine == 'pyfolio': # PyFolio assumes UTC time based DataFrames (so force this localisation) try: pnl = tz.localise_index_as_UTC(pnl) except: pass # set the matplotlib style sheet & defaults # at present this only works in Matplotlib engine try: matplotlib.rcdefaults() plt.style.use(ChartConstants().chartfactory_style_sheet['chartpy-pyfolio']) except: pass # TODO for intraday strategies, make daily # convert DataFrame (assumed to have only one column) to Series pnl = calculations.calculate_returns(pnl) pnl = pnl.dropna() pnl = pnl[pnl.columns[0]] fig = pf.create_returns_tear_sheet(pnl, return_fig=True) try: plt.savefig (trading_model.DUMP_PATH + "stats.png") except: pass plt.show() elif engine == 'finmarketpy': # assume we have TradingModel # to do to take in a time series from chartpy import Canvas, Chart pnl = trading_model.plot_strategy_pnl(silent_plot=True) # plot the final strategy individual = trading_model.plot_strategy_group_pnl_trades(silent_plot=True) # plot the individual trade P&Ls pnl_comp = trading_model.plot_strategy_group_benchmark_pnl(silent_plot=True) # plot all the cumulative P&Ls of each component ir_comp = trading_model.plot_strategy_group_benchmark_pnl_ir(silent_plot=True) # plot all the IR of each component leverage = trading_model.plot_strategy_leverage(silent_plot=True) # plot the leverage of the portfolio ind_lev = trading_model.plot_strategy_group_leverage(silent_plot=True) # plot all the individual leverages canvas = Canvas([[pnl, individual], [pnl_comp, ir_comp], [leverage, ind_lev]] ) canvas.generate_canvas(silent_display=False, canvas_plotter='plain')
def run_strategy_returns_stats(self, trading_model, index=None, engine='pyfolio'): """ run_strategy_returns_stats - Plots useful statistics for the trading strategy (using PyFolio) Parameters ---------- trading_model : TradingModel defining trading strategy index: DataFrame define strategy by a time series """ if index is None: pnl = trading_model.get_strategy_pnl() else: pnl = index tz = Timezone() calculations = Calculations() if engine == 'pyfolio': # PyFolio assumes UTC time based DataFrames (so force this localisation) try: pnl = tz.localise_index_as_UTC(pnl) except: pass # set the matplotlib style sheet & defaults # at present this only works in Matplotlib engine try: matplotlib.rcdefaults() plt.style.use(ChartConstants(). chartfactory_style_sheet['chartpy-pyfolio']) except: pass # TODO for intraday strategies, make daily # convert DataFrame (assumed to have only one column) to Series pnl = calculations.calculate_returns(pnl) pnl = pnl.dropna() pnl = pnl[pnl.columns[0]] fig = pf.create_returns_tear_sheet(pnl, return_fig=True) try: plt.savefig(trading_model.DUMP_PATH + "stats.png") except: pass plt.show() elif engine == 'finmarketpy': # assume we have TradingModel # to do to take in a time series from chartpy import Canvas, Chart pnl = trading_model.plot_strategy_pnl( silent_plot=True) # plot the final strategy individual = trading_model.plot_strategy_group_pnl_trades( silent_plot=True) # plot the individual trade P&Ls pnl_comp = trading_model.plot_strategy_group_benchmark_pnl( silent_plot=True ) # plot all the cumulative P&Ls of each component ir_comp = trading_model.plot_strategy_group_benchmark_pnl_ir( silent_plot=True) # plot all the IR of each component leverage = trading_model.plot_strategy_leverage( silent_plot=True) # plot the leverage of the portfolio ind_lev = trading_model.plot_strategy_group_leverage( silent_plot=True) # plot all the individual leverages canvas = Canvas([[pnl, individual], [pnl_comp, ir_comp], [leverage, ind_lev]]) canvas.generate_canvas(silent_display=False, canvas_plotter='plain')