def pnl_analyze(self, detailDF_pnl): ''' Function that uses pyfolio developed by quantopian to analyze the pnl curve given by the backTest function Params: total_balance series from detail dataframe generated by backTest Note: you can get pyfolio package simply by typing 'pip install pyfolio' and enter in your command line tool console. No need to install theano since we don't do bayesian analysis here. ''' # Get return series from pnl series, and resample return series on a daily basis pnl_daily = detailDF_pnl.resample('D').last() day_one_return = pnl_daily[0]/self.init_cash - 1. pnl_ret_daily = pnl_daily.pct_change() pnl_ret_daily[0] = day_one_return pnl_ret_daily = pnl_ret_daily.dropna() # Convert datetime to timezone-aware format and change the timezone to Beijing pnl_ret_daily = pnl_ret_daily.tz_localize('UTC').tz_convert('Asia/Shanghai') # PnL plot, drawdown analysis and risk analysis import pyfolio as pf # This benchmark(SHY) is the ETF that tracks 1-3 year US treasury bonds, you can also use # symbols like SPY for S&P500 or ASHR for CSI300 index benchmark = pf.utils.get_symbol_rets('SHY') # Generate different reports according to length of backtest timeIndex = pnl_ret_daily.index if((timeIndex[-1]-timeIndex[0]).days>30): pf.create_returns_tear_sheet(pnl_ret_daily, benchmark_rets=benchmark) else: pf.create_simple_tear_sheet(pnl_ret_daily, benchmark_rets=benchmark) return pnl_ret_daily
def create_tearsheet(self): rets = self._equity.pct_change() rets = rets[1:] rets.index = rets.index.tz_localize('UTC') self._df_positions.index = self._df_positions.index.tz_localize('UTC') self._df_trades.index = self._df_trades.index.tz_localize('UTC') #pf.create_full_tear_sheet(rets, self._df_positions, self._df_trades) pf.create_simple_tear_sheet(rets, benchmark_rets=rets)
def get_pyfolio_simple_tear_sheet(mdl, X_tr, Y_tr, X_tst, Y_tst, rtns_actual): # 1. Fit model using training set mdl.fit(X_tr, Y_tr) # 2. Predict labels using trained model predicted_labels = pd.Series(mdl.predict(X_tst), index=Y_tst.index) # 3. Calculate return using the predicted labels together the return vector rtns = predicted_labels * rtns_actual # 4. Generate term sheet using the backtest portfolio return vector using PyFolio package pf.create_simple_tear_sheet(rtns)
def backtest(mode): for m in mode: weights_backtest = {} for i in tqdm(range(37)): # 37 for 2019-01-01 observation_start_date = datetime.strftime( BACKTEST_START+relativedelta(months=i)-relativedelta(years=1), '%Y-%m-%d') rebalance_date = datetime.strftime( BACKTEST_START+relativedelta(months=i), '%Y-%m-%d') _, stat = empirical_estimate(data, tickers, observation_start_date, rebalance_date) weights_backtest[rebalance_date] = weight_construction_portfolio(stat, m) # print(weights_backtest[rebalance_date]) datemap = OrderedDict(weights_backtest) # print(datemap) # get all trading dates df_backtest = pd.DataFrame({'Date': list(data['MSFT'].index)}) df_backtest = df_backtest[df_backtest['Date']>=datetime.strftime( BACKTEST_START,'%Y-%m-%d')] df_backtest = df_backtest[df_backtest['Date']<=BACKTEST_END] df_backtest['Date'] = df_backtest['Date'].apply( lambda x: datetime.strftime(x,'%Y-%m-%d')) def find_weight(dt): result = None for dm, w in datemap.items(): if dt >= dm: result = w if dt < dm: return result else: return result df_backtest['Weight'] = df_backtest['Date'].apply(find_weight) df_backtest['Logret'] = df_backtest['Date'].apply( lambda x: [data[t].loc[x,'Logret'] for t in tickers]) df_backtest['Daily_Logret'] = df_backtest.apply( lambda x: sum(r*w for r,w in zip(x['Weight'],x['Logret'])) , axis=1) # Benchmark viz df_backtest['Date_dt'] = df_backtest['Date'].apply( lambda x: datetime.strptime(x, '%Y-%m-%d')) plt.plot(df_backtest['Date_dt'],df_backtest['Daily_Logret'].cumsum(),label=m) #Performance metrics if len(mode) == 1: df_metrics = df_backtest[['Date_dt','Daily_Logret']] df_metrics = df_metrics.set_index('Date_dt') pf.create_simple_tear_sheet(df_metrics['Daily_Logret']) plt.legend() plt.show()
def calculate(self): self.data() self.portfolio_weights = self.n_assets * [1 / self.n_assets] self.portfolio_returns = pd.Series(np.dot(self.portfolio_weights, self.returns.T), index=self.returns.index) pf.create_simple_tear_sheet(self.portfolio_returns)
def instrument_result_pf(instrument, path, benchmark, start_date): df = pd.read_csv(os.path.join(path, '%s_equitys.csv' % instrument), header=None, names=['timestamp', 'equitys', 'pnl', 'fee']) benchmark_df = pd.read_csv(os.path.join(benchmark, '%s_equitys.csv' % instrument), header=None, names=['timestamp', 'equitys', 'pnl', 'fee']) rets = calc_instrument_daily_ret(df) benchmark_rets = calc_instrument_daily_ret(benchmark_df) pf.create_simple_tear_sheet(rets, benchmark_rets=benchmark_rets, live_start_date=start_date)
def report(self): """ TODO: currently this function only supports daily PnL data. I should adjust it to work with a user-defined timescale. """ from pyfolio import create_simple_tear_sheet total_days = (self.bars.index[-1] - self.bars.index[0]).days n_of_trades = self.pos.diff().abs().sum() / 2 print('Mean value of trades per day = ' + str(n_of_trades / total_days)) create_simple_tear_sheet(returns=self.get_pnl().resample('1D').sum())
transactions=transactions) # In[ ]: sheets # In[ ]: returns.shape # In[ ]: returns.head() # In[ ]: type(returns) # In[ ]: returns.index = returns.index.date # In[ ]: returns # In[ ]: #pf.create_simple_tear_sheet(returns, positions=positions, transactions=transactions, live_start_date='2019-02-10') pf.create_simple_tear_sheet(returns)
def create_tear_sheet(self): return_ser = pd.read_csv('output.csv', index_col=0, header=0) return_ser.index = pd.to_datetime(return_ser.index) # pf.create_returns_tear_sheet(return_ser['HK.00001']) with open("data.html", "w") as file: file.write(pf.create_simple_tear_sheet(returns=return_ser['HK.00001']))
', but since the index has grown so much over time this statistic is not extremely meaningful') #f. Hit Ratio Hit_Ratio = positive_trades / total_trades print('The Hit Ratio for this strategy is ' + str(np.round(Hit_Ratio, 4))) #g. Highest profit & loss in a single trade trade_data = data['P & L'].dropna() Max_Profit = trade_data.max() Max_Loss = trade_data.min() print('The Highest Profit on any one trade was ' + str(np.round(Max_Profit, 2)) + ' dollars') print('The Highest Loss on any one trade was ' + str(np.round(Max_Loss, 2)) + ' dollars') pyfolio.create_simple_tear_sheet(data['Strategy']) pyfolio.create_full_tear_sheet(data['Strategy']) ##############Optional - Optimize the Strategy################################# import time t0 = time.time() #SMA sma1 = range(1, 40, 3) sma2 = range(20, 60, 3) sma3 = range(60, 200, 3) from itertools import product
for i in ticker: ohlc = get_historical_data(i, start, end, output_format='pandas', token=strToken) ohlc.columns = ["Open", "High", "Low", i, "Volume"] dfRet[i] = ohlc[i] return dfRet # In[19]: strTicker = GetStockTicker() print('No. of tickers:', len(strTicker)) dfRisky = IexStockAsset(strTicker) dfReturns = dfRisky.pct_change().dropna() print(dfReturns) intRisky = len(strTicker) print(intRisky) dblWeights = intRisky * [1 / intRisky] PortfolioReturns = pandas.Series(numpy.dot(dblWeights, dfReturns.T), index=dfReturns.index) print(dfReturns.T) print(PortfolioReturns) pyfolio.create_simple_tear_sheet(PortfolioReturns) # In[ ]:
#!pip install pyfolio import pyfolio as pf import pandas as pd import pandas_datareader as web snow = web.get_data_yahoo('SNOW', start='2020-03-26', end='2021-03-27') snow['% Returns'] = snow['Adj Close'].pct_change() pf.create_simple_tear_sheet(snow['% Returns'])
n_assets = len(RISKY_ASSETS) #3. Download the stock prices from Yahoo Finance: prices_df = yf.download(RISKY_ASSETS, start=START_DATE, end=END_DATE, adjusted=True) #4. Calculate individual asset returns: returns = prices_df['Adj Close'].pct_change().dropna() #5. Define the weights: portfolio_weights = n_assets * [1 / n_assets] #6. Calculate the portfolio returns: #portfolio_returns = pd.Series(np.dot(portfolio_weights, returns.T), #index=returns.index) portfolio_returns = returns #7. Create the tear sheet (simple variant): pf.create_simple_tear_sheet(portfolio_returns) # %% data = ta_f.get_BSH_signals(df=data, indicator_symbol='SRSI', plot=True) # %% [markdown] # ### Plot Technical Indicators # %% # %% # Plot BB ta_f.plot(df=data, indicator_symbol='BB') # %% RSI ta_f.plot(df=data, indicator_symbol='RSI')
def get_pyfolio_simple_tear_sheet(mdl, X_tr, Y_tr, X_tst, Y_tst, rtns_actual): mdl.fit(X_tr, Y_tr) predicted_labels = pd.Series(mdl.predict(X_tst), index=Y_tst.index) rtns = predicted_labels * rtns_actual pf.create_simple_tear_sheet(rtns)
def result_pf(path, benchmark): rets = calc_daily_rets(path) ben_rets = calc_daily_rets(benchmark) pf.create_simple_tear_sheet(rets, benchmark_rets=ben_rets, live_start_date=None)