模拟计数的问题

由bqetoybg创建,最终由bqetoybg 被浏览 7 用户

我在策略的handledata函数里有下面一段代码\n

# 记录新股票及其买入时的交易日索引
            context.holdings.append((best_code, current_idx))
            context.logger.info(f"持仓情况{context.holdings}, 计数{current_idx}")
            context.bought_today = True

用来记录买入的标的和时间,回测时运行正常,但是提交模拟后发现,在确信有持仓的情况下,每天买入股票之前context.holdings都是空的,请问怎么回事,怎么处理?

还有一个问题:trade_dates = dai.query("""

SELECT date

FROM all_trading_days""",

filters={"date": ["2020-01-01", "2020-01-31"]}).df()

trade_dates.tail()查询结果如下的DataFrame

        date

52 2020-01-29

53 2020-01-30

54 2020-01-30

55 2020-01-31

56 2020-01-31\n每个日期都出现两遍,并且最后这几个日期都不是交易日

\

def initialize(context: bigtrader.IContext):
    """
    回测初始化:设置因子数据、持仓记录
    """
    context.data = []
    # 持仓列表,每个元素为 (instrument, 买入时的交易日索引)
    context.holdings = []
    # 记录今天是否已经执行过卖出(每天只能卖一次)
    # context.sold_today = False
    # 记录今天是否已经执行过买入(每天只能买一次)
    context.bought_today = False


def before_trading(context: IContext, data: IBarData):
    """盘前重置每日交易标记"""
    context.bought_today = False
    

def handle_data(context: bigtrader.IContext, data: bigtrader.IBarData):
    current_date = data.current_dt.strftime("%Y-%m-%d")
    current_idx = context.trading_day_index

    sql = """
        查询内容略
        """
    e_date = context.current_dt
    s_date = e_date - timedelta(100)
    筛选过程略去
    data = data.sort_values(['daily_return'], ascending=[False])

    torch.manual_seed(99)
    np.random.seed(99)
    # ==================== 模型定义(二分类) ====================
    class CNNClassifier(nn.Module):
        def __init__(self, input_dim):
            super(CNNClassifier, self).__init__()
            self.conv1 = nn.Conv1d(in_channels=1, out_channels=64, kernel_size=1)
            self.conv2 = nn.Conv1d(in_channels=64, out_channels=32, kernel_size=1)
            self.global_pool = nn.AdaptiveAvgPool1d(1)
            self.fc1 = nn.Linear(32, 64)
            self.dropout = nn.Dropout(0.2)
            self.fc2 = nn.Linear(64, 1)  # 输出 logits
            self.relu = nn.ReLU()

        def forward(self, x):
            x = self.relu(self.conv1(x))
            x = self.relu(self.conv2(x))
            x = self.global_pool(x)
            x = x.view(x.size(0), -1)
            x = self.relu(self.fc1(x))
            x = self.dropout(x)
            x = self.fc2(x)
            return x
    
    feature_cols = [col for col in data.columns if col not in ['date', 'instrument']]
    model = CNNClassifier(input_dim=len(feature_cols))
    model.load_state_dict(torch.load('/home/aiuser/work/codeplayground/cnn_classifier_2_5_target_5.pth')) 
    model.eval()
    test_X = data[feature_cols].values.astype(np.float32)  # 先取 values
    test_X = torch.tensor(test_X, dtype=torch.float32).unsqueeze(1)
    try:
        with torch.no_grad():
            y_pred_proba = torch.sigmoid(model(test_X)).cpu().numpy().flatten()
        context.data = data[['date','instrument','daily_return','vol_ratio']] 
        context.data['pred_prob'] = y_pred_proba
        context.data = context.data.dropna()
        day_data = context.data.query('pred_prob>0.8').sort_values(['pred_prob','vol_ratio'], ascending=[False,False]).head(3)
    except:
        return


    # 获取当日因子数据,按 pred_ret 降序排序
    if day_data.empty:
        return

    # 当前持仓的股票代码
    current_hold_codes = {h[0] for h in context.holdings}
    context.logger.info(f"持仓情况{context.holdings}, 计数{current_idx}")

    # ---------- 持有满3天就卖 ----------
    if len(context.holdings) > 0:
        for oldest_code, oldest_idx in context.holdings:
            hold_days = current_idx - oldest_idx
            if hold_days >= 3:
                # 卖出到期股票
                context.order_target_value(oldest_code, 0)
                context.holdings.remove((oldest_code, oldest_idx))
            # context.sold_today = True

    # ---------- 买入逻辑:每天最多买一次,且确保买入后总持仓不超过3只 ----------
    if not context.bought_today and len(context.holdings) < 3:
        # 候选买入:当日得分最高且不在当前持仓中的股票
        candidates = day_data[~day_data["instrument"].isin(current_hold_codes)]
        if not candidates.empty:
            best_code = candidates.iloc[0]["instrument"]

            # 根据当前持仓数量决定买入金额比例
            hold_count = len(context.holdings)

            # 以下实现方式:获取当前账户信息,动态计算目标持仓比例。
            total_value = context.get_available_cash()  # 总资产
            context.logger.info(f"可用资金{total_value}")

            # 根据规则,本次买入应使用的现金比例
            if hold_count == 0:
                target_value = total_value / 3
            elif hold_count == 1:
                target_value = total_value / 2
            elif hold_count == 2:
                target_value = total_value
        
            context.order_target_value(best_code, target_value)

            # 记录新股票及其买入时的交易日索引
            context.holdings.append((best_code, current_idx))
            context.logger.info(f"持仓情况{context.holdings}, 计数{current_idx}")
            context.bought_today = True


# 回测配置
performance = bigtrader.run(
    market=bigtrader.Market.CN_STOCK,
    frequency=bigtrader.Frequency.DAILY,
    start_date='2026-01-01',
    end_date='2026-06-30',
    capital_base=100000,      # 初始资金10万
    initialize=initialize,
    handle_data=handle_data,
    before_trading_start=before_trading,
    order_price_field_buy='open',   # 以开盘价买入
    order_price_field_sell='open'   # 以开盘价卖出
)

我想实现的是持股三天就卖

评论
  • 你贴一下你的代码哈
  • 代码请见帖子,有两个问题烦请回复哈
{link}