def run_day_of_month_analysis(self, strat): from pythalesians.economics.seasonality.seasonality import Seasonality from pythalesians.timeseries.calcs.timeseriescalcs import TimeSeriesCalcs tsc = TimeSeriesCalcs() seas = Seasonality() strat.construct_strategy() pnl = strat.get_strategy_pnl() # get seasonality by day of the month pnl = pnl.resample('B').mean() rets = tsc.calculate_returns(pnl) bus_day = seas.bus_day_of_month_seasonality(rets, add_average = True) # get seasonality by month pnl = pnl.resample('BM').mean() rets = tsc.calculate_returns(pnl) month = seas.monthly_seasonality(rets) self.logger.info("About to plot seasonality...") gp = GraphProperties() pf = PlotFactory() # Plotting spot over day of month/month of year gp.color = 'Blues' gp.scale_factor = self.SCALE_FACTOR gp.file_output = self.DUMP_PATH + strat.FINAL_STRATEGY + ' seasonality day of month.png' gp.html_file_output = self.DUMP_PATH + strat.FINAL_STRATEGY + ' seasonality day of month.html' gp.title = strat.FINAL_STRATEGY + ' day of month seasonality' gp.display_legend = False gp.color_2_series = [bus_day.columns[-1]] gp.color_2 = ['red'] # red, pink gp.linewidth_2 = 4 gp.linewidth_2_series = [bus_day.columns[-1]] gp.y_axis_2_series = [bus_day.columns[-1]] pf.plot_line_graph(bus_day, adapter = self.DEFAULT_PLOT_ENGINE, gp = gp) gp = GraphProperties() gp.scale_factor = self.SCALE_FACTOR gp.file_output = self.DUMP_PATH + strat.FINAL_STRATEGY + ' seasonality month of year.png' gp.html_file_output = self.DUMP_PATH + strat.FINAL_STRATEGY + ' seasonality month of year.html' gp.title = strat.FINAL_STRATEGY + ' month of year seasonality' pf.plot_line_graph(month, adapter = self.DEFAULT_PLOT_ENGINE, gp = gp) return month
def monthly_seasonality(self, data_frame, cum=True, add_average=False, price_index=False): tsc = TimeSeriesCalcs() if price_index: data_frame = data_frame.resample('BM') # resample into month end data_frame = tsc.calculate_returns(data_frame) data_frame.index = pandas.to_datetime(data_frame.index) monthly_seasonality = tsc.average_by_month(data_frame) if add_average: monthly_seasonality['Avg'] = monthly_seasonality.mean(axis=1) if cum is True: monthly_seasonality.loc[0] = numpy.zeros( len(monthly_seasonality.columns)) monthly_seasonality = monthly_seasonality.sort() monthly_seasonality = tsc.create_mult_index(monthly_seasonality) return monthly_seasonality
def run_strategy_returns_stats(self, strategy): """ run_strategy_returns_stats - Plots useful statistics for the trading strategy (using PyFolio) Parameters ---------- strategy : StrategyTemplate defining trading strategy """ pnl = strategy.get_strategy_pnl() tz = TimeSeriesTimezone() tsc = TimeSeriesCalcs() # PyFolio assumes UTC time based DataFrames (so force this localisation) try: pnl = tz.localise_index_as_UTC(pnl) except: pass # TODO for intraday strategy make daily # convert DataFrame (assumed to have only one column) to Series pnl = tsc.calculate_returns(pnl) pnl = pnl[pnl.columns[0]] fig = pf.create_returns_tear_sheet(pnl, return_fig=True) try: plt.savefig (strategy.DUMP_PATH + "stats.png") except: pass plt.show()
def bus_day_of_month_seasonality(self, data_frame, month_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], cum = True, cal = "FX", partition_by_month = True, add_average = False, price_index = False): tsc = TimeSeriesCalcs() tsf = TimeSeriesFilter() if price_index: data_frame = data_frame.resample('B') # resample into business days data_frame = tsc.calculate_returns(data_frame) data_frame.index = pandas.to_datetime(data_frame.index) data_frame = tsf.filter_time_series_by_holidays(data_frame, cal) monthly_seasonality = tsc.average_by_month_day_by_bus_day(data_frame, cal) monthly_seasonality = monthly_seasonality.loc[month_list] if partition_by_month: monthly_seasonality = monthly_seasonality.unstack(level=0) if add_average: monthly_seasonality['Avg'] = monthly_seasonality.mean(axis=1) if cum is True: if partition_by_month: monthly_seasonality.loc[0] = numpy.zeros(len(monthly_seasonality.columns)) # monthly_seasonality.index = monthly_seasonality.index + 1 # shifting index monthly_seasonality = monthly_seasonality.sort() monthly_seasonality = tsc.create_mult_index(monthly_seasonality) return monthly_seasonality
def calculate_vol_adjusted_returns(self, returns_df, br, returns = True): """ calculate_vol_adjusted_returns - Adjusts returns for a vol target Parameters ---------- br : BacktestRequest Parameters for the backtest specifying start date, finish data, transaction costs etc. returns_a_df : pandas.DataFrame Asset returns to be traded Returns ------- pandas.DataFrame """ tsc = TimeSeriesCalcs() if not returns: returns_df = tsc.calculate_returns(returns_df) if not(hasattr(br, 'portfolio_vol_resample_type')): br.portfolio_vol_resample_type = 'mean' leverage_df = self.calculate_leverage_factor(returns_df, br.portfolio_vol_target, br.portfolio_vol_max_leverage, br.portfolio_vol_periods, br.portfolio_vol_obs_in_year, br.portfolio_vol_rebalance_freq, br.portfolio_vol_resample_freq, br.portfolio_vol_resample_type) vol_returns_df = tsc.calculate_signal_returns_with_tc_matrix(leverage_df, returns_df, tc = br.spot_tc_bp) vol_returns_df.columns = returns_df.columns return vol_returns_df, leverage_df
def run_strategy_returns_stats(self, strategy): """ run_strategy_returns_stats - Plots useful statistics for the trading strategy (using PyFolio) Parameters ---------- strategy : StrategyTemplate defining trading strategy """ pnl = strategy.get_strategy_pnl() tz = TimeSeriesTimezone() tsc = TimeSeriesCalcs() # PyFolio assumes UTC time based DataFrames (so force this localisation) try: pnl = tz.localise_index_as_UTC(pnl) except: pass # TODO for intraday strategy make daily # convert DataFrame (assumed to have only one column) to Series pnl = tsc.calculate_returns(pnl) pnl = pnl[pnl.columns[0]] fig = pf.create_returns_tear_sheet(pnl, return_fig=True) try: plt.savefig(strategy.DUMP_PATH + "stats.png") except: pass plt.show()
def calculate_vol_adjusted_returns(self, returns_df, br, returns=True): """ calculate_vol_adjusted_returns - Adjusts returns for a vol target Parameters ---------- br : BacktestRequest Parameters for the backtest specifying start date, finish data, transaction costs etc. returns_a_df : pandas.DataFrame Asset returns to be traded Returns ------- pandas.DataFrame """ tsc = TimeSeriesCalcs() if not returns: returns_df = tsc.calculate_returns(returns_df) if not (hasattr(br, 'portfolio_vol_resample_type')): br.portfolio_vol_resample_type = 'mean' leverage_df = self.calculate_leverage_factor( returns_df, br.portfolio_vol_target, br.portfolio_vol_max_leverage, br.portfolio_vol_periods, br.portfolio_vol_obs_in_year, br.portfolio_vol_rebalance_freq, br.portfolio_vol_resample_freq, br.portfolio_vol_resample_type) vol_returns_df = tsc.calculate_signal_returns_with_tc_matrix( leverage_df, returns_df, tc=br.spot_tc_bp) vol_returns_df.columns = returns_df.columns return vol_returns_df, leverage_df
def calculate_leverage_factor(self, returns_df, vol_target, vol_max_leverage, vol_periods = 60, vol_obs_in_year = 252, vol_rebalance_freq = 'BM', returns = True, period_shift = 0): """ calculate_leverage_factor - Calculates the time series of leverage for a specified vol target Parameters ---------- returns_df : DataFrame Asset returns vol_target : float vol target for assets vol_max_leverage : float maximum leverage allowed vol_periods : int number of periods to calculate volatility vol_obs_in_year : int number of observations in the year vol_rebalance_freq : str how often to rebalance returns : boolean is this returns time series or prices? period_shift : int should we delay the signal by a number of periods? Returns ------- pandas.Dataframe """ tsc = TimeSeriesCalcs() if not returns: returns_df = tsc.calculate_returns(returns_df) roll_vol_df = tsc.rolling_volatility(returns_df, periods = vol_periods, obs_in_year = vol_obs_in_year).shift(period_shift) # calculate the leverage as function of vol target (with max lev constraint) lev_df = vol_target / roll_vol_df lev_df[lev_df > vol_max_leverage] = vol_max_leverage # only allow the leverage change at resampling frequency (eg. monthly 'BM') lev_df = lev_df.resample(vol_rebalance_freq) returns_df, lev_df = returns_df.align(lev_df, join='left', axis = 0) lev_df = lev_df.fillna(method='ffill') return lev_df
def calculate_ret_stats_from_prices(self, prices_df, ann_factor): """ calculate_ret_stats_from_prices - Calculates return statistics for an asset's price Parameters ---------- prices_df : DataFrame asset prices ann_factor : int annualisation factor to use on return statistics Returns ------- DataFrame """ tsc = TimeSeriesCalcs() self.calculate_ret_stats(tsc.calculate_returns(prices_df), ann_factor)
def calculate_ret_stats_from_prices(self, prices_df, ann_factor): """ calculate_ret_stats_from_prices - Calculates return statistics for an asset's price Parameters ---------- prices_df : DataFrame asset prices ann_factor : int annualisation factor to use on return statistics Returns ------- DataFrame """ tsc = TimeSeriesCalcs() self.calculate_ret_stats(tsc.calculate_returns(prices_df), ann_factor)
def bus_day_of_month_seasonality( self, data_frame, month_list=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], cum=True, cal="FX", partition_by_month=True, add_average=False, price_index=False): tsc = TimeSeriesCalcs() tsf = TimeSeriesFilter() if price_index: data_frame = data_frame.resample( 'B') # resample into business days data_frame = tsc.calculate_returns(data_frame) data_frame.index = pandas.to_datetime(data_frame.index) data_frame = tsf.filter_time_series_by_holidays(data_frame, cal) monthly_seasonality = tsc.average_by_month_day_by_bus_day( data_frame, cal) monthly_seasonality = monthly_seasonality.loc[month_list] if partition_by_month: monthly_seasonality = monthly_seasonality.unstack(level=0) if add_average: monthly_seasonality['Avg'] = monthly_seasonality.mean(axis=1) if cum is True: if partition_by_month: monthly_seasonality.loc[0] = numpy.zeros( len(monthly_seasonality.columns)) # monthly_seasonality.index = monthly_seasonality.index + 1 # shifting index monthly_seasonality = monthly_seasonality.sort() monthly_seasonality = tsc.create_mult_index(monthly_seasonality) return monthly_seasonality
def run_strategy_returns_stats(self, strategy): """ run_strategy_returns_stats - Plots useful statistics for the trading strategy (using PyFolio) Parameters ---------- strategy : StrategyTemplate defining trading strategy """ pnl = strategy.get_strategy_pnl() tz = TimeSeriesTimezone() tsc = TimeSeriesCalcs() # 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(GraphicsConstants().plotfactory_pythalesians_style_sheet['pythalesians-pyfolio']) except: pass # TODO for intraday strategies, make daily # convert DataFrame (assumed to have only one column) to Series pnl = tsc.calculate_returns(pnl) pnl = pnl.dropna() pnl = pnl[pnl.columns[0]] fig = pf.create_returns_tear_sheet(pnl, return_fig=True) try: plt.savefig (strategy.DUMP_PATH + "stats.png") except: pass plt.show()
def monthly_seasonality(self, data_frame, cum = True, add_average = False, price_index = False): tsc = TimeSeriesCalcs() if price_index: data_frame = data_frame.resample('BM') # resample into month end data_frame = tsc.calculate_returns(data_frame) data_frame.index = pandas.to_datetime(data_frame.index) monthly_seasonality = tsc.average_by_month(data_frame) if add_average: monthly_seasonality['Avg'] = monthly_seasonality.mean(axis=1) if cum is True: monthly_seasonality.loc[0] = numpy.zeros(len(monthly_seasonality.columns)) monthly_seasonality = monthly_seasonality.sort() monthly_seasonality = tsc.create_mult_index(monthly_seasonality) return monthly_seasonality
def calculate_trading_PnL(self, br, asset_a_df, signal_df): """ calculate_trading_PnL - Calculates P&L of a trading strategy and statistics to be retrieved later Parameters ---------- br : BacktestRequest Parameters for the backtest specifying start date, finish data, transaction costs etc. asset_a_df : pandas.DataFrame Asset prices to be traded signal_df : pandas.DataFrame Signals for the trading strategy """ tsc = TimeSeriesCalcs() # signal_df.to_csv('e:/temp0.csv') # make sure the dates of both traded asset and signal are aligned properly asset_df, signal_df = asset_a_df.align(signal_df, join='left', axis='index') # only allow signals to change on the days when we can trade assets signal_df = signal_df.mask(numpy.isnan( asset_df.values)) # fill asset holidays with NaN signals signal_df = signal_df.fillna(method='ffill') # fill these down asset_df = asset_df.fillna(method='ffill') # fill down asset holidays returns_df = tsc.calculate_returns(asset_df) tc = br.spot_tc_bp signal_cols = signal_df.columns.values returns_cols = returns_df.columns.values pnl_cols = [] for i in range(0, len(returns_cols)): pnl_cols.append(returns_cols[i] + " / " + signal_cols[i]) # do we have a vol target for individual signals? if hasattr(br, 'signal_vol_adjust'): if br.signal_vol_adjust is True: if not (hasattr(br, 'signal_vol_resample_type')): br.signal_vol_resample_type = 'mean' leverage_df = self.calculate_leverage_factor( returns_df, br.signal_vol_target, br.signal_vol_max_leverage, br.signal_vol_periods, br.signal_vol_obs_in_year, br.signal_vol_rebalance_freq, br.signal_vol_resample_freq, br.signal_vol_resample_type) signal_df = pandas.DataFrame(signal_df.values * leverage_df.values, index=signal_df.index, columns=signal_df.columns) self._individual_leverage = leverage_df # contains leverage of individual signal (before portfolio vol target) _pnl = tsc.calculate_signal_returns_with_tc_matrix(signal_df, returns_df, tc=tc) _pnl.columns = pnl_cols # portfolio is average of the underlying signals: should we sum them or average them? if hasattr(br, 'portfolio_combination'): if br.portfolio_combination == 'sum': portfolio = pandas.DataFrame(data=_pnl.sum(axis=1), index=_pnl.index, columns=['Portfolio']) elif br.portfolio_combination == 'mean': portfolio = pandas.DataFrame(data=_pnl.mean(axis=1), index=_pnl.index, columns=['Portfolio']) else: portfolio = pandas.DataFrame(data=_pnl.mean(axis=1), index=_pnl.index, columns=['Portfolio']) portfolio_leverage_df = pandas.DataFrame(data=numpy.ones( len(_pnl.index)), index=_pnl.index, columns=['Portfolio']) # should we apply vol target on a portfolio level basis? if hasattr(br, 'portfolio_vol_adjust'): if br.portfolio_vol_adjust is True: portfolio, portfolio_leverage_df = self.calculate_vol_adjusted_returns( portfolio, br=br) self._portfolio = portfolio self._signal = signal_df # individual signals (before portfolio leverage) self._portfolio_leverage = portfolio_leverage_df # leverage on portfolio # multiply portfolio leverage * individual signals to get final position signals length_cols = len(signal_df.columns) leverage_matrix = numpy.repeat( portfolio_leverage_df.values.flatten()[numpy.newaxis, :], length_cols, 0) # final portfolio signals (including signal & portfolio leverage) self._portfolio_signal = pandas.DataFrame(data=numpy.multiply( numpy.transpose(leverage_matrix), signal_df.values), index=signal_df.index, columns=signal_df.columns) if hasattr(br, 'portfolio_combination'): if br.portfolio_combination == 'sum': pass elif br.portfolio_combination == 'mean': self._portfolio_signal = self._portfolio_signal / float( length_cols) else: self._portfolio_signal = self._portfolio_signal / float( length_cols) self._pnl = _pnl # individual signals P&L # TODO FIX very slow - hence only calculate on demand _pnl_trades = None # _pnl_trades = tsc.calculate_individual_trade_gains(signal_df, _pnl) self._pnl_trades = _pnl_trades self._tsd_pnl = TimeSeriesDesc() self._tsd_pnl.calculate_ret_stats(self._pnl, br.ann_factor) self._portfolio.columns = ['Port'] self._tsd_portfolio = TimeSeriesDesc() self._tsd_portfolio.calculate_ret_stats(self._portfolio, br.ann_factor) self._cumpnl = tsc.create_mult_index( self._pnl) # individual signals cumulative P&L self._cumpnl.columns = pnl_cols self._cumportfolio = tsc.create_mult_index( self._portfolio) # portfolio cumulative P&L self._cumportfolio.columns = ['Port']
def calculate_leverage_factor(self, returns_df, vol_target, vol_max_leverage, vol_periods=60, vol_obs_in_year=252, vol_rebalance_freq='BM', data_resample_freq=None, data_resample_type='mean', returns=True, period_shift=0): """ calculate_leverage_factor - Calculates the time series of leverage for a specified vol target Parameters ---------- returns_df : DataFrame Asset returns vol_target : float vol target for assets vol_max_leverage : float maximum leverage allowed vol_periods : int number of periods to calculate volatility vol_obs_in_year : int number of observations in the year vol_rebalance_freq : str how often to rebalance vol_resample_freq : str do we need to resample the underlying data first? (eg. have we got intraday data?) returns : boolean is this returns time series or prices? period_shift : int should we delay the signal by a number of periods? Returns ------- pandas.Dataframe """ tsc = TimeSeriesCalcs() if data_resample_freq is not None: return # TODO not implemented yet if not returns: returns_df = tsc.calculate_returns(returns_df) roll_vol_df = tsc.rolling_volatility( returns_df, periods=vol_periods, obs_in_year=vol_obs_in_year).shift(period_shift) # calculate the leverage as function of vol target (with max lev constraint) lev_df = vol_target / roll_vol_df lev_df[lev_df > vol_max_leverage] = vol_max_leverage # should we take the mean, first, last in our resample if data_resample_type == 'mean': lev_df = lev_df.resample(vol_rebalance_freq).mean() elif data_resample_type == 'first': lev_df = lev_df.resample(vol_rebalance_freq).first() elif data_resample_type == 'last': lev_df = lev_df.resample(vol_rebalance_freq).last() else: # TODO implement other types return returns_df, lev_df = returns_df.align(lev_df, join='left', axis=0) lev_df = lev_df.fillna(method='ffill') lev_df.ix[ 0: vol_periods] = numpy.nan # ignore the first elements before the vol window kicks in return lev_df
'GBPUSD', 'AUDUSD'], fields = ['close'], # which fields to download vendor_tickers = ['EURUSD BGN Curncy', # ticker (Bloomberg) 'GBPUSD BGN Curncy', 'AUDUSD BGN Curncy'], vendor_fields = ['PX_LAST'], # which Bloomberg fields to download cache_algo = 'internet_load_return') # how to return data ltsf = LightTimeSeriesFactory() df = None df = ltsf.harvest_time_series(time_series_request) tsc = TimeSeriesCalcs() df = tsc.calculate_returns(df) df = tsc.rolling_corr(df['EURUSD.close'], 20, data_frame2 = df[['GBPUSD.close', 'AUDUSD.close']]) gp = GraphProperties() gp.title = "1M FX rolling correlations" gp.scale_factor = 3 pf = PlotFactory() pf.plot_line_graph(df, adapter = 'pythalesians', gp = gp) ###### download daily data from Bloomberg for AUD/JPY, NZD/JPY spot with S&P500, then calculate correlation if True: time_series_request = TimeSeriesRequest( start_date="01 Jan 2015", # start date finish_date=datetime.date.today(), # finish date freq='daily', # daily data
def construct_strategy(self): """ construct_strategy - Constructs the returns for all the strategies which have been specified. - gets parameters form fill_backtest_request - market data from fill_assets """ time_series_calcs = TimeSeriesCalcs() # get the parameters for backtesting if hasattr(self, 'br'): br = self.br else: br = self.fill_backtest_request() # get market data for backtest asset_df, spot_df, spot_df2, basket_dict = self.fill_assets() if hasattr(br, 'tech_params'): tech_params = br.tech_params else: tech_params = TechParams() cumresults = pandas.DataFrame(index=asset_df.index) portleverage = pandas.DataFrame(index=asset_df.index) tsdresults = {} # each portfolio key calculate returns - can put parts of the portfolio in the key for key in basket_dict.keys(): asset_cut_df = asset_df[[x + '.close' for x in basket_dict[key]]] spot_cut_df = spot_df[[x + '.close' for x in basket_dict[key]]] self.logger.info("Calculating " + key) results, cash_backtest = self.construct_individual_strategy( br, spot_cut_df, spot_df2, asset_cut_df, tech_params, key) cumresults[results.columns[0]] = results portleverage[ results.columns[0]] = cash_backtest.get_porfolio_leverage() tsdresults[key] = cash_backtest.get_portfolio_pnl_tsd() # for a key, designated as the final strategy save that as the "strategy" if key == self.FINAL_STRATEGY: self._strategy_pnl = results self._strategy_pnl_tsd = cash_backtest.get_portfolio_pnl_tsd() self._strategy_leverage = cash_backtest.get_porfolio_leverage() self._strategy_signal = cash_backtest.get_porfolio_signal() # get benchmark for comparison benchmark = self.construct_strategy_benchmark() cumresults_benchmark = self.compare_strategy_vs_benchmark( br, cumresults, benchmark) self._strategy_group_benchmark_tsd = tsdresults if hasattr(self, '_benchmark_tsd'): tsdlist = tsdresults tsdlist['Benchmark'] = (self._benchmark_tsd) self._strategy_group_benchmark_tsd = tsdlist # calculate annualised returns years = time_series_calcs.average_by_annualised_year( time_series_calcs.calculate_returns(cumresults_benchmark)) self._strategy_group_pnl = cumresults self._strategy_group_pnl_tsd = tsdresults self._strategy_group_benchmark_pnl = cumresults_benchmark self._strategy_group_leverage = portleverage self._strategy_group_benchmark_annualised_pnl = years
def get_fx_cross(self, start, end, cross, cut = "NYC", source = "bloomberg", freq = "intraday", cache_algo='cache_algo_return', type = 'spot'): if source == "gain" or source == 'dukascopy' or freq == 'tick': return self.get_fx_cross_tick(start, end, cross, cut = cut, source = source, cache_algo='cache_algo_return', type = 'spot') if isinstance(cross, str): cross = [cross] time_series_request = TimeSeriesRequest() time_series_factory = self.time_series_factory time_series_calcs = TimeSeriesCalcs() data_frame_agg = None if freq == 'intraday': time_series_request.gran_freq = "minute" # intraday elif freq == 'daily': time_series_request.gran_freq = "daily" # intraday time_series_request.freq_mult = 1 # 1 min time_series_request.cut = cut # NYC/BGN ticker time_series_request.fields = 'close' # close field only time_series_request.cache_algo = cache_algo # cache_algo_only, cache_algo_return, internet_load time_series_request.environment = 'backtest' time_series_request.start_date = start time_series_request.finish_date = end time_series_request.data_source = source for cr in cross: base = cr[0:3] terms = cr[3:6] if (type == 'spot'): # non-USD crosses if base != 'USD' and terms != 'USD': base_USD = self.fxconv.correct_notation('USD' + base) terms_USD = self.fxconv.correct_notation('USD' + terms) # TODO check if the cross exists in the database # download base USD cross time_series_request.tickers = base_USD time_series_request.category = self.fxconv.em_or_g10(base, freq) base_vals = time_series_factory.harvest_time_series(time_series_request) # download terms USD cross time_series_request.tickers = terms_USD time_series_request.category = self.fxconv.em_or_g10(terms, freq) terms_vals = time_series_factory.harvest_time_series(time_series_request) if (base_USD[0:3] == 'USD'): base_vals = 1 / base_vals if (terms_USD[0:3] == 'USD'): terms_vals = 1 / terms_vals base_vals.columns = ['temp'] terms_vals.columns = ['temp'] cross_vals = base_vals.div(terms_vals, axis = 'index') cross_vals.columns = [cr + '.close'] else: if base == 'USD': non_USD = terms if terms == 'USD': non_USD = base correct_cr = self.fxconv.correct_notation(cr) time_series_request.tickers = correct_cr time_series_request.category = self.fxconv.em_or_g10(non_USD, freq) cross_vals = time_series_factory.harvest_time_series(time_series_request) # flip if not convention if(correct_cr != cr): cross_vals = 1 / cross_vals cross_vals.columns.names = [cr + '.close'] elif type[0:3] == "tot": if freq == 'daily': # download base USD cross time_series_request.tickers = base + 'USD' time_series_request.category = self.fxconv.em_or_g10(base, freq) + '-tot' if type == "tot": base_vals = time_series_factory.harvest_time_series(time_series_request) else: x = 0 # download terms USD cross time_series_request.tickers = terms + 'USD' time_series_request.category = self.fxconv.em_or_g10(terms, freq) + '-tot' if type == "tot": terms_vals = time_series_factory.harvest_time_series(time_series_request) else: x = 0 base_rets = time_series_calcs.calculate_returns(base_vals) terms_rets = time_series_calcs.calculate_returns(terms_vals) cross_rets = base_rets.sub(terms_rets.iloc[:,0],axis=0) # first returns of a time series will by NaN, given we don't know previous point cross_rets.iloc[0] = 0 cross_vals = time_series_calcs.create_mult_index(cross_rets) cross_vals.columns = [cr + '-tot.close'] elif freq == 'intraday': self.logger.info('Total calculated returns for intraday not implemented yet') return None if data_frame_agg is None: data_frame_agg = cross_vals else: data_frame_agg = data_frame_agg.join(cross_vals, how='outer') # strip the nan elements data_frame_agg = data_frame_agg.dropna() return data_frame_agg
def calculate_ret_stats_from_prices(self, returns_df, ann_factor): tsc = TimeSeriesCalcs() self.calculate_ret_stats(tsc.calculate_returns(returns_df), ann_factor)
def calculate_trading_PnL(self, br, asset_a_df, signal_df): """ calculate_trading_PnL - Calculates P&L of a trading strategy and statistics to be retrieved later Parameters ---------- br : BacktestRequest Parameters for the backtest specifying start date, finish data, transaction costs etc. asset_a_df : pandas.DataFrame Asset prices to be traded signal_df : pandas.DataFrame Signals for the trading strategy """ tsc = TimeSeriesCalcs() # make sure the dates of both traded asset and signal are aligned properly asset_df, signal_df = asset_a_df.align(signal_df, join='left', axis = 0) # only allow signals to change on the days when we can trade assets signal_df = signal_df.mask(numpy.isnan(asset_df.values)) # fill asset holidays with NaN signals signal_df = signal_df.fillna(method='ffill') # fill these down asset_df = asset_df.fillna(method='ffill') # fill down asset holidays returns_df = tsc.calculate_returns(asset_df) tc = br.spot_tc_bp signal_cols = signal_df.columns.values returns_cols = returns_df.columns.values pnl_cols = [] for i in range(0, len(returns_cols)): pnl_cols.append(returns_cols[i] + " / " + signal_cols[i]) if hasattr(br, 'signal_vol_adjust'): if br.signal_vol_adjust is True: leverage_df = self.calculate_leverage_factor(returns_df, br.signal_vol_target, br.signal_vol_max_leverage, br.signal_vol_periods, br.signal_vol_obs_in_year, br.signal_vol_rebalance_freq) signal_df = pandas.DataFrame( signal_df.values * leverage_df.values, index = signal_df.index, columns = signal_df.columns) self._individual_leverage = leverage_df _pnl = tsc.calculate_signal_returns_with_tc_matrix(signal_df, returns_df, tc = tc) _pnl.columns = pnl_cols # portfolio is average of the underlying signals interim_portfolio = pandas.DataFrame(data = _pnl.mean(axis = 1), index = _pnl.index, columns = ['Portfolio']) portfolio_leverage_df = pandas.DataFrame(data = numpy.ones(len(_pnl.index)), index = _pnl.index, columns = ['Portfolio']) if hasattr(br, 'portfolio_vol_adjust'): if br.portfolio_vol_adjust is True: interim_portfolio, portfolio_leverage_df = self.calculate_vol_adjusted_returns(interim_portfolio, br = br) self._portfolio = interim_portfolio self._signal = signal_df self._portfolio_leverage = portfolio_leverage_df # multiply portfolio leverage * individual signals to get final position signals length_cols = len(signal_df.columns) leverage_matrix = numpy.repeat(portfolio_leverage_df.values.flatten()[numpy.newaxis,:], length_cols, 0) self._portfolio_signal = pandas.DataFrame( data = numpy.multiply(numpy.transpose(leverage_matrix), signal_df.values), index = signal_df.index, columns = signal_df.columns) / float(length_cols) self._pnl = _pnl self._tsd_pnl = TimeSeriesDesc() self._tsd_pnl.calculate_ret_stats(self._pnl, br.ann_factor) self._portfolio.columns = ['Port'] self._tsd_portfolio = TimeSeriesDesc() self._tsd_portfolio.calculate_ret_stats(self._portfolio, br.ann_factor) self._cumpnl = tsc.create_mult_index(self._pnl) self._cumpnl.columns = pnl_cols self._cumportfolio = tsc.create_mult_index(self._portfolio) self._cumportfolio.columns = ['Port']
fields=['close'], # which fields to download vendor_tickers=[ 'EURUSD BGN Curncy', # ticker (Bloomberg) 'GBPUSD BGN Curncy', 'AUDUSD BGN Curncy' ], vendor_fields=['PX_LAST'], # which Bloomberg fields to download cache_algo='internet_load_return') # how to return data ltsf = LightTimeSeriesFactory() df = None df = ltsf.harvest_time_series(time_series_request) tsc = TimeSeriesCalcs() df = tsc.calculate_returns(df) df = tsc.rolling_corr(df['EURUSD.close'], 20, data_frame2=df[['GBPUSD.close', 'AUDUSD.close']]) gp = GraphProperties() gp.title = "1M FX rolling correlations" gp.scale_factor = 3 pf = PlotFactory() pf.plot_line_graph(df, adapter='pythalesians', gp=gp) ###### download daily data from Bloomberg for AUD/JPY, NZD/JPY spot with S&P500, then calculate correlation if True: time_series_request = TimeSeriesRequest( start_date="01 Jan 2015", # start date
def calculate_leverage_factor(self, returns_df, vol_target, vol_max_leverage, vol_periods = 60, vol_obs_in_year = 252, vol_rebalance_freq = 'BM', data_resample_freq = None, data_resample_type = 'mean', returns = True, period_shift = 0): """ calculate_leverage_factor - Calculates the time series of leverage for a specified vol target Parameters ---------- returns_df : DataFrame Asset returns vol_target : float vol target for assets vol_max_leverage : float maximum leverage allowed vol_periods : int number of periods to calculate volatility vol_obs_in_year : int number of observations in the year vol_rebalance_freq : str how often to rebalance vol_resample_freq : str do we need to resample the underlying data first? (eg. have we got intraday data?) returns : boolean is this returns time series or prices? period_shift : int should we delay the signal by a number of periods? Returns ------- pandas.Dataframe """ tsc = TimeSeriesCalcs() if data_resample_freq is not None: return # TODO not implemented yet if not returns: returns_df = tsc.calculate_returns(returns_df) roll_vol_df = tsc.rolling_volatility(returns_df, periods = vol_periods, obs_in_year = vol_obs_in_year).shift(period_shift) # calculate the leverage as function of vol target (with max lev constraint) lev_df = vol_target / roll_vol_df lev_df[lev_df > vol_max_leverage] = vol_max_leverage # should we take the mean, first, last in our resample if data_resample_type == 'mean': lev_df = lev_df.resample(vol_rebalance_freq).mean() elif data_resample_type == 'first': lev_df = lev_df.resample(vol_rebalance_freq).first() elif data_resample_type == 'last': lev_df = lev_df.resample(vol_rebalance_freq).last() else: # TODO implement other types return returns_df, lev_df = returns_df.align(lev_df, join='left', axis = 0) lev_df = lev_df.fillna(method='ffill') lev_df.ix[0:vol_periods] = numpy.nan # ignore the first elements before the vol window kicks in return lev_df
def create_tech_ind(self, data_frame_non_nan, name, tech_params): self._signal = None data_frame = data_frame_non_nan.fillna(method="ffill") if name == "SMA": self._techind = pandas.rolling_mean(data_frame, tech_params.sma_period) narray = numpy.where(data_frame > self._techind, 1, -1) self._signal = pandas.DataFrame(index = data_frame.index, data = narray) self._signal.columns = [x + " SMA Signal" for x in data_frame.columns.values] self._techind.columns = [x + " SMA" for x in data_frame.columns.values] elif name == "ROC": tsc = TimeSeriesCalcs() data_frame = tsc.calculate_returns(data_frame) self._techind = pandas.rolling_mean(data_frame, tech_params.roc_period) narray = numpy.where(self._techind > 0, 1, -1) self._signal = pandas.DataFrame(index = data_frame.index, data = narray) self._signal.columns = [x + " ROC Signal" for x in data_frame.columns.values] self._techind.columns = [x + " ROC" for x in data_frame.columns.values] elif name == "SMA2": sma = pandas.rolling_mean(data_frame, tech_params.sma_period) sma2 = pandas.rolling_mean(data_frame, tech_params.sma2_period) narray = numpy.where(sma > sma2, 1, -1) self._signal = pandas.DataFrame(index = data_frame.index, data = narray) self._signal.columns = [x + " SMA2 Signal" for x in data_frame.columns.values] sma.columns = [x + " SMA" for x in data_frame.columns.values] sma2.columns = [x + " SMA2" for x in data_frame.columns.values] self._techind = pandas.concat([sma, sma2], axis = 1) elif name in ['RSI']: # delta = data_frame.diff() # # dUp, dDown = delta.copy(), delta.copy() # dUp[dUp < 0] = 0 # dDown[dDown > 0] = 0 # # rolUp = pandas.rolling_mean(dUp, tech_params.rsi_period) # rolDown = pandas.rolling_mean(dDown, tech_params.rsi_period).abs() # # rsi = rolUp / rolDown # Get the difference in price from previous step delta = data_frame.diff() # Get rid of the first row, which is NaN since it did not have a previous # row to calculate the differences delta = delta[1:] # Make the positive gains (up) and negative gains (down) Series up, down = delta.copy(), delta.copy() up[up < 0] = 0 down[down > 0] = 0 # Calculate the EWMA roll_up1 = pandas.stats.moments.ewma(up, tech_params.rsi_period) roll_down1 = pandas.stats.moments.ewma(down.abs(), tech_params.rsi_period) # Calculate the RSI based on EWMA RS1 = roll_up1 / roll_down1 RSI1 = 100.0 - (100.0 / (1.0 + RS1)) # Calculate the SMA roll_up2 = pandas.rolling_mean(up, tech_params.rsi_period) roll_down2 = pandas.rolling_mean(down.abs(), tech_params.rsi_period) # Calculate the RSI based on SMA RS2 = roll_up2 / roll_down2 RSI2 = 100.0 - (100.0 / (1.0 + RS2)) self._techind = RSI2 self._techind.columns = [x + " RSI" for x in data_frame.columns.values] signal = data_frame.copy() sells = (signal.shift(-1) < tech_params.rsi_lower) & (signal > tech_params.rsi_lower) buys = (signal.shift(-1) > tech_params.rsi_upper) & (signal < tech_params.rsi_upper) print (buys[buys == True]) # buys signal[buys] = 1 signal[sells] = -1 signal[~(buys | sells)] = numpy.nan signal = signal.fillna(method = 'ffill') self._signal = signal self._signal.columns = [x + " RSI Signal" for x in data_frame.columns.values] elif name in ["BB"]: ## calcuate Bollinger bands mid = pandas.rolling_mean(data_frame, tech_params.bb_period); mid.columns = [x + " BB Mid" for x in data_frame.columns.values] std_dev = pandas.rolling_std(data_frame, tech_params.bb_period) BB_std = tech_params.bb_mult * std_dev lower = pandas.DataFrame(data = mid.values - BB_std.values, index = mid.index, columns = data_frame.columns) upper = pandas.DataFrame(data = mid.values + BB_std.values, index = mid.index, columns = data_frame.columns) ## calculate signals signal = data_frame.copy() buys = signal > upper sells = signal < lower signal[buys] = 1 signal[sells] = -1 signal[~(buys | sells)] = numpy.nan signal = signal.fillna(method = 'ffill') self._signal = signal self._signal.columns = [x + " " + name + " Signal" for x in data_frame.columns.values] lower.columns = [x + " BB Lower" for x in data_frame.columns.values] upper.columns = [x + " BB Mid" for x in data_frame.columns.values] upper.columns = [x + " BB Lower" for x in data_frame.columns.values] self._techind = pandas.concat([lower, mid, upper], axis = 1) # TODO create other indicators return self._techind
def construct_strategy(self, br = None): """ construct_strategy - Constructs the returns for all the strategies which have been specified. - gets parameters form fill_backtest_request - market data from fill_assets """ time_series_calcs = TimeSeriesCalcs() # get the parameters for backtesting if hasattr(self, 'br'): br = self.br elif br is None: br = self.fill_backtest_request() # get market data for backtest asset_df, spot_df, spot_df2, basket_dict = self.fill_assets() if hasattr(br, 'tech_params'): tech_params = br.tech_params else: tech_params = TechParams() cumresults = pandas.DataFrame(index = asset_df.index) portleverage = pandas.DataFrame(index = asset_df.index) from collections import OrderedDict tsdresults = OrderedDict() # each portfolio key calculate returns - can put parts of the portfolio in the key for key in basket_dict.keys(): asset_cut_df = asset_df[[x +'.close' for x in basket_dict[key]]] spot_cut_df = spot_df[[x +'.close' for x in basket_dict[key]]] self.logger.info("Calculating " + key) results, cash_backtest = self.construct_individual_strategy(br, spot_cut_df, spot_df2, asset_cut_df, tech_params, key) cumresults[results.columns[0]] = results portleverage[results.columns[0]] = cash_backtest.get_porfolio_leverage() tsdresults[key] = cash_backtest.get_portfolio_pnl_tsd() # for a key, designated as the final strategy save that as the "strategy" if key == self.FINAL_STRATEGY: self._strategy_pnl = results self._strategy_pnl_tsd = cash_backtest.get_portfolio_pnl_tsd() self._strategy_leverage = cash_backtest.get_porfolio_leverage() self._strategy_signal = cash_backtest.get_porfolio_signal() self._strategy_pnl_trades = cash_backtest.get_pnl_trades() # get benchmark for comparison benchmark = self.construct_strategy_benchmark() cumresults_benchmark = self.compare_strategy_vs_benchmark(br, cumresults, benchmark) self._strategy_group_benchmark_tsd = tsdresults if hasattr(self, '_benchmark_tsd'): tsdlist = tsdresults tsdlist['Benchmark'] = (self._benchmark_tsd) self._strategy_group_benchmark_tsd = tsdlist # calculate annualised returns years = time_series_calcs.average_by_annualised_year(time_series_calcs.calculate_returns(cumresults_benchmark)) self._strategy_group_pnl = cumresults self._strategy_group_pnl_tsd = tsdresults self._strategy_group_benchmark_pnl = cumresults_benchmark self._strategy_group_leverage = portleverage self._strategy_group_benchmark_annualised_pnl = years
def create_tech_ind(self, data_frame_non_nan, name, tech_params): self._signal = None data_frame = data_frame_non_nan.fillna(method="ffill") if name == "SMA": self._techind = pandas.rolling_mean(data_frame, tech_params.sma_period) narray = numpy.where(data_frame > self._techind, 1, -1) self._signal = pandas.DataFrame(index = data_frame.index, data = narray) self._signal.columns = [x + " SMA Signal" for x in data_frame.columns.values] self._techind.columns = [x + " SMA" for x in data_frame.columns.values] elif name == "ROC": tsc = TimeSeriesCalcs() data_frame = tsc.calculate_returns(data_frame) self._techind = pandas.rolling_mean(data_frame, tech_params.roc_period) narray = numpy.where(self._techind > 0, 1, -1) self._signal = pandas.DataFrame(index = data_frame.index, data = narray) self._signal.columns = [x + " ROC Signal" for x in data_frame.columns.values] self._techind.columns = [x + " ROC" for x in data_frame.columns.values] elif name == "SMA2": sma = pandas.rolling_mean(data_frame, tech_params.sma_period) sma2 = pandas.rolling_mean(data_frame, tech_params.sma2_period) narray = numpy.where(sma > sma2, 1, -1) self._signal = pandas.DataFrame(index = data_frame.index, data = narray) self._signal.columns = [x + " SMA2 Signal" for x in data_frame.columns.values] sma.columns = [x + " SMA" for x in data_frame.columns.values] sma2.columns = [x + " SMA2" for x in data_frame.columns.values] self._techind = pandas.concat([sma, sma2], axis = 1) elif name in ['RSI']: # delta = data_frame.diff() # # dUp, dDown = delta.copy(), delta.copy() # dUp[dUp < 0] = 0 # dDown[dDown > 0] = 0 # # rolUp = pandas.rolling_mean(dUp, tech_params.rsi_period) # rolDown = pandas.rolling_mean(dDown, tech_params.rsi_period).abs() # # rsi = rolUp / rolDown # Get the difference in price from previous step delta = data_frame.diff() # Get rid of the first row, which is NaN since it did not have a previous # row to calculate the differences delta = delta[1:] # Make the positive gains (up) and negative gains (down) Series up, down = delta.copy(), delta.copy() up[up < 0] = 0 down[down > 0] = 0 # Calculate the EWMA roll_up1 = pandas.stats.moments.ewma(up, tech_params.rsi_period) roll_down1 = pandas.stats.moments.ewma(down.abs(), tech_params.rsi_period) # Calculate the RSI based on EWMA RS1 = roll_up1 / roll_down1 RSI1 = 100.0 - (100.0 / (1.0 + RS1)) # Calculate the SMA roll_up2 = pandas.rolling_mean(up, tech_params.rsi_period) roll_down2 = pandas.rolling_mean(down.abs(), tech_params.rsi_period) # Calculate the RSI based on SMA RS2 = roll_up2 / roll_down2 RSI2 = 100.0 - (100.0 / (1.0 + RS2)) self._techind = RSI2 self._techind.columns = [x + " RSI" for x in data_frame.columns.values] signal = data_frame.copy() sells = (signal.shift(-1) < tech_params.rsi_lower) & (signal > tech_params.rsi_lower) buys = (signal.shift(-1) > tech_params.rsi_upper) & (signal < tech_params.rsi_upper) # print (buys[buys == True]) # buys signal[buys] = 1 signal[sells] = -1 signal[~(buys | sells)] = numpy.nan signal = signal.fillna(method = 'ffill') self._signal = signal self._signal.columns = [x + " RSI Signal" for x in data_frame.columns.values] elif name in ["BB"]: ## calcuate Bollinger bands mid = pandas.rolling_mean(data_frame, tech_params.bb_period); mid.columns = [x + " BB Mid" for x in data_frame.columns.values] std_dev = pandas.rolling_std(data_frame, tech_params.bb_period) BB_std = tech_params.bb_mult * std_dev lower = pandas.DataFrame(data = mid.values - BB_std.values, index = mid.index, columns = data_frame.columns) upper = pandas.DataFrame(data = mid.values + BB_std.values, index = mid.index, columns = data_frame.columns) ## calculate signals signal = data_frame.copy() buys = signal > upper sells = signal < lower signal[buys] = 1 signal[sells] = -1 signal[~(buys | sells)] = numpy.nan signal = signal.fillna(method = 'ffill') self._signal = signal self._signal.columns = [x + " " + name + " Signal" for x in data_frame.columns.values] lower.columns = [x + " BB Lower" for x in data_frame.columns.values] upper.columns = [x + " BB Mid" for x in data_frame.columns.values] upper.columns = [x + " BB Lower" for x in data_frame.columns.values] self._techind = pandas.concat([lower, mid, upper], axis = 1) elif name == "long-only": ## have +1 signals only self._techind = data_frame # the technical indicator is just "prices" narray = numpy.ones((len(data_frame.index), len(data_frame.columns))) self._signal = pandas.DataFrame(index = data_frame.index, data = narray) self._signal.columns = [x + " Long Only Signal" for x in data_frame.columns.values] self._techind.columns = [x + " Long Only" for x in data_frame.columns.values] # TODO create other indicators # apply signal multiplier (typically to flip signals) if hasattr(tech_params, 'signal_mult'): self._signal = self._signal * tech_params.signal_mult return self._techind
def calculate_leverage_factor(self, returns_df, vol_target, vol_max_leverage, vol_periods=60, vol_obs_in_year=252, vol_rebalance_freq='BM', returns=True, period_shift=0): """ calculate_leverage_factor - Calculates the time series of leverage for a specified vol target Parameters ---------- returns_df : DataFrame Asset returns vol_target : float vol target for assets vol_max_leverage : float maximum leverage allowed vol_periods : int number of periods to calculate volatility vol_obs_in_year : int number of observations in the year vol_rebalance_freq : str how often to rebalance returns : boolean is this returns time series or prices? period_shift : int should we delay the signal by a number of periods? Returns ------- pandas.Dataframe """ tsc = TimeSeriesCalcs() if not returns: returns_df = tsc.calculate_returns(returns_df) roll_vol_df = tsc.rolling_volatility( returns_df, periods=vol_periods, obs_in_year=vol_obs_in_year).shift(period_shift) # calculate the leverage as function of vol target (with max lev constraint) lev_df = vol_target / roll_vol_df lev_df[lev_df > vol_max_leverage] = vol_max_leverage # only allow the leverage change at resampling frequency (eg. monthly 'BM') lev_df = lev_df.resample(vol_rebalance_freq) returns_df, lev_df = returns_df.align(lev_df, join='left', axis=0) lev_df = lev_df.fillna(method='ffill') return lev_df
def calculate_trading_PnL(self, br, asset_a_df, signal_df): """ calculate_trading_PnL - Calculates P&L of a trading strategy and statistics to be retrieved later Parameters ---------- br : BacktestRequest Parameters for the backtest specifying start date, finish data, transaction costs etc. asset_a_df : pandas.DataFrame Asset prices to be traded signal_df : pandas.DataFrame Signals for the trading strategy """ tsc = TimeSeriesCalcs() # signal_df.to_csv('e:/temp0.csv') # make sure the dates of both traded asset and signal are aligned properly asset_df, signal_df = asset_a_df.align(signal_df, join='left', axis = 'index') # only allow signals to change on the days when we can trade assets signal_df = signal_df.mask(numpy.isnan(asset_df.values)) # fill asset holidays with NaN signals signal_df = signal_df.fillna(method='ffill') # fill these down asset_df = asset_df.fillna(method='ffill') # fill down asset holidays returns_df = tsc.calculate_returns(asset_df) tc = br.spot_tc_bp signal_cols = signal_df.columns.values returns_cols = returns_df.columns.values pnl_cols = [] for i in range(0, len(returns_cols)): pnl_cols.append(returns_cols[i] + " / " + signal_cols[i]) # do we have a vol target for individual signals? if hasattr(br, 'signal_vol_adjust'): if br.signal_vol_adjust is True: if not(hasattr(br, 'signal_vol_resample_type')): br.signal_vol_resample_type = 'mean' leverage_df = self.calculate_leverage_factor(returns_df, br.signal_vol_target, br.signal_vol_max_leverage, br.signal_vol_periods, br.signal_vol_obs_in_year, br.signal_vol_rebalance_freq, br.signal_vol_resample_freq, br.signal_vol_resample_type) signal_df = pandas.DataFrame( signal_df.values * leverage_df.values, index = signal_df.index, columns = signal_df.columns) self._individual_leverage = leverage_df # contains leverage of individual signal (before portfolio vol target) _pnl = tsc.calculate_signal_returns_with_tc_matrix(signal_df, returns_df, tc = tc) _pnl.columns = pnl_cols # portfolio is average of the underlying signals: should we sum them or average them? if hasattr(br, 'portfolio_combination'): if br.portfolio_combination == 'sum': portfolio = pandas.DataFrame(data = _pnl.sum(axis = 1), index = _pnl.index, columns = ['Portfolio']) elif br.portfolio_combination == 'mean': portfolio = pandas.DataFrame(data = _pnl.mean(axis = 1), index = _pnl.index, columns = ['Portfolio']) else: portfolio = pandas.DataFrame(data = _pnl.mean(axis = 1), index = _pnl.index, columns = ['Portfolio']) portfolio_leverage_df = pandas.DataFrame(data = numpy.ones(len(_pnl.index)), index = _pnl.index, columns = ['Portfolio']) # should we apply vol target on a portfolio level basis? if hasattr(br, 'portfolio_vol_adjust'): if br.portfolio_vol_adjust is True: portfolio, portfolio_leverage_df = self.calculate_vol_adjusted_returns(portfolio, br = br) self._portfolio = portfolio self._signal = signal_df # individual signals (before portfolio leverage) self._portfolio_leverage = portfolio_leverage_df # leverage on portfolio # multiply portfolio leverage * individual signals to get final position signals length_cols = len(signal_df.columns) leverage_matrix = numpy.repeat(portfolio_leverage_df.values.flatten()[numpy.newaxis,:], length_cols, 0) # final portfolio signals (including signal & portfolio leverage) self._portfolio_signal = pandas.DataFrame( data = numpy.multiply(numpy.transpose(leverage_matrix), signal_df.values), index = signal_df.index, columns = signal_df.columns) if hasattr(br, 'portfolio_combination'): if br.portfolio_combination == 'sum': pass elif br.portfolio_combination == 'mean': self._portfolio_signal = self._portfolio_signal / float(length_cols) else: self._portfolio_signal = self._portfolio_signal / float(length_cols) self._pnl = _pnl # individual signals P&L # TODO FIX very slow - hence only calculate on demand _pnl_trades = None # _pnl_trades = tsc.calculate_individual_trade_gains(signal_df, _pnl) self._pnl_trades = _pnl_trades self._tsd_pnl = TimeSeriesDesc() self._tsd_pnl.calculate_ret_stats(self._pnl, br.ann_factor) self._portfolio.columns = ['Port'] self._tsd_portfolio = TimeSeriesDesc() self._tsd_portfolio.calculate_ret_stats(self._portfolio, br.ann_factor) self._cumpnl = tsc.create_mult_index(self._pnl) # individual signals cumulative P&L self._cumpnl.columns = pnl_cols self._cumportfolio = tsc.create_mult_index(self._portfolio) # portfolio cumulative P&L self._cumportfolio.columns = ['Port']
start_date="01 Jan 1970", # start date finish_date=datetime.date.today(), # finish date freq='daily', # daily data data_source='quandl', # use Quandl as data source tickers=[ 'EURUSD', # ticker (Thalesians) 'GBPUSD' ], fields=['close'], # which fields to download vendor_tickers=['FRED/DEXUSEU', 'FRED/DEXUSUK'], # ticker (Quandl) vendor_fields=['close'], # which Bloomberg fields to download cache_algo='internet_load_return') # how to return data ltsf = LightTimeSeriesFactory() df = ltsf.harvest_time_series(time_series_request) df_ret = tsc.calculate_returns(df) day_of_month_seasonality = seasonality.bus_day_of_month_seasonality( df_ret, partition_by_month=False) day_of_month_seasonality = tsc.convert_month_day_to_date_time( day_of_month_seasonality) gp = GraphProperties() gp.date_formatter = '%b' gp.title = 'FX spot moves by day of month' gp.scale_factor = 3 gp.file_output = "output_data/FX spot DOM seasonality.png" pf.plot_line_graph(day_of_month_seasonality, adapter='pythalesians', gp=gp)
###### calculate seasonal moves in EUR/USD and GBP/USD (using Quandl data) if True: time_series_request = TimeSeriesRequest( start_date = "01 Jan 1970", # start date finish_date = datetime.date.today(), # finish date freq = 'daily', # daily data data_source = 'quandl', # use Quandl as data source tickers = ['EURUSD', # ticker (Thalesians) 'GBPUSD'], fields = ['close'], # which fields to download vendor_tickers = ['FRED/DEXUSEU', 'FRED/DEXUSUK'], # ticker (Quandl) vendor_fields = ['close'], # which Bloomberg fields to download cache_algo = 'internet_load_return') # how to return data ltsf = LightTimeSeriesFactory() df = ltsf.harvest_time_series(time_series_request) df_ret = tsc.calculate_returns(df) day_of_month_seasonality = seasonality.bus_day_of_month_seasonality(df_ret, partition_by_month = False) day_of_month_seasonality = tsc.convert_month_day_to_date_time(day_of_month_seasonality) gp = GraphProperties() gp.date_formatter = '%b' gp.title = 'FX spot moves by time of year' gp.scale_factor = 3 gp.file_output = "output_data/20150724 FX spot seas.png" pf.plot_line_graph(day_of_month_seasonality, adapter='pythalesians', gp = gp)
def calculate_ret_stats_from_prices(self, returns_df, ann_factor): tsc = TimeSeriesCalcs() self.calculate_ret_stats(tsc.calculate_returns(returns_df), ann_factor)