import pandas as pd import akshare as ak import warnings warnings.filterwarnings(‘ignore’) ======参数设置====== start_date = ‘20100101’ #开始日期 end_date = ‘20250320’ #结束日期 ma_length = 26 #均线长度 cost = 0.0003 #交易费率,万三 获取美债收益率数据 bond_df = ak.bond_zh_us_rate(start_date=start_date) bond_df[‘日期’] = bond_df[‘日期’].apply(lambda x: x.strftime(‘%Y-%m-%d’)) 获取沪深300指数数据 hs300_df = ak.index_zh_a_hist(symbol=‘000300’, period=‘daily’, start_date=start_date, end_date=end_date) hs300_df[‘涨跌幅’] = hs300_df[‘涨跌幅’] / 100.0 #将百分比转化成小数形式 合并数据,以沪深300日期为准 df = pd.merge(hs300_df[[‘日期’, ‘收盘’, ‘涨跌幅’]].rename(columns={‘收盘’:‘沪深300’}), bond_df[[‘日期’,‘美国国债收益率10年’]].rename(columns={‘美国国债收益率10年’:‘美债收益率’}), on=‘日期’, how=‘left’).fillna(method=‘ffill’).reset_index(drop=True) df[‘日期’] = pd.to_datetime(df[‘日期’]) # ======获取每周最后一个交易日====== rule:重采样频率,W-周频,M-月频 week_df = df.resample(rule=‘W’, on=‘日期’).agg({‘日期’:‘last’,‘美债收益率’:‘last’}).dropna() week_df[‘美债收益率MA’] = week_df[‘美债收益率’].rolling(ma_length).mean() week_df[‘周最后交易日’] = 1 week_df.index.name = ‘date’ # 拼接数据 day_df = pd.merge(df.drop(columns=[‘美债收益率’]), week_df, on=‘日期’, how=‘left’) day_df[‘周最后交易日’] = day_df[‘周最后交易日’].fillna(value=0) # 生成交易信号 如果 r-r_ma(26)<0,认为情绪偏多,今日只能看到昨日的数据 day_df.loc[((day_df[‘美债收益率’]-day_df[‘美债收益率MA’]).shift(1)<0) & (day_df[‘周最后交易日’].shift(1)>0), ‘signal’] = 1 如果 r-r_ma(26)>0,认为情绪偏空,今日只能看到昨日的数据 day_df.loc[((day_df[‘美债收益率’]-day_df[‘美债收益率MA’]).shift(1)>0) & (day_df[‘周最后交易日’].shift(1)>0), ‘signal’] = -1 day_df = day_df.set_index(‘日期’, drop=True) # 将交易信号转化为持仓 day_df[‘signal’] = day_df[‘signal’].fillna(method=‘ffill’).fillna(value=0) day_df[‘position’] = day_df[‘signal’].shift(1).fillna(value=0) #收盘交易,下一日才会有持仓 考虑交易成本 day_df[‘after_cost’] = 1.0 day_df.loc[day_df[‘signal’] != day_df[‘signal’].shift(1), ‘after_cost’] = (1.0 + cost) * (1.0 + cost) #开平仓各收一次手续费 day_df.loc[(day_df[‘signal’].shift(1) == 0) & (day_df[‘signal’] != 0), ‘after_cost’] = 1.0 + cost #第一次开仓只收一次手续费 day_df.loc[day_df.index[0], ‘after_cost’] = 1.0 # 画出净值曲线图 import matplotlib.pyplot as plt plt.rcParams[‘font.sans-serif’] = [‘SimHei’] plt.rcParams[‘axes.unicode_minus’] = False 择时策略的日收益率 day_df[‘strategy_pct’] = day_df[‘涨跌幅’] * day_df[‘position’] #策略和沪深300的净值 day_df[‘strategy’] = (1.0 + day_df[‘strategy_pct’]).cumprod() / day_df[‘after_cost’].cumprod() day_df[‘benchmark’] = (1.0 + day_df[‘涨跌幅’]).cumprod() 粗略计算年化收益率 annual_return = 100 * (pow(day_df[‘strategy’].iloc[-1], 250/day_df.shape[0]) - 1.0) print(‘美债收益率大盘择时策略的年化收益率:%.2f%%’ %annual_return) #将索引从字符串转换为日期格式,方便展示 ax = day_df[[‘strategy’,‘benchmark’]].plot(figsize=(16,8), color=[‘SteelBlue’,‘Red’], grid=True, title=‘美债收益率大盘择时策略净值’) plt.show() 给上述代码再加上最大回撤及夏普比率 卡玛比率代码 比较基准也一块加上
时间: 2025-07-08 14:35:43 浏览: 18
<think>好的,我需要帮用户给现有的Python代码添加最大回撤、夏普比率和卡玛比率,同时将这些指标与基准(沪深300)进行比较。现在我先仔细理解用户提供的代码结构,然后确定需要添加的部分。
首先,用户现有的代码通过美债收益率的移动平均生成交易信号,计算策略的净值曲线和年化收益率。现在需要补充三个指标:最大回撤、夏普比率、卡玛比率,并且对基准也做同样的计算。
最大回撤的计算需要找出净值曲线从峰值到谷底的最大跌幅。可以通过累计最大值和当前值来计算每日的回撤,然后取最大值。
夏普比率需要策略的年化收益率减去无风险利率(这里可能需要假设,比如用美债收益率作为无风险利率?但用户代码中未明确,可能需要用0或者另外获取数据),然后除以年化波动率。这里需要注意计算的是日度夏普,然后年化处理。
卡玛比率则是年化收益率除以最大回撤,所以需要先算年化收益和最大回撤。
另外,用户希望将基准(沪深300的净值)也计算同样的指标,所以需要分别对策略和基准进行处理。
现在分步骤考虑:
1. **计算最大回撤**:对于策略和基准的净值序列,计算每个时间点的历史最高值,然后计算当前净值相对于历史最高值的回撤比例,找出最大值。
2. **计算夏普比率**:需要日收益率数据。年化收益率已经计算,但需要年化波动率。假设一年约250个交易日。另外,无风险利率可能需要处理,例如用户可能用美债收益率的平均值作为无风险利率,或者忽略(即设为0)。这里可能需要进一步确认,但用户代码中没有明确,暂时假设无风险利率为0,或者从数据中提取。例如,美债收益率可能作为无风险利率的代理,但需要日度数据。当前代码中的美债收益率是周数据,填充到日数据,可能用ffill。所以,可以考虑每日的无风险利率是该天的美债收益率,或者周最后一个交易日的值。但这里可能比较复杂,用户可能希望简化处理,比如假设无风险利率为0。或者,用美债收益率的日数据计算日度的无风险收益。例如,将美债收益率除以252得到日利率。这部分需要明确,但用户代码中可能没有处理,所以可能需要假设或者询问用户,但根据用户的问题,可能暂时按默认方式处理,即使用年化无风险利率,例如0或者使用美债收益率的平均值。但需要看用户的数据是否有相关字段。
查看代码中的df结构,合并了美债收益率的数据,可能day_df中有美债收益率的日数据。所以,可以考虑将每日的美债收益率作为无风险利率。例如,将日度的美债收益率除以252(假设年化),得到日无风险利率。例如,如果美债收益率是年化的,那么日利率是r/252。但需要确认用户的数据中美债收益率的单位是否为年化百分比。例如,用户数据中的美债收益率如果是3表示3%,那么需要转换成小数形式。在现有代码中,用户处理涨跌幅时除以了100,所以可能美债收益率也是以百分比形式存在,需要转换。例如,原数据中的‘美国国债收益率10年’是百分比数值,比如3.0代表3%,所以用户可能在合并后没有处理,所以在day_df中的‘美债收益率’是百分比数值。例如,如果美债收益率是3%,那么日无风险利率为0.03/252。这可能需要调整。
但用户的代码中,可能未对美债收益率进行单位转换,例如原数据中的美债收益率是否为百分比形式(比如3.0代表3%)?比如在bond_df中,是否已经是小数形式?查看用户代码:
在获取美债收益率数据时,用户用的是akshare的bond_zh_us_rate函数。查阅akshare文档,美国国债收益率的数据返回的是数值型,例如10年期国债收益率可能是以百分比为单位,比如1.5表示1.5%。因此,用户可能需要将其转换为小数。例如,原数据中的美债收益率是1.5,那么实际是0.015。但用户当前代码中在合并后,并未进行这样的转换。例如,在合并后的df中的‘美债收益率’列是直接取自bond_df的‘美国国债收益率10年’,所以可能是百分比数值,如2.5代表2.5%。这时候需要除以100转化为小数形式。但用户的代码中,在获取沪深300的涨跌幅时,将其除以100转化为小数,但美债收益率可能没有处理,所以在计算无风险利率时需要转换。这可能是一个问题,需要确认。
例如,用户当前的代码中:
hs300_df[‘涨跌幅’] = hs300_df[‘涨跌幅’] / 100.0 #将百分比转化成小数形式
但bond_df中的‘美国国债收益率10年’没有进行这样的转换,所以可能该列的数据是如3.0表示3%,即0.03的小数形式?或者原数据是3.0代表3%?需要确认akshare返回的数据格式。假设akshare返回的美债收益率是百分比形式,例如3.0代表3%,则用户需要将其除以100转换为小数。例如,在合并后的df中美债收益率是3.0,此时用户需要将其转换为0.03。否则,如果已经是小数形式(如0.03),则无需转换。如果用户代码中未处理,那么在计算无风险利率时可能出现错误。
例如,用户代码中的美债收益率可能未转换,导致数值错误。这可能是一个潜在的问题。但根据用户的现有代码,暂时无法确定,所以可能需要假设。例如,假设美债收益率是以百分比形式存在,例如3.0代表3%,所以在计算时需要除以100转换为小数。因此,在计算无风险利率时,需要将美债收益率转换为小数,再计算日利率。
例如,假设用户的美债收益率是年化百分比,则日无风险利率为 (美债收益率 / 100) / 252。
但用户的代码中,美债收益率可能已经被处理了?或者原数据中已经是小数形式?比如,bond_zh_us_rate返回的数据是否已经是小数?比如,3%表示为0.03。需要确认。假设原数据中的美债收益率是小数形式,例如0.03代表3%,那么无需转换。否则,如果是3.0,则需要除以100。
这个问题可能会影响夏普比率的计算,所以需要处理。如果用户当前代码中没有对美债收益率进行转换,那么需要加上这一步。例如,在合并后的df中美债收益率是百分比数值,需要除以100。
例如,在合并后的df中,加入:
df['美债收益率'] = df['美债收益率'] / 100.0
但用户当前的代码中没有这一步,所以在后续计算中可能存在错误。但用户的问题不是调试代码,而是添加最大回撤等指标。因此,这里可能需要先修正美债收益率的转换问题,或者在计算无风险利率时进行处理。
这可能是一个需要注意的地方,但根据用户提供的现有代码,可能没有处理,所以这可能导致夏普比率计算时的错误。因此,在回答时需要指出这一点,或者直接在代码中添加转换。
综上,考虑到用户可能忽略将美债收益率转换为小数形式,所以在夏普比率计算时,需要处理。例如,在合并后的数据中,将美债收益率除以100:
df['美债收益率'] = df['美债收益率'] / 100.0
或者在计算无风险利率时处理。
现在回到用户的代码,在合并后的df中,美债收益率是来自bond_df的‘美国国债收益率10年’,而bond_df的数据可能未转换,所以需要检查是否应该进行转换。例如,假设原数据中的美债收益率是百分比数值,例如3.0代表3%,所以需要除以100转换为小数形式。这可能是一个必要的步骤,但用户的现有代码中没有,所以在添加指标时可能需要先处理。
因此,在合并后的df中,应该添加:
df['美债收益率'] = df['美债收益率'] / 100.0
这样才能正确使用美债收益率作为无风险利率。否则,如果美债收益率是小数形式,例如0.03代表3%,则无需处理。这需要用户确认akshare返回的数据格式。但根据用户处理涨跌幅的方式(除以100),推测美债收益率也需要同样的处理,所以应该在代码中添加这一步。
现在,假设用户的代码需要修正,将美债收益率转换为小数形式,在合并后的数据中添加:
df['美债收益率'] = df['美债收益率'] / 100.0
接下来,计算夏普比率时,需要策略的日收益率减去无风险利率的日收益率。假设美债收益率是年化的,那么日无风险利率为 (美债收益率) / 252。例如,年化3%的美债收益率对应的日利率约为0.03/252 ≈ 0.00011905。
因此,在计算每日的超额收益率时,策略的日收益率减去当日的无风险日利率。
但需要注意,美债收益率的数据可能存在缺失或者填充的情况。在用户代码中,合并数据时使用了ffill填充,所以每个交易日都有美债收益率的数据。
现在,添加最大回撤、夏普比率、卡玛比率的具体步骤:
**对于策略和基准:**
1. 最大回撤:
计算累计最大净值,然后计算每日回撤((累计最大值 - 当前净值)/ 累计最大值),取最大值。
2. 夏普比率:
计算日度超额收益率(策略日收益率 - 无风险日利率),计算平均超额收益率的年化值(乘以252),标准差年化(乘以sqrt(252)),夏普比率 = 年化平均超额收益率 / 年化标准差。
或者,如果假设无风险利率为0,则直接使用策略的日收益率计算。
但更准确的做法是使用无风险利率,这里用美债收益率作为无风险利率的代理。
3. 卡玛比率:
年化收益率 / 最大回撤。
**具体代码实现:**
首先,计算策略和基准的净值曲线已经存在('strategy'和'benchmark'列)。
然后,计算最大回撤:
对于策略:
max_drawdown = (1 - (day_df['strategy'] / day_df['strategy'].cummax())).max()
同样,基准的最大回撤:
benchmark_max_drawdown = (1 - (day_df['benchmark'] / day_df['benchmark'].cummax())).max()
然后,夏普比率:
需要策略的日收益率,这里策略的日收益率存储在'strategy_pct'列,但已经考虑了持仓和交易成本。或者,策略的日收益率是根据'strategy'列计算的每日收益率。例如:
day_df['strategy_daily_return'] = day_df['strategy'].pct_change().fillna(0)
但可能更准确的方式是使用已经计算好的'strategy_pct'列,因为策略的日收益率是涨跌幅乘以持仓,并且考虑交易成本后的净值。但原代码中的'strategy_pct'是涨跌幅乘以position,然后累计乘积再除以after_cost的累计乘积,这可能比较复杂。或者,可能应该根据净值的每日变化来计算日收益率。例如,策略的日收益率是 (strategy_t / strategy_{t-1}) - 1。
所以更准确的计算方式是:
day_df['strategy_daily_return'] = day_df['strategy'].pct_change().fillna(0)
同样,基准的日收益率是涨跌幅,即'涨跌幅'列。
对于无风险日利率,假设美债收益率是年化收益率,将其转换为日利率:
day_df['risk_free_daily'] = day_df['美债收益率'] / 252
然后,计算超额收益率:
day_df['excess_return_strategy'] = day_df['strategy_daily_return'] - day_df['risk_free_daily']
夏普比率 = (平均超额收益率 * 252) / (超额收益率的标准差 * sqrt(252))
即:
sharpe_ratio = (excess_return_strategy.mean() * 252) / (excess_return_strategy.std() * np.sqrt(252))
同样,对于基准:
day_df['benchmark_daily_return'] = day_df['benchmark'].pct_change().fillna(0)
excess_return_benchmark = day_df['benchmark_daily_return'] - day_df['risk_free_daily']
sharpe_ratio_benchmark = (excess_return_benchmark.mean() * 252) / (excess_return_benchmark.std() * np.sqrt(252))
卡玛比率:
策略年化收益率 / 策略最大回撤
假设已有策略的年化收益率变量annual_return(以小数形式,比如0.1代表10%),则卡玛比率 = annual_return / max_drawdown
同样计算基准的年化收益率,然后卡玛比率。
但原代码中的annual_return是用户计算的策略年化收益率,但以百分比形式输出。例如,用户代码中的:
annual_return = 100 * (pow(day_df['strategy'].iloc[-1], 250/day_df.shape[0]) - 1.0)
这里,可能计算有误,因为通常年化收益率的计算应该是 (净值^(365/天数) - 1),但用户这里用250/day_df.shape[0]。假设一年250个交易日,所以是正确的。
但需要将结果转换为小数形式,比如如果annual_return是10.5(代表10.5%),则需要除以100得到0.105。
因此,在计算卡玛比率时,应该用年化收益率的小数形式除以最大回撤的小数形式。
现在,具体代码步骤:
首先,计算最大回撤:
# 策略最大回撤
strategy_max_drawdown = (1 - day_df['strategy'] / day_df['strategy'].cummax()).max()
# 基准最大回撤
benchmark_max_drawdown = (1 - day_df['benchmark'] / day_df['benchmark'].cummax()).max()
然后,计算夏普比率:
假设无风险利率是美债收益率,年化转换为日:
import numpy as np
# 转换美债收益率为小数(如果尚未转换)
day_df['美债收益率'] = day_df['美债收益率'] / 100.0 # 如果原数据是百分比形式,例如3.0代表3%
day_df['risk_free_daily'] = day_df['美债收益率'] / 252
# 计算策略的日收益率
day_df['strategy_daily_return'] = day_df['strategy'].pct_change().fillna(0)
# 计算基准的日收益率
day_df['benchmark_daily_return'] = day_df['benchmark'].pct_change().fillna(0)
# 策略超额收益
day_df['excess_return_strategy'] = day_df['strategy_daily_return'] - day_df['risk_free_daily']
# 基准超额收益
day_df['excess_return_benchmark'] = day_df['benchmark_daily_return'] - day_df['risk_free_daily']
# 计算夏普比率
sharpe_strategy = (day_df['excess_return_strategy'].mean() * 252) / (day_df['excess_return_strategy'].std() * np.sqrt(252))
sharpe_benchmark = (day_df['excess_return_benchmark'].mean() * 252) / (day_df['excess_return_benchmark'].std() * np.sqrt(252))
卡玛比率:
# 计算策略年化收益率(小数形式)
annual_return_strategy = pow(day_df['strategy'].iloc[-1], 250/day_df.shape[0]) - 1.0
# 卡玛比率策略
calmar_strategy = annual_return_strategy / strategy_max_drawdown
# 计算基准年化收益率
annual_return_benchmark = pow(day_df['benchmark'].iloc[-1], 250/day_df.shape[0]) - 1.0
# 卡玛比率基准
calmar_benchmark = annual_return_benchmark / benchmark_max_drawdown
然后,将这些指标格式化输出,与之前的annual_return一起显示。
用户当前的代码中,annual_return是以百分比形式打印的,所以可能需要将这里的annual_return_strategy乘以100得到百分比形式。
同时,注意原代码中的annual_return计算可能存在误差,因为用户用了250/day_df.shape[0],而实际交易日数量可能不等于该数值。但用户可能假设如此,所以保持原计算方式。
现在,将这些代码添加到用户的代码中:
在计算完annual_return后,添加:
import numpy as np
# 计算最大回撤
day_df['strategy_cummax'] = day_df['strategy'].cummax()
strategy_max_drawdown = (1 - day_df['strategy'] / day_df['strategy_cummax']).max()
day_df['benchmark_cummax'] = day_df['benchmark'].cummax()
benchmark_max_drawdown = (1 - day_df['benchmark'] / day_df['benchmark_cummax']).max()
# 转换美债收益率为小数形式(假设原数据为百分比)
day_df['美债收益率'] = day_df['美债收益率'] / 100.0
# 计算无风险日利率
day_df['risk_free_daily'] = day_df['美债收益率'] / 252
# 计算策略和基准的日收益率
day_df['strategy_daily_return'] = day_df['strategy'].pct_change().fillna(0)
day_df['benchmark_daily_return'] = day_df['benchmark'].pct_change().fillna(0)
# 计算超额收益
day_df['excess_return_strategy'] = day_df['strategy_daily_return'] - day_df['risk_free_daily']
day_df['excess_return_benchmark'] = day_df['benchmark_daily_return'] - day_df['risk_free_daily']
# 计算夏普比率
sharpe_strategy = (day_df['excess_return_strategy'].mean() * 252) / (day_df['excess_return_strategy'].std() * np.sqrt(252))
sharpe_benchmark = (day_df['excess_return_benchmark'].mean() * 252) / (day_df['excess_return_benchmark'].std() * np.sqrt(252))
# 计算卡玛比率
annual_return_strategy = pow(day_df['strategy'].iloc[-1], 250/day_df.shape[0]) - 1.0
calmar_strategy = annual_return_strategy / strategy_max_drawdown
annual_return_benchmark = pow(day_df['benchmark'].iloc[-1], 250/day_df.shape[0]) - 1.0
calmar_benchmark = annual_return_benchmark / benchmark_max_drawdown
# 输出结果
print('策略年化收益率:{:.2f}%'.format(annual_return * 100)) # 这里原代码中的annual_return可能已经计算正确?
print('策略最大回撤:{:.2%}'.format(strategy_max_drawdown))
print('策略夏普比率:{:.2f}'.format(sharpe_strategy))
print('策略卡玛比率:{:.2f}'.format(calmar_strategy))
print('------------------------')
print('基准年化收益率:{:.2f}%'.format(annual_return_benchmark * 100))
print('基准最大回撤:{:.2%}'.format(benchmark_max_drawdown))
print('基准夏普比率:{:.2f}'.format(sharpe_benchmark))
print('基准卡玛比率:{:.2f}'.format(calmar_benchmark))
但需要注意原代码中的annual_return变量是否正确。用户原来的代码:
annual_return = 100 * (pow(day_df['strategy'].iloc[-1], 250/day_df.shape[0]) - 1.0)
这可能有问题,因为策略的净值在计算时除以了after_cost的累计乘积。例如,策略的净值计算是:
day_df['strategy'] = (1.0 + day_df['strategy_pct']).cumprod() / day_df['after_cost'].cumprod()
但after_cost的累计乘积可能不是简单的时间加权,需要确认是否正确。或者,是否应该直接根据strategy的净值曲线计算年化收益率。例如,年化收益率的正确计算应该是:
(day_df['strategy'].iloc[-1] ** (252 / len(day_df))) - 1
假设每年252个交易日,len(day_df)是总交易日数。所以用户原来的代码中使用了250/day_df.shape[0],可能存在偏差。应该根据实际交易天数调整。
例如,正确的年化收益率计算应为:
annual_return_strategy = (day_df['strategy'].iloc[-1] ** (252 / len(day_df))) - 1
同样适用于基准的年化收益率。
因此,用户原来的annual_return计算可能需要修正。例如,将250改为252,并计算正确的年化收益率。但用户可能根据自身需求设置,这里暂时保持原计算方式,但需要注意。
综上,将这些代码添加到用户现有代码的打印年化收益率之后即可。
同时,可能需要在计算前导入numpy:
import numpy as np
现在,整合到用户代码中:
在plt.show()之前添加:
# 计算最大回撤
day_df['strategy_cummax'] = day_df['strategy'].cummax()
strategy_max_drawdown = (1 - day_df['strategy'] / day_df['strategy_cummax']).max()
day_df['benchmark_cummax'] = day_df['benchmark'].cummax()
benchmark_max_drawdown = (1 - day_df['benchmark'] / day_df['benchmark_cummax']).max()
# 转换美债收益率为小数形式(假设原数据为百分比)
day_df['美债收益率'] = day_df['美债收益率'] / 100.0
# 计算无风险日利率
day_df['risk_free_daily'] = day_df['美债收益率'] / 252
# 计算策略和基准的日收益率
day_df['strategy_daily_return'] = day_df['strategy'].pct_change().fillna(0)
day_df['benchmark_daily_return'] = day_df['benchmark'].pct_change().fillna(0)
# 计算超额收益
day_df['excess_return_strategy'] = day_df['strategy_daily_return'] - day_df['risk_free_daily']
day_df['excess_return_benchmark'] = day_df['benchmark_daily_return'] - day_df['risk_free_daily']
# 计算夏普比率
sharpe_strategy = (day_df['excess_return_strategy'].mean() * 252) / (day_df['excess_return_strategy'].std() * np.sqrt(252))
sharpe_benchmark = (day_df['excess_return_benchmark'].mean() * 252) / (day_df['excess_return_benchmark'].std() * np.sqrt(252))
# 计算卡玛比率
annual_return_strategy = pow(day_df['strategy'].iloc[-1], 250/day_df.shape[0]) - 1.0
calmar_strategy = annual_return_strategy / strategy_max_drawdown
annual_return_benchmark = pow(day_df['benchmark'].iloc[-1], 250/day_df.shape[0]) - 1.0
calmar_benchmark = annual_return_benchmark / benchmark_max_drawdown
print('策略年化收益率:{:.2f}%'.format(annual_return))
print('策略最大回撤:{:.2%}'.format(strategy_max_drawdown))
print('策略夏普比率:{:.2f}'.format(sharpe_strategy))
print('策略卡玛比率:{:.2f}'.format(calmar_strategy))
print('------------------------')
print('基准年化收益率:{:.2f}%'.format(annual_return_benchmark * 100))
print('基准最大回撤:{:.2%}'.format(benchmark_max_drawdown))
print('基准夏普比率:{:.2f}'.format(sharpe_benchmark))
print('基准卡玛比率:{:.2f}'.format(calmar_benchmark))
但需要注意,原来的annual_return是用户计算的策略年化收益率,而annual_return_strategy是重新计算的,可能存在差异。例如,用户原来的代码:
annual_return = 100 * (pow(day_df['strategy'].iloc[-1], 250/day_df.shape[0]) - 1.0)
而在这里,annual_return_strategy = pow(...) - 1.0,没有乘以100。所以,在打印基准年化时,应该使用annual_return_benchmark * 100。
或者,统一使用新的计算方式,避免混淆。例如,重新计算策略和基准的年化收益率:
# 重新计算年化收益率(假设250个交易日)
annual_return_strategy = (day_df['strategy'].iloc[-1] ** (250 / len(day_df))) - 1
annual_return_benchmark = (day_df['benchmark'].iloc[-1] ** (250 / len(day_df))) - 1
print('策略年化收益率:{:.2%}'.format(annual_return_strategy))
print('策略最大回撤:{:.2%}'.format(strategy_max_drawdown))
print('策略夏普比率:{:.2f}'.format(sharpe_strategy))
print('策略卡玛比率:{:.2f}'.format(annual_return_strategy / strategy_max_drawdown))
print('------------------------')
print('基准年化收益率:{:.2%}'.format(annual_return_benchmark))
print('基准最大回撤:{:.2%}'.format(benchmark_max_drawdown))
print('基准夏普比率:{:.2f}'.format(sharpe_benchmark))
print('基准卡玛比率:{:.2f}'.format(annual_return_benchmark / benchmark_max_drawdown))
这样更统一,可能更准确。
但用户原来的代码中annual_return是乘以100并以百分比打印,所以需要保持一致性。或者,建议用户统一使用更准确的年化计算方法,并确保美债收益率的转换正确。
综上,最终的代码补充部分应该包括:
1. 转换美债收益率为小数形式(如果原数据是百分比)。
2. 计算最大回撤。
3. 计算夏普比率,使用美债收益率作为无风险利率。
4. 计算卡玛比率。
同时,将基准的相同指标一并计算并输出。
最后,确保导入numpy库,并在代码中添加必要的部分。</think>以下是添加最大回撤、夏普比率和卡玛比率的完整代码实现(新增部分已用注释标注):
```python
# ... 原有代码保持不变 ...
# ======新增性能指标计算======
import numpy as np
# 计算最大回撤(策略)
day_df['strategy_cummax'] = day_df['strategy'].cummax()
strategy_drawdown = (day_df['strategy'] - day_df['strategy_cummax']) / day_df['strategy_cummax']
strategy_max_drawdown = strategy_drawround.min()
# 计算最大回撤(基准)
day_df['benchmark_cummax'] = day_df['benchmark'].cummax()
benchmark_drawdown = (day_df['benchmark'] - day_df['benchmark_cummax']) / day_df['benchmark_cummax']
benchmark_max_drawdown = benchmark_drawdown.min()
# 转换美债收益率为小数格式(假设原始数据为百分比)
day_df['美债收益率'] = day_df['美债收益率'] / 100.0
# 计算年化无风险利率(使用美债收益率均值)
risk_free_rate = day_df['美债收益率'].mean()
# 计算夏普比率(策略)
strategy_return = day_df['strategy'].pct_change().dropna()
excess_return_strategy = strategy_return - risk_free_rate/252
sharpe_strategy = np.sqrt(252) * excess_return_strategy.mean() / excess_return_strategy.std()
# 计算夏普比率(基准)
benchmark_return = day_df['涨跌幅'].copy()
excess_return_benchmark = benchmark_return - risk_free_rate/252
sharpe_benchmark = np.sqrt(252) * excess_return_benchmark.mean() / excess_return_benchmark.std()
# 计算卡玛比率(策略)
annual_return_strategy = (day_df['strategy'].iloc[-1] ** (250/len(day_df)) - 1)
calmar_strategy = annual_return_strategy / abs(strategy_max_drawdown)
# 计算卡玛比率(基准)
annual_return_benchmark = (day_df['benchmark'].iloc[-1] ** (250/len(day_df)) - 1)
calmar_benchmark = annual_return_benchmark / abs(benchmark_max_drawdown)
# ======结果输出======
print('\n======策略表现======')
print(f'策略年化收益率:{annual_return:.2f}%')
print(f'策略最大回撤:{abs(strategy_max_drawdown):.2%}')
print(f'策略夏普比率:{sharpe_strategy:.2f}')
print(f'策略卡玛比率:{calmar_strategy:.2f}')
print('\n======基准表现======')
print(f'基准年化收益率:{annual_return_benchmark*100:.2f}%')
print(f'基准最大回撤:{abs(benchmark_max_drawdown):.2%}')
print(f'基准夏普比率:{sharpe_benchmark:.2f}')
print(f'基准卡玛比率:{calmar_benchmark:.2f}')
# ... 后续绘图代码保持不变 ...
```
**代码说明:**
1. **最大回撤计算**:通过累计最大值计算每个交易日的回撤率,取最小值作为最大回撤(结果为负值,取绝对值显示)
2. **夏普比率计算**:
- 使用$$Sharpe = \frac{E(R_p - R_f)}{\sigma_p} \times \sqrt{252}$$公式
- 将年化美债收益率转换为日无风险利率$$R_f^{daily} = R_f^{annual}/252$$
3. **卡玛比率计算**:
- 使用$$Calmar = \frac{年化收益率}{最大回撤}$$公式
- 年化收益率计算保持与原有代码一致(250个交易日假设)
4. **基准指标计算**:
- 使用沪深300原始涨跌幅计算基准的夏普比率
- 基准最大回撤计算方式与策略一致
**注意事项:**
1. 美债收益率数据需要确认是否为百分比格式,若原始数据已为小数格式需删除转换代码
2. 年化交易日假设可根据实际数据调整(建议使用252天)
3. 最大回撤计算结果为负值,输出时取绝对值显示
阅读全文
相关推荐



















