今天借助AI,设计了一个超短线策略,持股时间不超过3天,同时亏损5%就止损。
1、原理是从自选里的大概100值沪深股票里进行挑选操作,满足买入条件就买入,有持仓的话,满足卖出条件的就卖出,费率按万分之三处理。
2、效果如下,说明备注一下,这里回撤有点不准,主要是有时候有数据丢失现象:
3、主要的回测代码如下:
def run_backtest(self):
"""执行回测(替换实时交易循环)"""
# 获取所有交易日
all_dates = sorted(set.union(*[set(df.index) for df in self.hist_data.values()]))
for date in all_dates:
for stock in self.stock_list:
if date in self.hist_data[stock].index:
signal = self._generate_signal(stock, date)
if signal:
self._execute_order(stock, date, signal)
#position_value = sum([self.positions[stock] * self.hist_data[stock].loc[date]['close']
# for stock in self.stock_list if date in self.hist_data[stock].index])
#修改后的持仓计算部分
position_value = sum([
self.positions[stock] * self.hist_data[stock].loc[date]['close']
for stock in self.stock_list
if self._is_date_valid(stock, date) # 改用验证函数
])
print(f"run_backtest total:{date} : {self.cash + position_value}")
self.equity.append({'date': date, 'total': self.cash + position_value})
# ✅ 新增日期验证方法
def _is_date_valid(self, stock, date):
if stock not in self.hist_data:
#print(f"⚠️ 股票 {stock} 无数据")
return False
if date not in self.hist_data[stock].index:
#print(f"⚠️ 股票 {stock} 在 {date} 无数据,索引范围: {self.hist_data[stock].index.min()} 到 {self.hist_data[stock].index.max()}")
return False
return True
def analyze_results(self):
"""生成回测报告(新增分析功能)"""
# 计算收益曲线
#print(f"analyze_results: {self.equity}")
# 空数据保护
if not self.equity:
print("回测期间无有效数据")
return
equity_df = pd.DataFrame(self.equity).set_index('date')
# 空数据保护
if equity_df.empty:
print("回测期间无有效数据")
return
equity_df['returns'] = equity_df['total'].pct_change()
# 计算关键指标
total_return = equity_df['total'].iloc[-1] / equity_df['total'].iloc[0] - 1
max_drawdown = (equity_df['total'].cummax() - equity_df['total']).max()
# 输出报告
print(f"\n{' 回测结果报告 ':=^40}")
print(f"初始资金: {self.initial_cash:,.2f}")
print(f"最终资产: {equity_df['total'].iloc[-1]:,.2f}")
print(f"总收益率: {total_return:.2%}")
print(f"最大回撤: {max_drawdown:,.2f}")
# 交易统计
trades_df = pd.DataFrame(self.trade_records)
print(f"\n累计交易次数: {len(trades_df)}")
if len(trades_df) == 0:
return
#print(trades_df.tail())
print(trades_df)
trades_df.to_excel('trades_kdj_sel.xlsx', index=False, sheet_name='KDJ选择的股票交易记录')
# ========== 新增绩效指标 ==========
# ✅ 关键修改:年化收益率计算
trading_days = len(equity_df)
total_return = equity_df['total'].iloc[-1] / self.initial_cash - 1
if trading_days < 10:
annualized_return = total_return
print("警告:回测周期不足10个交易日,年化收益率参考价值有限")
else:
# 修正为自然日或250交易日基准
total_days = (equity_df.index[-1] - equity_df.index[0]).days # 自然日
annualized_return_natural = (1 + total_return) ** (365 / total_days) - 1
annualized_return_trading = (1 + total_return) ** (250 / trading_days) - 1
# 夏普比率(假设无风险利率为3%)
excess_returns = equity_df['returns'] - 0.03/252
sharpe_ratio = np.sqrt(252) * excess_returns.mean() / excess_returns.std()
# ✅ 关键修改:胜率计算校验
trades_df = pd.DataFrame(self.trade_records)
sell_trades = trades_df[trades_df['action'] == 'SELL']
print("\n卖出交易详情:")
print(sell_trades[['date', 'stock', 'profit']])
if not sell_trades.empty:
win_rate = (sell_trades['profit'] > 0).mean()
else:
win_rate = 0.0
print(f"\n{' 高级绩效指标 ':=^40}")
print(f"自然日年化收益率: {annualized_return_natural:.2%}")
print(f"交易日年化收益率: {annualized_return_trading:.2%}")
print(f"夏普比率: {sharpe_ratio:.2f}")
print(f"交易胜率: {win_rate:.2%}")
print(f"最大回撤: {-max_drawdown/self.initial_cash:.2%}") # 显示为百分比
# ========== 新增沪深300对比 ==========
# 获取回测日期范围
start_date = equity_df.index[0].strftime('%Y%m%d')
end_date = equity_df.index[-1].strftime('%Y%m%d')
# 获取沪深300数据
hs300_code = '000300.SH'
xtdata.download_history_data(hs300_code, period='1d', start_time=start_date)
hs300_data = xtdata.get_market_data([], [hs300_code], '1d',
start_time=start_date, end_time=end_date)
# 处理数据格式
hs300_df = pd.DataFrame({
'time': pd.to_datetime(hs300_data['time'].squeeze(), unit='ms'),
'close': hs300_data['close'].squeeze()
}).set_index('time')
# 计算收益率(归一化处理)
initial_value = hs300_df['close'].iloc[0]
hs300_df['hs300'] = hs300_df['close'] / initial_value * self.initial_cash
# 合并数据
compare_df = equity_df.join(hs300_df, how='inner')
# 绘制对比图
plt.figure(figsize=(12, 6))
plt.plot(compare_df['total'], label='策略净值')
plt.plot(compare_df['hs300'], label='沪深300', linestyle='--')
plt.title('策略收益 vs 沪深300')
plt.legend()
plt.grid(True)
# 新增交互功能代码
# 创建数据标签字典
total_labels = [f"日期:{d.strftime('%Y-%m-%d')}\n策略净值:{v:,.2f}"
for d, v in zip(compare_df.index, compare_df['total'])]
hs300_labels = [f"日期:{d.strftime('%Y-%m-%d')}\n沪深300:{v:,.2f}"
for d, v in zip(compare_df.index, compare_df['hs300'])]
# 获取线条对象
lines = plt.gca().get_lines()
# 配置悬停提示
cursor = mplcursors.cursor(lines, hover=True)
cursor.connect(
"add",
lambda sel: sel.annotation.set_text(
total_labels[int(sel.index)] if sel.artist == lines[0]
else hs300_labels[int(sel.index)] # 强制转换为int类型
)
)
# 显示图形
plt.show(block=True)
4、收益与沪深300比较图