def test_calmar_ratio(self): res_a = empyrical.calmar_ratio(ret['a']) res_b = empyrical.calmar_ratio(ret['b']) res_c = empyrical.calmar_ratio(ret['c']) assert isclose(ret['a'].vbt.returns.calmar_ratio(), res_a) pd.testing.assert_series_equal( ret.vbt.returns.calmar_ratio(), pd.Series([res_a, res_b, res_c], index=ret.columns))
def test_calmar_ratio(self): res_a = empyrical.calmar_ratio(ret['a']) res_b = empyrical.calmar_ratio(ret['b']) res_c = empyrical.calmar_ratio(ret['c']) assert isclose(ret['a'].vbt.returns.calmar_ratio(), res_a) pd.testing.assert_series_equal( ret.vbt.returns.calmar_ratio(), pd.Series([res_a, res_b, res_c], index=ret.columns).rename('calmar_ratio')) pd.testing.assert_series_equal( ret.vbt.returns.rolling_calmar_ratio(ret.shape[0], minp=1).iloc[-1], pd.Series([res_a, res_b, res_c], index=ret.columns).rename(ret.index[-1]))
def _get_reward(self) -> float: """ This method computes the reward from each action, by looking at the annualized ratio, provided in the reward_function :return: annualized value of the selected reward ratio """ lookback = min(self.current_step, self._returns_lookback) returns = np.diff(self.portfolio[-lookback:]) if np.count_nonzero(returns) < 1: return 0 if np.count_nonzero(returns) < 1: return 0 if self._reward_function == 'sortino': reward = sortino_ratio(returns, annualization=365 * 24) elif self._reward_function == 'calmar': reward = calmar_ratio(returns, annualization=365 * 24) elif self._reward_function == 'omega': reward = omega_ratio(returns, annualization=365 * 24) else: reward = returns[-1] return reward if np.isfinite(reward) else 0
def get_perf_att(series, bnchmark, rf=0.03 / 12, freq='monthly'): """F: that provides performance statistic of the returns params ------- series: daily or monthly returns returns: dataframe of Strategy name and statistics""" port_mean, port_std, port_sr = (get_stats(series, dtime=freq)) perf = pd.Series( { 'Annualized_Mean': '{:,.2f}'.format(round(port_mean, 3)), 'Annualized_Volatility': round(port_std, 3), 'Sharpe Ratio': round(port_sr, 3), 'Calmar Ratio': round(empyrical.calmar_ratio(series, period=freq), 3), 'Alpha': round(empyrical.alpha(series, bnchmark, risk_free=rf, period=freq), 3), 'Beta': round(empyrical.beta(series, bnchmark), 3), 'Max Drawdown': '{:,.2%}'.format(drawdown(series, ret_='nottext')), 'Sortino Ratio': round( empyrical.sortino_ratio( series, required_return=rf, period=freq), 3), }, ) perf.name = series.name return perf.to_frame()
def evaluation(self): ap.sound(f'entry: create_df') mdd = empyrical.max_drawdown(self.df.eac_stgy_rt) stgy_ret_an = empyrical.annual_return(self.df.eac_stgy_rt, annualization=self.cls.annualization) bcmk_ret_an = empyrical.annual_return(self.df.eac_bcmk_rt, annualization=self.cls.annualization) stgy_vlt_an = empyrical.annual_volatility(self.df.eac_stgy_rt, annualization=self.cls.annualization) bcmk_vlt_an = empyrical.annual_volatility(self.df.eac_bcmk_rt, annualization=self.cls.annualization) calmar = empyrical.calmar_ratio(self.df.eac_stgy_rt, annualization=self.cls.annualization) omega = empyrical.omega_ratio(self.df.eac_stgy_rt, risk_free=self.cls.rf, annualization=self.cls.annualization) sharpe = qp.sharpe_ratio(stgy_ret_an, self.df.cum_stgy_rt, self.cls.rf) sortino = empyrical.sortino_ratio(self.df.eac_stgy_rt, annualization=self.cls.annualization) dsrk = empyrical.downside_risk(self.df.eac_stgy_rt, annualization=self.cls.annualization) information = empyrical.information_ratio(self.df.eac_stgy_rt, factor_returns=self.df.eac_bcmk_rt) beta = empyrical.beta(self.df.eac_stgy_rt, factor_returns=self.df.eac_bcmk_rt, risk_free=self.cls.rf) tail_rt = empyrical.tail_ratio(self.df.eac_stgy_rt) alpha = qp.alpha_ratio(stgy_ret_an, bcmk_ret_an, self.cls.rf, beta) stgy_ttrt_rt = (self.cls.yd.ttas[-1] - self.cls.yd.ttas[0]) / self.cls.yd.ttas[0] bcmk_ttrt_rt = (self.cls.pc.close[-1] - self.cls.pc.close[0]) / self.cls.pc.close[0] car_rt = stgy_ttrt_rt - bcmk_ttrt_rt car_rt_an = stgy_ret_an - bcmk_ret_an self.cls.df_output = pd.DataFrame( {'sgty_ttrt_rt': [stgy_ttrt_rt], 'bcmk_ttrt_rt': [bcmk_ttrt_rt], 'car_rt': [car_rt], 'stgy_ret_an': [stgy_ret_an], 'bcmk_ret_an': [bcmk_ret_an], 'car_rt_an': [car_rt_an], 'stgy_vlt_an': [stgy_vlt_an], 'bcmk_vlt_an': [bcmk_vlt_an], 'mdd': [mdd], 'sharpe': [sharpe], 'alpha': [alpha], 'beta': [beta], 'information': [information], 'tail_rt': [tail_rt], 'calmar': [calmar], 'omega': [omega], 'sortino': [sortino], 'dsrk': [dsrk]}) print(f'feedback: \n{self.cls.df_output.T}')
def calmar_ratio(returns, period=DAILY): """ Determines the Calmar ratio, or drawdown ratio, of a strategy. Parameters ---------- returns : pd.Series Daily returns of the strategy, noncumulative. - See full explanation in :func:`~pyfolio.timeseries.cum_returns`. period : str, optional Defines the periodicity of the 'returns' data for purposes of annualizing. Can be 'monthly', 'weekly', or 'daily'. - Defaults to 'daily'. Returns ------- float Calmar ratio (drawdown ratio) as float. Returns np.nan if there is no calmar ratio. Note ----- See https://en.wikipedia.org/wiki/Calmar_ratio for more details. """ return empyrical.calmar_ratio(returns, period=period)
def calmar_ratio(returns, period=DAILY): """ Determines the Calmar ratio, or drawdown ratio, of a strategy. Parameters ---------- returns : pd.Series Daily returns of the strategy, noncumulative. - See full explanation in :func:`~pyfolio.timeseries.cum_returns`. period : str, optional Defines the periodicity of the 'returns' data for purposes of annualizing. Can be 'monthly', 'weekly', or 'daily'. - Defaults to 'daily'. Returns ------- float Calmar ratio (drawdown ratio) as float. Returns np.nan if there is no calmar ratio. Note ----- See https://en.wikipedia.org/wiki/Calmar_ratio for more details. """ return ep.calmar_ratio(returns, period=period)
def test_calmar(self, returns, period, expected): assert_almost_equal( empyrical.calmar_ratio( returns, period=period ), expected, DECIMAL_PLACES)
def calmar_ratio(daily_returns, period="daily"): """Calmar Ratio""" try: logger.info('Calculating Calmar Ratio...') calmar = empyrical.calmar_ratio(daily_returns, period=period) return calmar except Exception as exception: logger.error('Oops! An Error Occurred ⚠️') raise exception
def plot(self): # show a plot of portfolio vs mean market performance df_info = pd.DataFrame(self.infos) df_info.set_index('current step', inplace=True) # df_info.set_index('date', inplace=True) rn = np.asarray(df_info['portfolio return']) try: spf = df_info['portfolio value'].iloc[1] # Start portfolio value epf = df_info['portfolio value'].iloc[-1] # End portfolio value pr = (epf - spf) / spf except: pr = 0 try: sr = sharpe_ratio(rn) except: sr = 0 try: sor = sortino_ratio(rn) except: sor = 0 try: mdd = max_drawdown(rn) except: mdd = 0 try: cr = calmar_ratio(rn) except: cr = 0 try: om = omega_ratio(rn) except: om = 0 try: dr = downside_risk(rn) except: dr = 0 print("First portfolio value: ", np.round(df_info['portfolio value'].iloc[1])) print("Last portfolio value: ", np.round(df_info['portfolio value'].iloc[-1])) title = self.strategy_name + ': ' + 'profit={: 2.2%} sharpe={: 2.2f} sortino={: 2.2f} max drawdown={: 2.2%} calmar={: 2.2f} omega={: 2.2f} downside risk={: 2.2f}'.format( pr, sr, sor, mdd, cr, om, dr) # df_info[['market value', 'portfolio value']].plot(title=title, fig=plt.gcf(), figsize=(15,10), rot=30) df_info[['portfolio value']].plot(title=title, fig=plt.gcf(), figsize=(15, 10), rot=30)
def _get_reward(self, current_prices, next_prices): if self.compute_reward == compute_reward.profit: returns_rate = next_prices / current_prices # pip_value = self._calculate_pip_value_in_account_currency(account_currency.USD, next_prices) # returns_rate = np.multiply(returns_rate, pip_value) log_returns = np.log(returns_rate) last_weight = self.current_weights securities_value = self.current_portfolio_values[:-1] * returns_rate self.current_portfolio_values[:-1] = securities_value self.current_weights = self.current_portfolio_values / np.sum( self.current_portfolio_values) reward = last_weight[:-1] * log_returns elif self.compute_reward == compute_reward.sharpe: try: sr = sharpe_ratio(np.asarray(self.returns)) except: sr = 0 reward = sr elif self.compute_reward == compute_reward.sortino: try: sr = sortino_ratio(np.asarray(self.returns)) except: sr = 0 reward = sr elif self.compute_reward == compute_reward.max_drawdown: try: mdd = max_drawdown(np.asarray(self.returns)) except: mdd = 0 reward = mdd elif self.compute_reward == compute_reward.calmar: try: cr = calmar_ratio(np.asarray(self.returns)) except: cr = 0 reward = cr elif self.compute_reward == compute_reward.omega: try: om = omega_ratio(np.asarray(self.returns)) except: om = 0 reward = om elif self.compute_reward == compute_reward.downside_risk: try: dr = downside_risk(np.asarray(self.returns)) except: dr = 0 reward = dr try: reward = reward.mean() except: reward = reward return reward
def _reward(self): length = min(self.current_step, self.reward_len) returns = np.diff(self.net_worths)[-length:] if self.reward_func == 'sortino': reward = sortino_ratio(returns) elif self.reward_func == 'calmar': reward = calmar_ratio(returns) elif self.reward_func == 'omega': reward = omega_ratio(returns) else reward = np.mean(returns) return reward if abs(reward) != inf and not np.isnan(reward) else 0
def get_perf_att(series, bnchmark, rf=0.03 / 12, freq='monthly'): """F: that provides performance statistic of the returns params ------- series: daily or monthly returns returns: dataframe of Strategy name and statistics""" port_mean, port_std, port_sr = (get_stats(series, dtime=freq)) regs = sm.OLS(series, sm.add_constant(bnchmark)).fit() alpha, beta = regs.params t_alpha, t_beta = regs.tvalues perf = pd.Series( { 'Annualized_Mean': '{:,.5f}'.format(round(port_mean, 5)), 'Annualized_Volatility': round(port_std, 5), 'Sharpe Ratio': round(port_sr, 3), 'Calmar Ratio': round(empyrical.calmar_ratio(series, period=freq), 3), # 'Alpha' : round(empyrical.alpha(series, # bnchmark, # risk_free = rf, # period = freq), 'Alpha': round(alpha, 3), # 'Beta': round(empyrical.beta(series, # bnchmark), 'Beta': round(beta, 3), 'T Value (Alpha)': round(t_alpha, 3), 'T Value (Beta)': round(t_beta, 3), 'Max Drawdown': '{:,.2%}'.format(drawdown(series, ret_='nottext')), 'Sortino Ratio': round( empyrical.sortino_ratio( series, required_return=rf, period=freq), 3), }, ) perf.name = series.name return perf.to_frame()
def _reward(self): length = min(self.current_step, self.forecast_len) returns = np.diff(self.net_worths[-length:]) if np.count_nonzero(returns) < 1: return 0 if self.reward_func == 'sortino': reward = sortino_ratio(returns, annualization=365 * 24) elif self.reward_func == 'calmar': reward = calmar_ratio(returns, annualization=365 * 24) elif self.reward_func == 'omega': reward = omega_ratio(returns, annualization=365 * 24) else: reward = returns[-1] return reward if np.isfinite(reward) else 0
def _reward(self): length = min(self.current_step, self.window_size) returns = np.diff(self.net_worths[-length:]) if np.count_nonzero(returns) < 1: return 0 if self.reward_func == 'sortino': reward = sortino_ratio(returns, annualization=self.annualization) elif self.reward_func == 'calmar': reward = calmar_ratio(returns, annualization=self.annualization) elif self.reward_func == 'omega': reward = omega_ratio(returns, annualization=self.annualization) elif self.reward_func == "logret": reward = np.log(returns[-1]) else: reward = returns[-1] return reward if np.isfinite(reward) else 0
def get_statistics(ticker, end_date, k): """ 得到一只基金在end_date前推k个交易日的 1. 收益率 2. 波动率 3. 最大回撤 4. Sharpe 5. Calmar """ fname = '%s/history/%s.xlsx'%(const.DATA_DIR, ticker) df = pd.read_excel(fname, index_col=0) df = df[df.index <= end_date] if k > df.shape[0]: return 0, 0, 0, 0, 0 df = df[df.index >= df.index[-k]] df.loc[:, 'return'] = df.loc[:, 'nav_adj'].pct_change() returns = (df.ix[-1, 'nav_adj'] - df.ix[0, 'nav_adj']) / df.ix[0, 'nav_adj'] volatility = empyrical.annual_volatility(df['return']) max_drawdown = empyrical.max_drawdown(df['return']) sharpe = empyrical.sharpe_ratio(df['return']) calmar = empyrical.calmar_ratio(df['return']) return returns, volatility, max_drawdown, sharpe, calmar
def _calmar(self): self.__calmar = ey.calmar_ratio(returns = self.__returns)
def test(): # 构造测试数据 returns = pd.Series( index = pd.date_range("2017-03-10", "2017-03-19"), data = (-0.012143, 0.045350, 0.030957, 0.004902, 0.002341, -0.02103, 0.00148, 0.004820, -0.00023, 0.01201)) print(returns) benchmark_returns = pd.Series( index = pd.date_range("2017-03-10", "2017-03-19"), data = ( -0.031940, 0.025350, -0.020957, -0.000902, 0.007341, -0.01103, 0.00248, 0.008820, -0.00123, 0.01091)) print(benchmark_returns) # 计算累积收益率 creturns = ey.cum_returns(returns) print("累积收益率\n", creturns) risk = riskAnalyzer(returns, benchmark_returns, riskFreeRate = 0.01) results = risk.run() print(results) # 直接调用empyrical试试 alpha = ey.alpha(returns = returns, factor_returns = benchmark_returns, risk_free = 0.01) calmar = ey.calmar_ratio(returns) print(alpha, calmar) # 自己计算阿尔法值 annual_return = ey.annual_return(returns) annual_bench = ey.annual_return(benchmark_returns) print(annual_return, annual_bench) alpha2 = (annual_return - 0.01) - results["贝塔"]*(annual_bench - 0.01) print(alpha2) # 自己计算阿尔法贝塔 def get_return(code, startdate, endate): df = ts.get_k_data(code, ktype = "D", autype = "qfq", start = startdate, end = endate) p1 = np.array(df.close[1:]) p0 = np.array(df.close[:-1]) logret = np.log(p1/p0) rate = pd.DataFrame() rate[code] = logret rate.index = df["date"][1:] return rate def alpha_beta(code, startdate, endate): mkt_ret = get_return("sh", startdate, endate) stock_ret = get_return(code, startdate, endate) df = pd.merge(mkt_ret, stock_ret, left_index = True, right_index = True) x = df.iloc[:, 0] y = df.iloc[:, 1] beta, alpha, r_value, p_value, std_err = stats.linregress(x, y) return (alpha, beta) def stocks_alpha_beta(stocks, startdate, endate): df = pd.DataFrame() alpha = [] beta = [] for code in stocks.values(): a, b = alpha_beta(code, startdate, endate) alpha.append(float("%.4f"%a)) beta.append(float("%.4f"%b)) df["alpha"] = alpha df["beta"] = beta df.index = stocks.keys() return df startdate = "2017-01-01" endate = "2018-11-09" stocks={'中国平安':'601318','格力电器':'000651','招商银行':'600036','恒生电子':'600570','中信证券':'600030','贵州茅台':'600519'} results = stocks_alpha_beta(stocks, startdate, endate) print("自己计算结果") print(results) # 用empyrical计算 def stocks_alpha_beta2(stocks, startdate, endate): df = pd.DataFrame() alpha = [] beta = [] for code in stocks.values(): a, b = empyrical_alpha_beta(code, startdate, endate) alpha.append(float("%.4f"%a)) beta.append(float("%.4f"%b)) df["alpha"] = alpha df["beta"] = beta df.index = stocks.keys() return df def empyrical_alpha_beta(code, startdate, endate): mkt_ret = get_return("sh", startdate, endate) stock_ret = get_return(code, startdate, endate) alpha, beta = ey.alpha_beta(returns = stock_ret, factor_returns = mkt_ret, annualization = 1) return (alpha, beta) results2 = stocks_alpha_beta2(stocks, startdate, endate) print("empyrical计算结果") print(results2) print(results2["alpha"]/results["alpha"])
def create_summary_tearsheet(self, performance, agg_performance=None): """ Create a tear sheet of summary performance stats in a table. Parameters ---------- performance : DailyPerformance, required a DailyPerformance instance agg_performance : AggregateDailyPerformance, optional an AggregateDailyPerformance instance. Constructed from performance if not provided. Returns ------- None Examples -------- >>> from moonchart import DailyPerformance, Tearsheet >>> perf = DailyPerformance.from_moonshot_csv("backtest_results.csv") >>> t = Tearsheet() >>> t.create_summary_tearsheet(perf) """ if agg_performance is None: agg_performance = AggregateDailyPerformance(performance) stats = [] if agg_performance.pnl is not None: stats.append(["PNL", round(agg_performance.pnl.sum(), 2)]) if agg_performance.commission_amounts is not None: stats.append([ "Commissions", round(agg_performance.commission_amounts.sum(), 2) ]) stats.append([ "Start Date", agg_performance.returns.index.min().date().isoformat() ]) stats.append([ "End Date", agg_performance.returns.index.max().date().isoformat() ]) stats.append([ 'Total Months', round((agg_performance.returns.index.max() - agg_performance.returns.index.min()) / pd.Timedelta(1, 'M')) ]) stats.append(["", " Risk and Returns"]) stats.append( ["CAGR", "{0}%".format(round(agg_performance.cagr * 100, 1))]) stats.append(["Sharpe Ratio", '%.2f' % agg_performance.sharpe]) stats.append([ "Max Drawdown", "{0}%".format(round(agg_performance.max_drawdown * 100, 1)) ]) stats.append([ "Cumulative Return", "{0}%".format( round(ep.cum_returns_final(agg_performance.returns) * 100, 1)) ]) stats.append([ "Annual Volatility", "{0}%".format( round(ep.annual_volatility(agg_performance.returns) * 100, 1)) ]) stats.append([ "Sortino Ratio", '%.2f' % ep.sortino_ratio(agg_performance.returns) ]) stats.append([ "Calmar Ratio", '%.2f' % ep.calmar_ratio(agg_performance.returns) ]) stats.append( ["Skew", '%.2f' % scipy.stats.skew(agg_performance.returns)]) stats.append([ "Kurtosis", '%.2f' % scipy.stats.kurtosis(agg_performance.returns) ]) if any([ field is not None for field in (agg_performance.abs_exposures, agg_performance.net_exposures, agg_performance.total_holdings, agg_performance.turnover) ]): stats.append(["", " Positions and Exposure"]) if agg_performance.abs_exposures is not None: avg_abs_exposures = agg_performance.abs_exposures.mean() stats.append([ "Absolute Exposure (percentage of capital)", "{0}%".format(round(avg_abs_exposures * 100, 1)) ]) if agg_performance.net_exposures is not None: avg_net_exposures = agg_performance.net_exposures.mean() stats.append([ "Net Exposure (percentage of capital)", "{0}%".format(round(avg_net_exposures * 100, 1)) ]) if agg_performance.total_holdings is not None: avg_daily_holdings = agg_performance.total_holdings.mean() stats.append(["Average Daily Holdings", round(avg_daily_holdings)]) if agg_performance.turnover is not None: avg_daily_turnover = agg_performance.turnover.mean() stats.append([ "Average Daily Turnover (percentage of capital)", "{0}%".format(round(avg_daily_turnover * 100, 1)) ]) if agg_performance.abs_exposures is not None: norm_cagr = agg_performance.cagr / avg_abs_exposures stats.append([ "Normalized CAGR (CAGR/Absolute Exposure)", "{0}%".format(round(norm_cagr * 100, 1)) ]) with sns.axes_style("white", {'axes.linewidth': 0}): fig = plt.figure("Performance Summary", figsize=(6, 6)) axis = fig.add_subplot(111) axis.get_xaxis().set_visible(False) axis.get_yaxis().set_visible(False) headings, values = zip(*stats) table = axis.table(cellText=[[v] for v in values], rowLabels=headings, colLabels=["Performance Summary"], loc="center") for (row, col), cell in table.get_celld().items(): txt = cell.get_text().get_text() if row == 0 or txt.startswith(" "): cell.set_text_props(fontproperties=FontProperties( weight='bold')) table.scale(1, 2) table.set_fontsize("large") fig.tight_layout()
# convert to daily return for different asset in t ind_return = pd.concat([ind_return, df[i + '-ind_return']], axis=1) #%% Portfolio Average # Strategy return in daily ind_return['port_avg'] = ind_return.mean(skipna=1, axis=1) # convert to monthly basis strategy_month_rtns = ind_return['port_avg'].resample('BM').last().ffill() strategy_cumm_rtns['cummulative'] = (1 + ind_return['port_avg']).cumprod() # convert to monthly cum return strategy_month = strategy_cumm_rtns['cummulative'].resample('BM').last().ffill() #%% Print Results print("Annualized Sharpe Ratio = ", empyrical.sharpe_ratio(ind_return['port_avg'], period='daily')) print("Annualized Mean Returns = ", empyrical.annual_return(ind_return['port_avg'], period='daily')) print("Annualized Standard Deviations = ", empyrical.annual_volatility(ind_return['port_avg'], period='daily')) print("Max Drawdown (MDD) = ", empyrical.max_drawdown(ind_return['port_avg'])) print("Sortino ratio = ", empyrical.sortino_ratio(ind_return['port_avg'], period='daily')) print("Calmar ratio = ", empyrical.calmar_ratio(ind_return['port_avg'], period='daily')) #%% Visualization #print(empyrical.sharpe_ratio(strategy_month_rtns, period='monthly')) a = empyrical.cum_returns(ind_return['port_avg']) #b = strategy_month plt.plot(a, color = 'red', label = 'Raw Portfolio') plt.title('Cumulative return in daily basis') plt.xlabel('Time') plt.ylabel('Cumulative return') plt.legend() plt.show()
def trades(trades_list: list, daily_balance: list): starting_balance = 0 current_balance = 0 for e in store.exchanges.storage: starting_balance += store.exchanges.storage[e].starting_assets[ jh.app_currency()] current_balance += store.exchanges.storage[e].assets[jh.app_currency()] starting_balance = round(starting_balance, 2) current_balance = round(current_balance, 2) if len(trades_list) == 0: return None df = pd.DataFrame.from_records([t.to_dict() for t in trades_list]) total_completed = len(df) winning_trades = df.loc[df['PNL'] > 0] total_winning_trades = len(winning_trades) losing_trades = df.loc[df['PNL'] < 0] total_losing_trades = len(losing_trades) losing_i = df['PNL'] < 0 losing_streaks = losing_i.ne(losing_i.shift()).cumsum() losing_streak = losing_streaks[losing_i].value_counts().max() winning_i = df['PNL'] > 0 winning_streaks = winning_i.ne(winning_i.shift()).cumsum() winning_streak = winning_streaks[winning_i].value_counts().max() largest_losing_trade = round(df['PNL'].min(), 2) largest_winning_trade = round(df['PNL'].max(), 2) win_rate = len(winning_trades) / (len(losing_trades) + len(winning_trades)) max_R = round(df['R'].max(), 2) min_R = round(df['R'].min(), 2) mean_R = round(df['R'].mean(), 2) longs_count = len(df.loc[df['type'] == 'long']) shorts_count = len(df.loc[df['type'] == 'short']) longs_percentage = longs_count / (longs_count + shorts_count) * 100 short_percentage = 100 - longs_percentage fee = df['fee'].sum() net_profit = round(df['PNL'].sum(), 2) net_profit_percentage = round((net_profit / starting_balance) * 100, 2) average_win = round(winning_trades['PNL'].mean(), 2) average_loss = round(abs(losing_trades['PNL'].mean()), 2) ratio_avg_win_loss = average_win / average_loss expectancy = (0 if np.isnan(average_win) else average_win) * win_rate - ( 0 if np.isnan(average_loss) else average_loss) * (1 - win_rate) expectancy = round(expectancy, 2) expectancy_percentage = round((expectancy / starting_balance) * 100, 2) expected_net_profit_every_100_trades = round(expectancy_percentage * 100, 2) average_holding_period = df['holding_period'].mean() average_winning_holding_period = winning_trades['holding_period'].mean() average_losing_holding_period = losing_trades['holding_period'].mean() gross_profit = round(df.loc[df['PNL'] > 0]['PNL'].sum(), 2) gross_loss = round(df.loc[df['PNL'] < 0]['PNL'].sum(), 2) daily_returns = pd.Series(daily_balance).pct_change(1).values max_drawdown = round(empyrical.max_drawdown(daily_returns) * 100, 2) annual_return = round(empyrical.annual_return(daily_returns) * 100, 2) sharpe_ratio = round(empyrical.sharpe_ratio(daily_returns), 2) calmar_ratio = round(empyrical.calmar_ratio(daily_returns), 2) sortino_ratio = round(empyrical.sortino_ratio(daily_returns), 2) omega_ratio = round(empyrical.omega_ratio(daily_returns), 2) total_open_trades = store.app.total_open_trades open_pl = store.app.total_open_pl return { 'total': np.nan if np.isnan(total_completed) else total_completed, 'total_winning_trades': np.nan if np.isnan(total_winning_trades) else total_winning_trades, 'total_losing_trades': np.nan if np.isnan(total_losing_trades) else total_losing_trades, 'starting_balance': np.nan if np.isnan(starting_balance) else starting_balance, 'finishing_balance': np.nan if np.isnan(current_balance) else current_balance, 'win_rate': np.nan if np.isnan(win_rate) else win_rate, 'max_R': np.nan if np.isnan(max_R) else max_R, 'min_R': np.nan if np.isnan(min_R) else min_R, 'mean_R': np.nan if np.isnan(mean_R) else mean_R, 'ratio_avg_win_loss': np.nan if np.isnan(ratio_avg_win_loss) else ratio_avg_win_loss, 'longs_count': np.nan if np.isnan(longs_count) else longs_count, 'longs_percentage': np.nan if np.isnan(longs_percentage) else longs_percentage, 'short_percentage': np.nan if np.isnan(short_percentage) else short_percentage, 'shorts_count': np.nan if np.isnan(shorts_count) else shorts_count, 'fee': np.nan if np.isnan(fee) else fee, 'net_profit': np.nan if np.isnan(net_profit) else net_profit, 'net_profit_percentage': np.nan if np.isnan(net_profit_percentage) else net_profit_percentage, 'average_win': np.nan if np.isnan(average_win) else average_win, 'average_loss': np.nan if np.isnan(average_loss) else average_loss, 'expectancy': np.nan if np.isnan(expectancy) else expectancy, 'expectancy_percentage': np.nan if np.isnan(expectancy_percentage) else expectancy_percentage, 'expected_net_profit_every_100_trades': np.nan if np.isnan(expected_net_profit_every_100_trades) else expected_net_profit_every_100_trades, 'average_holding_period': average_holding_period, 'average_winning_holding_period': average_winning_holding_period, 'average_losing_holding_period': average_losing_holding_period, 'gross_profit': gross_profit, 'gross_loss': gross_loss, 'max_drawdown': max_drawdown, 'annual_return': annual_return, 'sharpe_ratio': sharpe_ratio, 'calmar_ratio': calmar_ratio, 'sortino_ratio': sortino_ratio, 'omega_ratio': omega_ratio, 'total_open_trades': total_open_trades, 'open_pl': open_pl, 'winning_streak': winning_streak, 'losing_streak': losing_streak, 'largest_losing_trade': largest_losing_trade, 'largest_winning_trade': largest_winning_trade, }
max_drawdown, sharpe_ratio, sortino_ratio, calmar_ratio, omega_ratio, tail_ratio ) import pandas as pd returns = pd.Series( index=pd.date_range('2017-03-10', '2017-03-19'), data=(-0.012143, 0.045350, 0.030957, 0.004902, 0.002341, -0.02103, 0.00148, 0.004820, -0.00023, 0.01201) ) benchmark_returns = pd.Series( index=pd.date_range('2017-03-10', '2017-03-19'), data=(-0.031940, 0.025350, -0.020957, -0.000902, 0.007341, -0.01103, 0.00248, 0.008820, -0.00123, 0.01091) ) creturns = cum_returns(returns) max_drawdown(returns) annual_return(returns) annual_volatility(returns, period='daily') calmar_ratio(returns) omega_ratio(returns=returns, risk_free=0.01) sharpe_ratio(returns=returns, risk_free=0.01) sortino_ratio(returns=returns) downside_risk(returns=returns) alpha(returns=returns, factor_returns=benchmark_returns, risk_free=0.01) beta(returns=returns, factor_returns=benchmark_returns, risk_free=0.01) tail_ratio(returns=returns)
target_vol = 0.15 for i in ast: # 进行水平方向的合并 df = pd.concat([ast[i], predicted_X_t[i + "-X_t"]], axis=1) day_vol = df[i].ewm(ignore_na=False, adjust=True, span=60, min_periods=0).std(bias=False) # daily return based on equation (1) for individual asset df[i + '-ind_return'] = df[i] * df[i + "-X_t"] * target_vol / day_vol # convert to daily return for different asset in t ind_return = pd.concat([ind_return, df[i + '-ind_return']], axis=1) # daily return in portfolio ind_return['port_avg'] = ind_return.mean(skipna=1, axis=1) #%% Print Results print("Annualized Sharpe Ratio = ", empyrical.sharpe_ratio(ind_return['port_avg'], period='daily')) print("Annualized Mean Returns = ", empyrical.annual_return(ind_return['port_avg'], period='daily')) print("Annualized Standard Deviations = ", empyrical.annual_volatility(ind_return['port_avg'], period='daily')) print("Max Drawdown (MDD) = ", empyrical.max_drawdown(ind_return['port_avg'])) print("Sortino ratio = ", empyrical.sortino_ratio(ind_return['port_avg'], period='daily')) print("Calmar ratio = ", empyrical.calmar_ratio(ind_return['port_avg'], period='daily'))
def get_calmar_ratio(self, data): data = copy.deepcopy(data) calmar_ratio = empyrical.calmar_ratio(data.rets.dropna(), period='weekly') return calmar_ratio
def run_turtle(): PROPERTY = START_MONEY CASH = START_MONEY show_df = None show_df = stock_df_dict['NDX'].copy() order_df = None order_df = pd.DataFrame(columns=[ 'buy_date', 'symbol', 'buy_count', 'buy_price', 'buy_reason', 'sell_date', 'sell_price', 'sell_reason', 'profit', 'cash', 'property' ]) count_day = 0 yesterday = None for today in pd.period_range(start=start_date, end=end_date, freq='D'): count_day += 1 if yesterday is None: yesterday = today continue if today not in stock_df_dict['NDX'].index: continue if IS_HAPPY_MONEY: if PROPERTY > START_MONEY * 2: global HAPPY_MONEY HAPPY_MONEY += int(START_MONEY / 2) PROPERTY -= int(START_MONEY / 2) CASH = PROPERTY # 买卖过程 sell_signal = [] buy_signal = [] for symbol in NASDAQ100[:]: # for symbol in ['TSLA']: if symbol in [ 'ALGN', 'ROST', 'ORLY', 'ESRX', 'ULTA', 'REGN', 'MNST' ]: # continue pass if symbol == 'NDX': continue if today not in stock_df_dict[ symbol].index or yesterday not in stock_df_dict[ symbol].index: continue # 突破下行趋势,清仓退出 order_arr = order_df.to_records(index=False) if len(order_arr[(order_arr.symbol == symbol) & (order_arr.sell_price == 0)]) != 0: is_sell = False for idx in order_df[(order_df['symbol'] == symbol) & (order_df['sell_price'] == 0)].index: if order_df.loc[idx, 'buy_reason'] == 'SHORT': is_sell = ( stock_df_dict[symbol].loc[today, 'open'] <= stock_df_dict[symbol].loc[today, 'ROLLING_%d_MIN' % TURTLE_SHORT_SELL_N]) if order_df.loc[idx, 'buy_reason'] == 'LONG': is_sell = ( stock_df_dict[symbol].loc[today, 'open'] <= stock_df_dict[symbol].loc[today, 'ROLLING_%d_MIN' % TURTLE_LONG_SELL_N]) if is_sell: CASH += order_df.loc[idx, 'buy_count'] * \ stock_df_dict[symbol].loc[today, 'open'] order_df.loc[idx, 'sell_date'] = today order_df.loc[idx, 'sell_price'] = stock_df_dict[symbol].loc[ today, 'open'] order_df.loc[idx, 'sell_reason'] = 'EXIT' order_df.loc[idx, 'profit'] = \ (order_df.loc[idx, 'sell_price'] - order_df.loc[idx, 'buy_price']) * order_df.loc[idx, 'buy_count'] # print(today, '退出', stock_df_dict[symbol].loc[today, 'open'], CASH) # 突破上行趋势,买入一份 order_arr = order_df.to_records(index=False) if stock_df_dict[symbol].loc[ today, 'MA30'] >= stock_df_dict[symbol].loc[today, 'MA180']: is_buy = False if stock_df_dict[symbol].loc[today, 'open'] >= stock_df_dict[ symbol].loc[today, 'ROLLING_%d_MAX' % TURTLE_LONG_BUY_N]: is_buy = True buy_reason = 'LONG' elif stock_df_dict[symbol].loc[today, 'open'] >= stock_df_dict[ symbol].loc[today, 'ROLLING_%d_MAX' % TURTLE_SHORT_BUY_N]: is_buy = True buy_reason = 'SHORT' if is_buy: buy_count = 0 if CASH >= PROPERTY / TURTLE_POS: buy_count = int( (PROPERTY / TURTLE_POS) / stock_df_dict[symbol].loc[today, 'open']) if buy_count > 0: CASH -= buy_count * \ stock_df_dict[symbol].loc[today, 'open'] # print(today, '买入', buy_count, stock_df_dict[symbol].loc[today, 'open'], CASH) order_df = order_df.append( { 'buy_date': today, 'symbol': symbol, 'buy_count': buy_count, 'buy_price': stock_df_dict[symbol].loc[today, 'open'], 'buy_reason': buy_reason, 'sell_date': pd.np.nan, 'sell_price': 0, 'profit': 0, 'cash': CASH, 'property': PROPERTY, }, ignore_index=True) # 每天盘点财产 show_df.loc[today, 'CASH_TURTLE_%d_%d_%d' % (TURTLE_POS, TURTLE_LONG_BUY_N, TURTLE_LONG_SELL_N)] = CASH PROPERTY = CASH + \ sum( [ stock_df_dict[order_df.loc[idx, 'symbol']].loc[today, 'open'] * order_df.loc[idx, 'buy_count'] for idx in order_df.loc[order_df['sell_price'] == 0].index ] ) show_df.loc[today, 'PROPERTY_TURTLE_%d_%d_%d' % (TURTLE_POS, TURTLE_LONG_BUY_N, TURTLE_LONG_SELL_N)] = PROPERTY yesterday = today # 最终结果 print('CASH', CASH) print('HAPPY_MONEY', HAPPY_MONEY) print('PROPERTY', PROPERTY) benchmark_symbol = 'NDX' s_p = stock_df_dict[benchmark_symbol][start_date:].iloc[0].open e_p = stock_df_dict[benchmark_symbol].iloc[-1].open print(benchmark_symbol, s_p, e_p, e_p / s_p) show_df = show_df[start_date:].dropna(how='any', inplace=False) show_df['strategy_pct'] = show_df['PROPERTY_TURTLE_%d_%d_%d' % (TURTLE_POS, TURTLE_LONG_BUY_N, TURTLE_LONG_SELL_N)].pct_change() # show_df['benchmark_pct'] = show_df['open'].pct_change() show_df['benchmark_pct'] = stock_df_dict[benchmark_symbol].open.pct_change( ) # print('cum_returns', emp.cum_returns(show_df.strategy_pct)) print('max_drawdown', emp.max_drawdown(show_df.strategy_pct)) print( 'MDD', MDD(show_df['PROPERTY_TURTLE_%d_%d_%d' % (TURTLE_POS, TURTLE_LONG_BUY_N, TURTLE_LONG_SELL_N)])) print('annual_return', emp.annual_return(show_df.strategy_pct)) print('annual_volatility', emp.annual_volatility(show_df.strategy_pct, period='daily')) print('calmar_ratio', emp.calmar_ratio(show_df.strategy_pct)) print('sharpe_ratio', emp.sharpe_ratio(returns=show_df.strategy_pct)) print( 'alpha', emp.alpha(returns=show_df.strategy_pct, factor_returns=show_df.benchmark_pct, risk_free=0.00)) print( 'beta', emp.beta(returns=show_df.strategy_pct, factor_returns=show_df.benchmark_pct, risk_free=0.00))
def Strategy_performance(returns: pd.DataFrame, mark_benchmark: str = 'benchmark', periods: str = 'daily') -> pd.DataFrame: ''' 风险指标计算 returns:index-date col-数据字段 mark_benchmark:用于指明基准 periods:频率 ''' df: pd.DataFrame = pd.DataFrame() df['年化收益率'] = ep.annual_return(returns, period=periods) df['累计收益'] = returns.apply(lambda x: ep.cum_returns(x).iloc[-1]) df['波动率'] = returns.apply( lambda x: ep.annual_volatility(x, period=periods)) df['夏普'] = returns.apply(ep.sharpe_ratio, period=periods) df['最大回撤'] = returns.apply(lambda x: ep.max_drawdown(x)) df['索提诺比率'] = returns.apply(lambda x: ep.sortino_ratio(x, period=periods)) df['Calmar'] = returns.apply(lambda x: ep.calmar_ratio(x, period=periods)) # 相对指标计算 if mark_benchmark in returns.columns: select_col = [col for col in returns.columns if col != mark_benchmark] df['IR'] = returns[select_col].apply( lambda x: information_ratio(x, returns[mark_benchmark])) df['Alpha'] = returns[select_col].apply( lambda x: ep.alpha(x, returns[mark_benchmark], period=periods)) df['Beta'] = returns[select_col].apply( lambda x: ep.beta(x, returns[mark_benchmark])) # 计算相对年化波动率 df['超额收益率'] = df['年化收益率'] - \ df.loc[mark_benchmark, '年化收益率'] return df.T # def show_worst_drawdown_periods(returns: pd.Series, # benchmark_code: str = "000300.SH", # top: int = 5): # """ # Prints information about the worst drawdown periods. # Prints peak dates, valley dates, recovery dates, and net # drawdowns. # Parameters # ---------- # returns : pd.Series # Daily returns of the strategy, noncumulative. # - See full explanation in tears.create_full_tear_sheet. # top : int, optional # Amount of top drawdowns periods to plot (default 5). # """ # drawdown_df = ts.gen_drawdown_table(returns, top=top) # drawdown_df.index = list(range(1, len(drawdown_df) + 1)) # phase_change = compare_phase_change(returns, benchmark_code, top) # df = pd.concat((drawdown_df, phase_change), axis=1) # # print_table( # # df.sort_values('区间最大回撤 %', ascending=False), # # name='序号', # # float_format='{0:.2f}'.format, # # ) # return df # def compare_phase_change(returns: pd.Series, # benchmark_code: str, # top: int = 5) -> pd.DataFrame: # ''' # 对比策略与基准在回撤区间内的收益 # ------ # returns:策略净值收益率 # benchmark_code:基准的代码 # ''' # beginDt = returns.index.min() # endDt = returns.index.max() # benchmark = get_wsd_data(benchmark_code, # 'pct_chg', # beginDt, # endDt, # 'priceAdj=B', # usedf=True) # benchmark = benchmark['PCT_CHG'] / 100 # df = pd.DataFrame(columns=['策略收益%', '基准收益%'], # index=list(range(1, top + 1))) # drawdowns_list = ts.get_top_drawdowns(returns, top=top) # for i, v in enumerate(drawdowns_list): # peak_date, _, recovery_date = v # if pd.isnull(recovery_date): # df.loc[i + 1, '策略收益%'] = np.nan # df.loc[i + 1, '基准收益'] = np.nan # else: # df.loc[i + 1, '策略收益%'] = ep.cum_returns( # returns.loc[peak_date:recovery_date]).iloc[-1] # df.loc[i + 1, '基准收益%'] = ep.cum_returns( # benchmark.loc[peak_date:recovery_date])[-1] # return df
def fin_funcs_port(df): """ Financial calculations taken from Quantopians Empirical Library. :param df: dataframe containing daily returns calculated for a portfolio and as well for the related accounts. :return: Dictionary of financial ratios both for percent change returns and log returns. """ returns_port = df["portfolio"] returns_acct = df["account"] risk_free_rate = 0.0 annual_return_port = ep.annual_return(returns_port, period="daily", annualization=None) annual_return_acct = ep.annual_return(returns_acct, period="daily", annualization=None) cumm_return_port = ep.cum_returns(returns_port, starting_value=0).iloc[-1] cumm_return_acct = ep.cum_returns(returns_acct, starting_value=0).iloc[-1] cagr_port = ep.cagr(returns_port, period="daily", annualization=None) cagr_acct = ep.cagr(returns_acct, period="daily", annualization=None) sharpe_port = ep.sharpe_ratio(returns_port, risk_free=risk_free_rate, period="daily", annualization=None) sharpe_acct = ep.sharpe_ratio(returns_acct, risk_free=risk_free_rate, period="daily", annualization=None) annual_volatility_port = ep.annual_volatility(returns_port, period="daily", alpha=2.0, annualization=None) annual_volatility_acct = ep.annual_volatility(returns_acct, period="daily", alpha=2.0, annualization=None) max_drawdown_port = ep.max_drawdown(returns_port) max_drawdown_acct = ep.max_drawdown(returns_acct) calmar_port = ep.calmar_ratio(returns_port, period="daily", annualization=None) calmar_acct = ep.calmar_ratio(returns_acct, period="daily", annualization=None) sortino_port = ep.sortino_ratio( returns_port, required_return=0, period="daily", annualization=None, _downside_risk=None, ) sortino_acct = ep.sortino_ratio( returns_acct, required_return=0, period="daily", annualization=None, _downside_risk=None, ) tail_ratio_port = ep.tail_ratio(returns_port) tail_ratio_acct = ep.tail_ratio(returns_acct) financials = { ("return_portfolio", "annual_return"): annual_return_port, ("return_portfolio", "cumm_return"): cumm_return_port, ("return_portfolio", "cagr"): cagr_port, ("return_portfolio", "sharpe"): sharpe_port, ("return_portfolio", "annual_volatility"): annual_volatility_port, ("return_portfolio", "max_drawdown"): max_drawdown_port, ("return_portfolio", "calmar"): calmar_port, ("return_portfolio", "sortino"): sortino_port, ("return_portfolio", "tail_ratio"): tail_ratio_port, ("return_account", "annual_return"): annual_return_acct, ("return_account", "cumm_return"): cumm_return_acct, ("return_account", "cagr"): cagr_acct, ("return_account", "sharpe"): sharpe_acct, ("return_account", "annual_volatility"): annual_volatility_acct, ("return_account", "max_drawdown"): max_drawdown_acct, ("return_account", "calmar"): calmar_acct, ("return_account", "sortino"): sortino_acct, ("return_account", "tail_ratio"): tail_ratio_acct, } return financials
span=60, min_periods=0).std(bias=False) df['return'] = AD1.iloc[7479:, 0] * y_pred_lstm * 0.15 / day_vol #%% import empyrical print("Annualized Sharpe Ratio = ", empyrical.sharpe_ratio(df['return'], period='daily')) print("Annualized Mean Returns = ", empyrical.annual_return(df['return'], period='daily')) print("Annualized Standard Deviations = ", empyrical.annual_volatility(df['return'], period='daily')) print("Max Drawdown (MDD) = ", empyrical.max_drawdown(df['return'])) print("Sortino ratio = ", empyrical.sortino_ratio(df['return'], period='daily')) print("Calmar ratio = ", empyrical.calmar_ratio(df['return'], period='daily')) #%% a = pd.DataFrame() a = pd.concat([a, TSMOM.ind_return['port_avg']], axis=1) a = a.tail(831) b = empyrical.cum_returns(a) c = empyrical.cum_returns(df['return']) plt.plot(b, color='red', label='R') plt.plot(c, color='blue', label='R') plt.title('Cumulative return in daily basis') plt.xlabel('Time') plt.ylabel('Cumulative return') plt.legend() plt.show()
def calmar_ratio(portfolio_daily_returns): return ep.calmar_ratio(portfolio_daily_returns)
def fin_funcs(df): """ Financial calculations taken from Quantopians Empirical Library. :param df: dataframe containing daily returns calculated on a percentage change and also by log scale. :return: Dictionary of financial ratios both for percent change returns and log returns. """ returns_pct = df["pct_change"] risk_free_rate = 0.0 annual_return_pct = ep.annual_return(returns_pct, period="daily", annualization=None) cumm_return_pct = ep.cum_returns(returns_pct, starting_value=0).iloc[-1] cagr_pct = ep.cagr(returns_pct, period="daily", annualization=None) sharpe_pct = ep.sharpe_ratio(returns_pct, risk_free=risk_free_rate, period="daily", annualization=None) annual_volatility_pct = ep.annual_volatility(returns_pct, period="daily", alpha=2.0, annualization=None) max_drawdown_pct = ep.max_drawdown(returns_pct) calmar_pct = ep.calmar_ratio(returns_pct, period="daily", annualization=None) sortino_pct = ep.sortino_ratio( returns_pct, required_return=0, period="daily", annualization=None, _downside_risk=None, ) tail_ratio_pct = ep.tail_ratio(returns_pct) financials = { "annual_return": annual_return_pct, "cumm_return": cumm_return_pct, "cagr": cagr_pct, "sharpe": sharpe_pct, "annual_volatility": annual_volatility_pct, "max_drawdown": max_drawdown_pct, "calmar": calmar_pct, "sortino": sortino_pct, "tail_ratio": tail_ratio_pct, } # Originally set up program to analyse both pct_change and log returns, but the difference between log and # pct_change was not material to the final analysis. Consequently pct_change used exclusively. The code below # is left in tact should log returns at the account level be desired. # returns_log = df["log_ret"] # Log returns not used in final scenario. # annual_return_log = ep.annual_return( # returns_log, period="daily", annualization=None # ) # cumm_return_log = ep.cum_returns(returns_log, starting_value=0).iloc[-1] # cagr_log = ep.cagr(returns_log, period="daily", annualization=None) # sharpe_log = ep.sharpe_ratio( # returns_log, risk_free=risk_free_rate, period="daily", annualization=None # ) # annual_volatility_log = ep.annual_volatility( # returns_log, period="daily", alpha=2.0, annualization=None # ) # max_drawdown_log = ep.max_drawdown(returns_log) # calmar_log = ep.calmar_ratio(returns_log, period="daily", annualization=None) # sortino_log = ep.sortino_ratio( # returns_log, # required_return=0, # period="daily", # annualization=None, # _downside_risk=None, # ) # tail_ratio_log = ep.tail_ratio(returns_log) # financials = { # ("return_percent_change", "annual_return"): annual_return_pct, # ("return_percent_change", "cumm_return"): cumm_return_pct, # ("return_percent_change", "cagr"): cagr_pct, # ("return_percent_change", "sharpe"): sharpe_pct, # ("return_percent_change", "annual_volatility"): annual_volatility_pct, # ("return_percent_change", "max_drawdown"): max_drawdown_pct, # ("return_percent_change", "calmar"): calmar_pct, # ("return_percent_change", "sortino"): sortino_pct, # ("return_percent_change", "tail_ratio"): tail_ratio_pct, # ("return_log", "annual_return"): annual_return_log, # ("return_log", "cumm_return"): cumm_return_log, # ("return_log", "cagr"): cagr_log, # ("return_log", "sharpe"): sharpe_log, # ("return_log", "annual_volatility"): annual_volatility_log, # ("return_log", "max_drawdown"): max_drawdown_log, # ("return_log", "calmar"): calmar_log, # ("return_log", "sortino"): sortino_log, # ("return_log", "tail_ratio"): tail_ratio_log, # } return financials
def work(PARAMS): info('work %s' % str(PARAMS)) stock_df_dict = None show_df = None order_df = None PROPERTY = None STRATEGY = PARAMS[0] POS = PARAMS[1] N = PARAMS[2] K = PARAMS[3] M = PARAMS[4] global ROTATION_LIST ROTATION_LIST = ROTATION_LIST stock_df_dict = get_stock_df_dict(N, M) show_df, order_df, PROPERTY = run_turtle(ROTATION_LIST, stock_df_dict, STRATEGY, POS, N, K, M) df = show_df.dropna(how='any', inplace=False).copy() df = df.loc[start_date:end_date] algo = df['PROPERTY'].pct_change() benchmark = df.open.pct_change() DAYS_ALL = len(df) DAYS_NOFULLHOLD = len(df[df['CASH'] > (df['PROPERTY'] / POS)]) output_str = '' for y in range(int(start_date.split('-')[0]), int(end_date.split('-')[0]) + 1, 1): # info('y = %d' % y) y_df = df.loc['%d-01-01' % y:'%d-01-01' % (y + 1)] if len(y_df) == 0: continue y_algo = y_df['PROPERTY'].pct_change() # info(y_algo) y_benchmark = y_df.open.pct_change() # info('y_benc') result = '%d-%d,%.3f,%.3f,%.3f,%.3f' % ( y, y + 1, emp.cum_returns(y_algo)[-1], emp.cum_returns(y_benchmark)[-1], emp.max_drawdown(y_algo), emp.max_drawdown(y_benchmark) ) output_str += result output_str += ';' # info(output_str) df = order_df.copy() df['pro_pct'] = (df.borrow_price - df.return_price) / df.return_price df = df.loc[:, ['symbol', 'pro_pct']] df = df.groupby(by='symbol').sum() buy_stock_count = len(df) score_sr = pd.Series({ 'START': start_date, 'END': end_date, 'STRATEGY': STRATEGY, 'POS': POS, 'N': N, 'K': K, 'M': M, 'ORDER': len(order_df), 'STOCK': buy_stock_count, 'RETURN_ALGO': emp.cum_returns(algo)[-1], 'RETURN_BENC': emp.cum_returns(benchmark)[-1], 'MAXDROPDOWN_ALGO': emp.max_drawdown(algo), 'MAXDROPDOWN_BENC': emp.max_drawdown(benchmark), 'WINRATE_ORDER': len(order_df[order_df.profit > 0]) / len(order_df[order_df.profit != 0]), 'WINRATE_YEARLY': 0, 'ANNUAL_RETURN': emp.annual_return(algo), 'ANNUAL_VOLATILITY': emp.annual_volatility(algo, period='daily'), 'CALMAR_RATIO': emp.calmar_ratio(algo), 'SHARPE_RATIO': emp.sharpe_ratio(returns=algo), 'ALPHA': emp.alpha(returns=algo, factor_returns=benchmark, risk_free=0.00), 'BETA': emp.beta(returns=algo, factor_returns=benchmark, risk_free=0.00), 'DAYS_ALL': DAYS_ALL, 'DAYS_NOFULLHOLD': DAYS_NOFULLHOLD, 'RET_PER_YEAR': output_str, }) YEAR_COUNT = 0 ALGO_WIN_YEAR_COUNT = 0 df = show_df.dropna(how='any', inplace=False).copy() df = df.loc[start_date:end_date] for y in range(int(start_date.split('-')[0]), int(end_date.split('-')[0]) + 1, 1): y_df = df.loc['%d-01-01' % y:'%d-01-01' % (y + 1)] # info('y = %d' % y) if len(y_df) == 0: continue y_algo = y_df['PROPERTY'].pct_change() y_benchmark = y_df.open.pct_change() score_sr['RETURN_ALGO_%d' % y] = emp.cum_returns(y_algo)[-1] score_sr['RETURN_BENC_%d' % y] = emp.cum_returns(y_benchmark)[-1] YEAR_COUNT += 1 if score_sr['RETURN_ALGO_%d' % y] > score_sr['RETURN_BENC_%d' % y]: ALGO_WIN_YEAR_COUNT += 1 score_sr['WINRATE_YEARLY'] = ALGO_WIN_YEAR_COUNT / YEAR_COUNT return PARAMS, score_sr, order_df