在量化交易系统的回测模块中,按照我们的交易策略,产生了一条条的交易记录,如何通过这些交易数据,来判断我们策略的好坏,是否可以拿到实盘上跑呢?
评价一个交易策略,主要从以下三个方面:收益、风险、稳定性。常用的评价指标有:年化收益率、最大回撤、夏普比率、胜率、信息率等。今天主要分享这些指标的代码实现。
最大回撤
计算净值的最大回撤可以帮助投资者了解其投资组合经历的最大损失幅度,也就是能够承受的最大亏损,属于风险性指标。最大回撤的计算涉及找到净值序列中某个峰值到谷值之间的最大跌幅。
def calculate_max_drawdown(net_values):
"""
计算净值数组的最大回撤以及回撤区间的开始和结束下标。
参数:
net_values(list of float):净值数组。
返回:
tuple:(最大回撤值, 回撤开始下标, 回撤结束下标)
"""
if not net_values:
return(0, -1, -1)
max_drawdown =0
start_index =0
end_index =0
peak_index =0
for i in range(1, len(net_values)):
if net_values[i]> net_values[peak_index]:
peak_index = i
drawdown =(net_values[peak_index]- net_values[i])/ net_values[peak_index]
if drawdown > max_drawdown:
max_drawdown = drawdown
start_index = peak_index
end_index = i
return max_drawdown, start_index, end_index
在之前的文章 七天打造一套量化交易系统:Day3-回测系统的选择、搭建及改造,回测结果资金曲线中,可以加上最大回撤的区间,画图模块的代码后续分享。

年化收益率
计算净值的年化收益率可以帮助投资者理解其投资的长期回报率。下面代码中假设一年有 245 个交易日(针对国内股票、期货市场)。如果是数字货币交易,全年无休,就需要填成 365。
def calculate_annualized_return(net_values, num_trading_days=None):
"""
计算净值数组的年化收益率。
参数:
net_values(list of float):净值列表。
num_trading_days(int, optional):净值列表所代表的交易天数。如果为None,将假设净值列表长度为交易天数。
返回:
float:年化收益率,以小数形式表示。
"""
if not net_values or len(net_values)<2:
raise ValueError("净值列表至少需要两个数据点")
initial_value = net_values[0]
final_value = net_values[-1]
# 默认以净值长度为交易天数
num_days = len(net_values)if num_trading_days is Noneelse num_trading_days
# 计算总收益率
total_return =(final_value - initial_value)/ initial_value
# 计算年化收益率,假设一年有 245 个交易日
annualized_return =(1+ total_return)**(245.0/ num_days)-1
return annualized_return
夏普比率
夏普比率(Sharpe Ratio)是一个可以同时对收益与风险加以综合考虑的指标。
- • 在给定的风险水平下使期望回报最大化
- • 在给定期望回报率的水平上使风险最小化
def calculate_daily_returns(net_values):
"""
计算每日回报率。
参数:
net_values(list of float):每日净值列表。
返回:
list of float:每日回报率,以小数表示。
"""
if not net_values or len(net_values)<2:
raise ValueError("净值列表必须包含至少两个元素。")
daily_returns =[]
for i in range(1, len(net_values)):
daily_return =(net_values[i]- net_values[i -1])/ net_values[i -1]
daily_returns.append(daily_return)
return daily_returns
def calculate_sharpe_ratio(returns, risk_free_rate=0):
"""
计算投资组合的夏普比率。
参数:
returns (list or np.ndarray):投资组合的回报率序列。
risk_free_rate (float):无风险利率(默认值为0)。
返回:
float:夏普比率。
"""
returns = np.array(returns)
# 计算超额收益
excess_returns = returns - risk_free_rate
# 计算平均超额收益
mean_excess_return = np.mean(excess_returns)
# 计算超额收益的标准差
std_excess_return = np.std(excess_returns)
# 计算夏普比率
sharpe_ratio = mean_excess_return / std_excess_return
return sharpe_ratio
信息率
信息率用来衡量承担主动风险所带来的超额收益,表示单位主动风险所带来的超额收益,在承担适度风险的情况下,尽量追求高信息率。
def calculate_information_ratio(portfolio_returns, benchmark_returns):
"""
计算投资组合的信息率。
参数:
portfolio_returns(list or np.ndarray):投资组合的回报率序列。
benchmark_returns(list or np.ndarray):基准的回报率序列。
返回:
float:信息率。
"""
portfolio_returns = np.array(portfolio_returns)
benchmark_returns = np.array(benchmark_returns)
# 计算主动回报(超额收益)
active_returns = portfolio_returns - benchmark_returns
# 计算平均主动回报
mean_active_return = np.mean(active_returns)
# 计算跟踪误差(主动回报的标准差)
tracking_error = np.std(active_returns)
# 计算信息率
information_ratio = mean_active_return / tracking_error
return information_ratio
测试方法
if __name__ =="__main__":
# 每日净值列表(假设9个交易日)
net_values =[1.0,1.2,1.1,1.4,1.3,1.0,1.5,1.4,1.2]
print(net_values)
# 计算最大回撤
max_drawdown, start, end = calculate_max_drawdown(net_values)
print(f"max_drawdown: {max_drawdown:.4f}")
print(f"start index: {start} value: {net_values[start]:.2f}")
print(f"end index: {end} value: {net_values[end]:.2f}")
# 计算年化收益率
print(f"calculate_annualized_return: {calculate_annualized_return(net_values):.4f}")
print(f"calculate_annualized_return (245 days): {calculate_annualized_return(net_values, 245):.4f}")
print(f"calculate_annualized_return (490 days): {calculate_annualized_return(net_values, 490):.4f}")
# 计算每日回报率
daily_returns = calculate_daily_returns(net_values)
# 使用列表推导式格式化数组中的每个数字保留4位小数
formatted_daily_returns =["{:.4f}".format(num)for num in daily_returns]
print(f"daily_returns: {formatted_daily_returns}")
# 计算夏普比率
risk_free_rate =0.03/245# 假设每日无风险利率
sharpe_ratio = calculate_sharpe_ratio(daily_returns, risk_free_rate)
print(f"sharpe_ratio: {sharpe_ratio:.4f}")
# 计算信息率
# 假设基准的每日回报率
benchmark_returns =[0.005,0.015,0.01,0,0.02,0.01,0,-0.02]
information_ratio = calculate_information_ratio(daily_returns, benchmark_returns)
print(f"information_ratio: {information_ratio:.4f}")
执行结果:
[1.0,1.2,1.1,1.4,1.3,1.0,1.5,1.4,1.2]
max_drawdown:0.2857
start index:3 value:1.40
end index:5 value:1.00
calculate_annualized_return2:0.0231
calculate_annualized_return:142.0505
calculate_annualized_return (245 days):0.2000
calculate_annualized_return (490 days):0.0954
daily_returns:['0.2000','-0.0833','0.2727','-0.0714','-0.2308','0.5000','-0.0667','-0.1429']
sharpe_ratio:0.2015
information_ratio: 0.1820
c++版本
对于大部分朋友,python 版本的代码已经足够使用。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/134198
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!