def test_value_at_risk(self, test_cutoff): # empyrical can't tolerate NaNs here res_a = empyrical.value_at_risk(ret['a'].iloc[1:], cutoff=test_cutoff) res_b = empyrical.value_at_risk(ret['b'].iloc[1:], cutoff=test_cutoff) res_c = empyrical.value_at_risk(ret['c'].iloc[1:], cutoff=test_cutoff) assert isclose(ret['a'].vbt.returns.value_at_risk(cutoff=test_cutoff), res_a) pd.testing.assert_series_equal( ret.vbt.returns.value_at_risk(cutoff=test_cutoff), pd.Series([res_a, res_b, res_c], index=ret.columns))
def test_value_at_risk(self, test_cutoff): # empyrical can't tolerate NaN here res_a = empyrical.value_at_risk(ret['a'].iloc[1:], cutoff=test_cutoff) res_b = empyrical.value_at_risk(ret['b'].iloc[1:], cutoff=test_cutoff) res_c = empyrical.value_at_risk(ret['c'].iloc[1:], cutoff=test_cutoff) assert isclose(ret['a'].vbt.returns.value_at_risk(cutoff=test_cutoff), res_a) pd.testing.assert_series_equal( ret.vbt.returns.value_at_risk(cutoff=test_cutoff), pd.Series([res_a, res_b, res_c], index=ret.columns).rename('value_at_risk')) pd.testing.assert_series_equal( ret.vbt.returns.rolling_value_at_risk(ret.shape[0], minp=1, cutoff=test_cutoff).iloc[-1], pd.Series([res_a, res_b, res_c], index=ret.columns).rename(ret.index[-1]))
def _func(_p): _p._set_kwargs(**self._kwargs) _ret = self._returns[_p._id] var = ep.value_at_risk(_ret) _p.__log__('VaR: %s' % var) self._vars[_p._id] = var v = var * self._weights[_p._id] return v
def _get_backtest_performance_metrics(ret, benchmark_ret): metrics = { 'alpha': empyrical.alpha(ret, benchmark_ret), 'beta': empyrical.beta(ret, benchmark_ret), 'return': empyrical.cum_returns_final(ret), 'cagr': empyrical.cagr(ret), 'sharpe': empyrical.sharpe_ratio(ret), 'max_drawdown': empyrical.max_drawdown(ret), 'var': empyrical.value_at_risk(ret), 'volatility': empyrical.annual_volatility(ret), } return metrics
def plot_function(epoch_weights): ew = np.concatenate(epoch_weights).reshape(-1, No_Channels) comm = np.sum(np.abs(ew[1:] - ew[:-1]), axis=1) ret = np.sum(np.multiply(ew, y_test.numpy()), axis=1)[1:] ind = pd.date_range("20180101", periods=len(ret), freq='H') ret = pd.DataFrame(ret - comm * cost, index = ind) exp = np.exp(ret.resample('1D').sum()) - 1.0 ggg = 'Drawdown:', emp.max_drawdown(exp).values[0], 'Sharpe:', emp.sharpe_ratio(exp)[0], \ 'Sortino:', emp.sortino_ratio(exp).values[0], 'Stability:', emp.stability_of_timeseries(exp), \ 'Tail:', emp.tail_ratio(exp), 'ValAtRisk:', emp.value_at_risk(exp) ttt = ' '.join(str(x) for x in ggg) print(ttt) plt.figure() np.exp(ret).cumprod().plot(figsize=(48, 12), title=ttt) plt.savefig('cumulative_return') plt.close() ret = ret.resample('1W').sum() plt.figure(figsize=(48, 12)) pal = sns.color_palette("Greens_d", len(ret)) rank = ret.iloc[:,0].argsort() ax = sns.barplot(x=ret.index.strftime('%d-%m'), y=ret.values.reshape(-1), palette=np.array(pal[::-1])[rank]) ax.text(0.5, 1.0, ttt, horizontalalignment='center', verticalalignment='top', transform=ax.transAxes) plt.savefig('weekly_returns') plt.close() ew_df = pd.DataFrame(ew) plt.figure(figsize=(48, 12)) ax = sns.heatmap(ew_df.T, cmap=cmap, center=0, xticklabels=False, robust=True) ax.text(0.5, 1.0, ttt, horizontalalignment='center', verticalalignment='top', transform=ax.transAxes) plt.savefig('portfolio_weights') plt.close() tr = np.diff(ew.T, axis=1) plt.figure(figsize=(96, 12)) ax = sns.heatmap(tr, cmap=cmap, center=0, robust=True, yticklabels=False, xticklabels=False) ax.text(0.5, 1.0, ttt, horizontalalignment='center', verticalalignment='top', transform=ax.transAxes) plt.savefig('transactions') plt.close()
def calculate_statistics(self, df: DataFrame = None, output=True): """""" self.output("开始计算策略统计指标") # Check DataFrame input exterior if df is None: df = self.daily_df # Check for init DataFrame if df is None: # Set all statistics to 0 if no trade. start_date = "" end_date = "" total_days = 0 profit_days = 0 loss_days = 0 end_balance = 0 max_drawdown = 0 max_ddpercent = 0 max_drawdown_duration = 0 max_drawdown_end = 0 total_net_pnl = 0 daily_net_pnl = 0 total_commission = 0 daily_commission = 0 total_slippage = 0 daily_slippage = 0 total_turnover = 0 daily_turnover = 0 total_trade_count = 0 daily_trade_count = 0 total_return = 0 annual_return = 0 daily_return = 0 return_std = 0 sharpe_ratio = 0 sortino_info = 0 win_ratio = 0 return_drawdown_ratio = 0 tail_ratio_info = 0 stability_return = 0 win_loss_pnl_ratio = 0 pnl_medio = 0 duration_medio = 0 calmar_ratio = 0 else: # Calculate balance related time series data df["balance"] = df["net_pnl"].cumsum() + self.capital df["return"] = np.log(df["balance"] / df["balance"].shift(1)).fillna(0) df["highlevel"] = (df["balance"].rolling(min_periods=1, window=len(df), center=False).max()) df["drawdown"] = df["balance"] - df["highlevel"] df["ddpercent"] = df["drawdown"] / df["highlevel"] * 100 # Calculate statistics value start_date = df.index[0] end_date = df.index[-1] total_days = len(df) profit_days = len(df[df["net_pnl"] > 0]) loss_days = len(df[df["net_pnl"] < 0]) end_balance = df["balance"].iloc[-1] max_drawdown = df["drawdown"].min() max_ddpercent = df["ddpercent"].min() max_drawdown_end = df["drawdown"].idxmin() if isinstance(max_drawdown_end, date): max_drawdown_start = df["balance"][:max_drawdown_end].idxmax() max_drawdown_duration = (max_drawdown_end - max_drawdown_start).days else: max_drawdown_duration = 0 total_net_pnl = df["net_pnl"].sum() daily_net_pnl = total_net_pnl / total_days win = df[df["net_pnl"] > 0] win_amount = win["net_pnl"].sum() win_pnl_medio = win["net_pnl"].mean() # win_duration_medio = win["duration"].mean().total_seconds()/3600 win_count = win["trade_count"].sum() pnl_medio = df["net_pnl"].mean() # duration_medio = df["duration"].mean().total_seconds()/3600 loss = df[df["net_pnl"] < 0] loss_amount = loss["net_pnl"].sum() loss_pnl_medio = loss["net_pnl"].mean() # loss_duration_medio = loss["duration"].mean().total_seconds()/3600 total_commission = df["commission"].sum() daily_commission = total_commission / total_days total_slippage = df["slippage"].sum() daily_slippage = total_slippage / total_days total_turnover = df["turnover"].sum() daily_turnover = total_turnover / total_days total_trade_count = df["trade_count"].sum() win_ratio = (win_count / total_trade_count) * 100 win_loss_pnl_ratio = -win_pnl_medio / loss_pnl_medio daily_trade_count = total_trade_count / total_days total_return = (end_balance / self.capital - 1) * 100 annual_return = total_return / total_days * 240 daily_return = df["return"].mean() * 100 return_std = df["return"].std() * 100 if return_std: sharpe_ratio = daily_return / return_std * np.sqrt(240) else: sharpe_ratio = 0 return_drawdown_ratio = -total_return / max_ddpercent #calmar_ratio:年化收益率与历史最大回撤率之间的比率 calmar_ratio = annual_return / abs(max_ddpercent) #sortino_info sortino_info = sortino_ratio(df['return']) omega_info = omega_ratio(df['return']) #年化波动率 annual_volatility_info = annual_volatility(df['return']) #年化复合增长率 cagr_info = cagr(df['return']) #年化下行风险率 annual_downside_risk = downside_risk(df['return']) """CVaR即条件风险价值,其含义为在投资组合的损失超过某个给定VaR值的条件下,该投资组合的平均损失值。""" c_var = conditional_value_at_risk(df['return']) """风险价值(VaR)是对投资损失风险的一种度量。它估计在正常的市场条件下,在设定的时间段(例如一天)中, 一组投资可能(以给定的概率)损失多少。金融业中的公司和监管机构通常使用VaR来衡量弥补可能损失所需的资产数量""" var_info = value_at_risk(df['return']) #收益稳定率 stability_return = stability_of_timeseries(df['return']) #尾部比率0.25 == 1/4,收益1,风险4 tail_ratio_info = tail_ratio(df['return']) # Output if output: self.output("-" * 30) self.output(f"首个交易日:\t{start_date}") self.output(f"最后交易日:\t{end_date}") self.output(f"总交易日:\t{total_days}") self.output(f"盈利交易日:\t{profit_days}") self.output(f"亏损交易日:\t{loss_days}") self.output(f"起始资金:\t{self.capital:,.2f}") self.output(f"结束资金:\t{end_balance:,.2f}") self.output(f"总收益率:\t{total_return:,.2f}%") self.output(f"年化收益:\t{annual_return:,.2f}%") self.output(f"最大回撤: \t{max_drawdown:,.2f}") self.output(f"百分比最大回撤: {max_ddpercent:,.2f}%") self.output(f"最长回撤天数: \t{max_drawdown_duration}") self.output(f"总盈亏:\t{total_net_pnl:,.2f}") self.output(f"总手续费:\t{total_commission:,.2f}") self.output(f"总滑点:\t{total_slippage:,.2f}") self.output(f"总成交金额:\t{total_turnover:,.2f}") self.output(f"总成交笔数:\t{total_trade_count}") self.output(f"日均盈亏:\t{daily_net_pnl:,.2f}") self.output(f"日均手续费:\t{daily_commission:,.2f}") self.output(f"日均滑点:\t{daily_slippage:,.2f}") self.output(f"日均成交金额:\t{daily_turnover:,.2f}") self.output(f"日均成交笔数:\t{daily_trade_count}") self.output(f"日均收益率:\t{daily_return:,.2f}%") self.output(f"收益标准差:\t{return_std:,.2f}%") self.output(f"胜率:\t{win_ratio:,.2f}") self.output(f"盈亏比:\t\t{win_loss_pnl_ratio:,.2f}") self.output(f"平均每笔盈亏:\t{pnl_medio:,.2f}") self.output(f"calmar_ratio:\t{calmar_ratio:,.3f}") # self.output(f"平均持仓小时:\t{duration_medio:,.2f}") self.output(f"Sharpe Ratio:\t{sharpe_ratio:,.2f}") self.output(f"sortino Ratio:\t{sortino_info:,.3f}") self.output(f"收益回撤比:\t{return_drawdown_ratio:,.2f}") statistics = { "start_date": start_date, "end_date": end_date, "total_days": total_days, "profit_days": profit_days, "loss_days": loss_days, "capital": self.capital, "end_balance": end_balance, "max_drawdown": max_drawdown, "max_ddpercent": max_ddpercent, "max_drawdown_end": max_drawdown_end, "max_drawdown_duration": max_drawdown_duration, "total_net_pnl": total_net_pnl, "daily_net_pnl": daily_net_pnl, "total_commission": total_commission, "daily_commission": daily_commission, "total_slippage": total_slippage, "daily_slippage": daily_slippage, "total_turnover": total_turnover, "daily_turnover": daily_turnover, "total_trade_count": total_trade_count, "daily_trade_count": daily_trade_count, "total_return": total_return, "annual_return": annual_return, "daily_return": daily_return, "return_std": return_std, "sharpe_ratio": sharpe_ratio, 'sortino_info': sortino_info, "win_ratio": win_ratio, "return_drawdown_ratio": return_drawdown_ratio, "tail_ratio_info": tail_ratio_info, "stability_return": stability_return, "win_loss_pnl_ratio": win_loss_pnl_ratio, "pnl_medio": pnl_medio, "calmar_ratio": calmar_ratio } # Filter potential error infinite value for key, value in statistics.items(): if value in (np.inf, -np.inf): value = 0 statistics[key] = np.nan_to_num(value) self.output("策略统计指标计算完成") return statistics
def runstrategy(ticker_list,bench_ticker): args = parse_args() print(args) # Create a cerebro cerebro = bt.Cerebro() # Get the dates from the args fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d') todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d') # bench = bt.feeds.YahooFinanceData( # dataname=bench_ticker, # fromdate=fromdate, # todate=todate, # buffered=True,plot = False # ) bench = bt.feeds.GenericCSVData( dataname='/Users/joan/PycharmProjects/CSV_DB/IB/' + bench_ticker + '.csv', fromdate=fromdate, todate=todate, nullvalue=0.0, dtformat=('%Y%m%d'), datetime=1, open=2, high=3, low=4, close=5, volume=6, reverse=False, plot=False) cerebro.adddata(bench, name=bench_ticker) for i in ticker_list: print('Loading data: '+ i) # data = bt.feeds.YahooFinanceData( # dataname=i, # fromdate=fromdate, # todate=todate, # adjclose=True, # buffered=True, plot = False # ) data = bt.feeds.GenericCSVData( dataname='/Users/joan/PycharmProjects/CSV_DB/IB/'+i+'.csv', fromdate=fromdate, todate=todate, nullvalue=0.0, dtformat=('%Y%m%d'), datetime=1, open=2, high=3, low=4, close=5, volume=6, reverse=False, plot= False) cerebro.adddata(data,name = i) # Add the strategy cerebro.addstrategy(PairTradingStrategy, period=args.period, stake=args.stake) # Add the commission - only stocks like a for each operation cerebro.broker.setcash(args.cash) # Add the commission - only stocks like a for each operation # cerebro.broker.setcommission(commission=args.commperc) comminfo = FixedCommisionScheme() cerebro.broker.addcommissioninfo(comminfo) cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe_ratio') cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="ta") cerebro.addanalyzer(bt.analyzers.SQN, _name="sqn") cerebro.addanalyzer(bt.analyzers.SharpeRatio_A, _name='myysharpe', riskfreerate=args.rf_rate) cerebro.addanalyzer(bt.analyzers.PyFolio, _name='mypyf') cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Days, data=bench, _name='benchreturns') cerebro.addobserver(bt.observers.Value) cerebro.addobserver(bt.observers.Benchmark,plot = False) cerebro.addobserver(bt.observers.DrawDown) # And run it strat = cerebro.run(runonce=not args.runnext, preload=not args.nopreload, oldsync=args.oldsync ) # Plot if requested if args.plot: cerebro.plot(style='candlestick', barup='green', bardown='red',figsize=(100,100)) bench_returns = strat[0].analyzers.benchreturns.get_analysis() bench_df = pd.DataFrame.from_dict(bench_returns, orient='index', columns=['return']) return_df = pd.DataFrame.from_dict(strat[0].analyzers.mypyf.get_analysis()['returns'], orient='index', columns=['return']) # print('Sharpe Ratio(bt):', firstStrat.analyzers.myysharpe.get_analysis()['sharperatio']) # print('Sharpe Ratio:', empyrical.sharpe_ratio(return_df, risk_free=args.rf_rate / 252, period='daily')[0]) # print('Sharpe Ratio Benchmark:', empyrical.sharpe_ratio(bench_df, risk_free=args.rf_rate / 252, period='daily')[0]) # print('') # # print('Sortino Ratio:', empyrical.sortino_ratio(return_df, period='daily')[0]) # print('Sortino Ratio Benchmark:', empyrical.sortino_ratio(bench_df, period='daily')[0]) # print('') # print('VaR:', empyrical.value_at_risk(return_df) * 100, '%') # print('VaR Benchmark:', empyrical.value_at_risk(bench_df) * 100, '%') # # print('') # # print('Capture:', round(empyrical.capture(return_df, bench_df, period='daily')[0] * 100), '%') # print('') # # print('Max drawdown: ', round(empyrical.max_drawdown(return_df)[0] * 100), '%') # print('Max drawdown Benchmark: ', round(empyrical.max_drawdown(bench_df)[0] * 100), '%') # # print('') alpha, beta = empyrical.alpha_beta(return_df, bench_df, risk_free=args.rf_rate) # print('Beta: ', beta) # print('') # print('Annual return:', round(empyrical.annual_return(return_df)[0] * 100), '%') # print('Annual Vol:', round(empyrical.annual_volatility(return_df)[0] * 100), '%') # print('') # print('Annual return Benchmark:', round(empyrical.annual_return(bench_df)[0] * 100), '%') # print('Annual Vol Benchmark:', round(empyrical.annual_volatility(bench_df)[0] * 100), '%') # print('') dic = {'SQN': printSQN(strat[0].analyzers.sqn.get_analysis()), 'sharpe': empyrical.sharpe_ratio(return_df, risk_free=args.rf_rate / 252, period='daily')[0], 'sharpe_bm': empyrical.sharpe_ratio(bench_df, risk_free=args.rf_rate / 252, period='daily')[0], 'sortino': empyrical.sortino_ratio(bench_df, period='daily')[0], 'sortino_bm': empyrical.sortino_ratio(bench_df, period='daily')[0], 'VaR': empyrical.value_at_risk(return_df) * 100, 'VaR_bm': empyrical.value_at_risk(bench_df) * 100, 'capture': round(empyrical.capture(return_df, bench_df, period='daily')[0] * 100), 'max_dd': round(empyrical.max_drawdown(return_df)[0] * 100), 'max_dd_bm':round(empyrical.max_drawdown(bench_df)[0] * 100), 'beta': beta, 'return_annual':round(empyrical.annual_return(return_df)[0] * 100,2), 'return_annual_bm':round(empyrical.annual_volatility(return_df)[0] * 100,2), 'vol_annual':round(empyrical.annual_return(bench_df)[0] * 100,2), 'vol_annual_bm':round(empyrical.annual_volatility(bench_df)[0] * 100,2)} df = pd.DataFrame(dic,index = [0]) print(df) def calc_stats(df): df['perc_ret'] = (1 + df['return']).cumprod() - 1 # print(df.tail()) return df s = return_df.rolling(30).std() b = bench_df.rolling(30).std() # Get final portfolio Value portvalue = cerebro.broker.getvalue() # Print out the final result print('Final Portfolio Value: ${}'.format(round(portvalue)), 'PnL: ${}'.format(round(portvalue - args.cash)), 'PnL: {}%'.format(((portvalue / args.cash) - 1) * 100)) # Finally plot the end results if args.plot: fig, axs = plt.subplots(2, sharex=True) fig.autofmt_xdate() axs[1].plot(s) axs[1].plot(b) axs[1].set_title('Drawdown') axs[1].legend(['Fund', 'Benchmark']) axs[0].set_title('Returns') axs[0].plot(calc_stats(return_df)['perc_ret']) axs[0].plot(calc_stats(bench_df)['perc_ret']) axs[0].legend(['Fund', 'Benchmark']) plt.show()
def rovar(excess_returns_series): return excess_returns_series.mean() / np.abs(ep.value_at_risk(excess_returns_series))
def value_at_risk(portfolio_daily_returns, probability=0.05): return ep.value_at_risk(portfolio_daily_returns, probability)
firstStrat.analyzers.mypyf.get_analysis()['returns'], orient='index', columns=['return']) # print('Sharpe Ratio(bt):', firstStrat.analyzers.myysharpe.get_analysis()['sharperatio']) print('Sharpe Ratio:', empyrical.sharpe_ratio(return_df, risk_free=rf / 252, period='daily')[0]) print('Sharpe Ratio Benchmark:', empyrical.sharpe_ratio(bench_df, risk_free=rf / 252, period='daily')[0]) print('') print('Sortino Ratio:', empyrical.sortino_ratio(return_df, period='daily')[0]) print('Sortino Ratio Benchmark:', empyrical.sortino_ratio(bench_df, period='daily')[0]) print('') print('VaR:', empyrical.value_at_risk(return_df) * 100, '%') print('VaR Benchmark:', empyrical.value_at_risk(bench_df) * 100, '%') print('') print('Capture:', round(empyrical.capture(return_df, bench_df, period='daily')[0] * 100), '%') print('') print('Max drawdown: ', round(empyrical.max_drawdown(return_df)[0] * 100), '%') print('Max drawdown Benchmark: ', round(empyrical.max_drawdown(bench_df)[0] * 100), '%') print('') alpha, beta = empyrical.alpha_beta(return_df, bench_df, risk_free=rf)