记录一个超短线持股不超过3天的量化交易策略

       今天借助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比较图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宁波阿成

你的支持,是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值