def backtest(self, prices, ref_prices, params): m = params["m"] x = params["x"] interval = params[Ct.interval_key()] mon_ret_df = Financials.pct_change(prices) p_return = IntradayResistanceBreakout.calculate(mon_ret_df, m, x) cagr_params = {Ct.interval_key(): interval} cagr = CAGR.get_cagr(p_return, cagr_params) sharpe_params = {"rf": 0.025, Ct.interval_key(): interval} sharpe = Sharpe.get_sharpe(p_return, sharpe_params) max_dd = MaxDrawdown.get_max_drawdown(p_return) # calculating overall strategy's KPIs mon_ret_df = Financials.pct_change(ref_prices) cagr_ref = CAGR.get_cagr(mon_ret_df, cagr_params) sharpe_params = {"rf": 0.025, Ct.interval_key(): interval} sharpe_ref = Sharpe.get_sharpe(mon_ret_df, sharpe_params) max_dd_ref = MaxDrawdown.get_max_drawdown(mon_ret_df) print("CAGR - Portfolio: {}".format(cagr[Ct.cagr_key()]["mon_ret"])) print("Sharpe - Portfolio: {}".format( sharpe[Ct.sharpe_key()]["mon_ret"])) print("MAX-Drawdown - Portfolio: {}".format( max_dd[Ct.max_drawdown_key()]["mon_ret"])) print("CAGR - Ref: {}".format(cagr_ref[Ct.cagr_key()]["^DJI"])) print("Sharpe - Ref: {}".format(sharpe_ref[Ct.sharpe_key()]["^DJI"])) print("MAX-Drawdown - Ref: {}".format( max_dd_ref[Ct.max_drawdown_key()]["^DJI"])) IntradayResistanceBreakout.plot(p_return, mon_ret_df)
def test_KPI_cagr(self): tickers = ["TSLA", "SPY"] interval = Ct.INTERVAL.DAY conf = { Ct.tickers_key(): tickers, Ct.historical_type_key(): DATASOURCETYPE.YFINANCE, Ct.fundamentals_type_key(): None, Ct.fundamentals_options_key(): [], Ct.force_fundamentals_key(): False, Ct.indicators_key(): [], Ct.start_date_key(): dt.datetime(2021, 3, 7) - dt.timedelta(1825), Ct.end_date_key(): dt.datetime(2021, 3, 7), Ct.interval_key(): interval, Ct.period_key(): None, Ct.bulk_key(): True } stocks = \ StocksFactory.create_stocks( conf=conf ) prices_df = stocks[0].get_prices_data(keys={Ct.adj_close_key(): True}) df = Financials.pct_change(prices_df) params = {Ct.interval_key(): interval} cagr = CAGR() result = cagr.calculate(df, params) self.assertEqual(0.7093784038450781, result[Ct.cagr_key()]['TSLA']) self.assertEqual(0.1608091728848835, result[Ct.cagr_key()]['SPY'])
class CAGR(KPI): kpi_name = Ct.cagr_key() def __init__(self, params=None): super().__init__(params) if not params: self.params = {} def calculate(self, df, params=None): """"function to calculate the Cumulative Annual Growth Rate of a trading strategy""" super().calculate(df, params) self.result = CAGR.get_cagr(df, self.params) return self.result # Params: {period:Ct.INTERVAL.MONTH|Ct.INTERVAL.DAY} # DF should be a percentage change @staticmethod def get_cagr(input_df, params=None): """"function to calculate the Cumulative Annual Growth Rate of a trading strategy""" reference_days = KPI.get_reference_days(params) df = input_df.copy() df.columns = df.columns.droplevel(1) cagr_data = (1 + df).cumprod() n = len(cagr_data) / reference_days result_df = pd.DataFrame() result_df[CAGR.kpi_name] = cagr_data.iloc[-1]**(1 / n) - 1 return result_df
def get_sortino(input_df, params=None): if params is None: params = {} if "rf" not in params.keys(): # USA: risk free rate params = {"rf": 0.0144} rf = params["rf"] "function to calculate Sortino ratio ; rf is the risk free rate" cagr = CAGR.get_cagr(input_df, params) vol_params = params vol_params[Ct.neg_volatility_key()] = True neg_vol = Volatility.get_volatility(input_df, vol_params) result_df = pd.DataFrame() result_df[Sortino.kpi_name] = (cagr.loc[:, Ct.cagr_key()] - rf) / neg_vol.loc[:, Ct.volatility_key()] result_df.rename(index={0: Sortino.kpi_name}, inplace=True) return result_df
def get_calmar(input_df, params=None): """function to calculate Calmar""" if params is None: params = {} cagr = CAGR.get_cagr(input_df, params) max_dd = MaxDrawdown.get_max_drawdown(input_df) result_df = pd.DataFrame() result_df[Calmar.kpi_name] = (cagr[Ct.cagr_key()] / max_dd[Ct.max_drawdown_key()]) return result_df
def get_sharpe(input_df, params): """ function to calculate sharpe """ if params is None: params = {} if "rf" not in params.keys(): # USA: risk free rate params["rf"] = 0.0144 rf = params["rf"] "function to calculate sharpe ratio ; rf is the risk free rate" cagr = CAGR.get_cagr(input_df, params) volatility = Volatility.get_volatility(input_df, params) result_df = pd.DataFrame() result_df[Sharpe.kpi_name] = (cagr.loc[:, Ct.cagr_key()] - rf) / volatility.loc[:, Ct.volatility_key()] return result_df