使用 vnpy_portfoliostrategy 策略,在 calculate(self, bars: Dict[str, BarData], freq) 方法中调用了self.rebalance_portfolio(bars),但在回测时发现并不一定能回调到 update_trade方法,调试发现在调用rebalance_portfolio时,也执行了 self.buy(vt_symbol, order_price, buy_volume),本次回测为单个标的,数据库K线数据未发现缺失。calculate 函数代码如下:
def calculate(self, bars: Dict[str, BarData], freq):
# 因calculate可能在多个周期K线更新时调用,上一笔交易未完成时直接返回
if not self.trade_finish_signal:
logging.debug(f"上一笔交易未完成")
return
for vt_symbol, bar in bars.items():
if vt_symbol == None or bar == None:
continue
current_time = bar.datetime
if current_time.hour >= 15:
# 15点不做交易
continue
else:
# 其它时间段只在15分钟级别上调用
if freq != "15m":
continue
current_pos = self.holdings_pos.get(vt_symbol, SymbolPos.Empty)
trade_type, pos = algo(vt_symbol, current_time, current_pos, self)
if trade_type == TradeType.Unknown or pos == SymbolPos.Empty:
continue
if trade_type == TradeType.Buy:
# 判断持仓标的数量是否超限
is_new_target = vt_symbol not in self.holdings_pos
if len(self.holdings_pos) >= self.holdings_max_count and is_new_target:
logging.warning(f"持仓标的数量已达 {self.holdings_max_count} 个,剩余资金:{self.total_capital:.2f},不再买入")
continue
if current_pos + pos > SymbolPos.Full:
logging.debug(f"已经有 {current_pos} 仓位,此次买入 {pos} 后将超满仓,减量买入")
pos = SymbolPos.Full - current_pos
self.buy_targets_pos[vt_symbol] = pos
logging.debug(f"{vt_symbol} 买入 {pos} 仓位")
elif trade_type == TradeType.Sell:
record:StockRecord = self.get_record(vt_symbol)
# total_vol = record.get_total_vol()
total_vol = self.get_pos(vt_symbol) # 当前总持仓
sell_vol:int = 0
sell_pos = SymbolPos.Empty
index = 0
while index < len(record.buy_info_list) and sell_pos < pos:
item: BuyInfo = record.buy_info_list[index]
# 检查是否是当天买入的
if current_time and current_time.date() == item.buy_time.date():
logging.debug(f"{current_time:%F %X} 买入的 {item.buy_vol} 股不能卖出,跳过")
index += 1 # 移动到下一个元素
continue
sell_vol += item.buy_vol
sell_pos += item.buy_pos
del record.buy_info_list[index]
if sell_pos <= 0:
continue
dest_vol = total_vol - sell_vol
self.set_target(vt_symbol, dest_vol)
self.sell_targets_pos[vt_symbol] = sell_pos
if len(self.sell_targets_pos) > 0:
logging.debug("有卖出,先执行卖出,下次再执行买入操作")
self.trade_finish_signal = False
self.rebalance_portfolio(bars)
self.put_event()
return
if len(self.buy_targets_pos) == 0:
logging.debug("buy_targets_pos == 0,不执行买入")
return
# 计算能够买入的仓位
for vt_symbol, pos in self.buy_targets_pos.items():
# 当前标的已满仓
current_pos = self.holdings_pos.get(vt_symbol, SymbolPos.Empty)
if current_pos == SymbolPos.Full:
logging.warning(f"{vt_symbol} 已满仓")
continue
# 计算平均资金买入数量
cur_price = self.get_last_price(vt_symbol, 'h')
if cur_price <= 0:
dt = 0
for vt_symbol, bar in bars.items():
if isinstance(bar.datetime, datetime):
dt = bar.datetime
break
logging.warning(f"异常!获取 {vt_symbol} 的最新价格为:{cur_price:.2f},时间:{dt:%F %X}")
continue
record:StockRecord = self.get_record(vt_symbol)
# 每次买入前需要重新计算,去掉已经买入的标的
total_holdings_pos = sum(self.holdings_pos.values())
if self.capital_shares_num > total_holdings_pos + pos:
self.target_capital = self.total_capital / (self.capital_shares_num - total_holdings_pos) * pos
elif self.capital_shares_num == total_holdings_pos + pos:
self.target_capital = self.total_capital
else:
self.target_capital = 0
target = math.floor((self.target_capital / cur_price) / 100) * 100
if target < 100:
current_time = bars[vt_symbol].datetime
logging.warning(f"资金不足。total_capital = {self.total_capital:.2f}, target_capital = {self.target_capital:.2f} 代码:{vt_symbol} 时间:{get_dt_string(current_time)}")
continue
cur_pos = self.get_pos(vt_symbol)
target += cur_pos
self.set_target(vt_symbol, target)
logging.warning(f"{vt_symbol} cur_pos = {cur_pos}, target = {target}")
# 执行买入
self.trade_finish_signal = False
self.rebalance_portfolio(bars)
self.put_event()
logging.debug("after put_event")
部分日志输出如下:
2026-03-21 17:47:02 [ DEBUG line:5650 ] 600645.SSE 买入 3 仓位
2026-03-21 17:47:02 [ WARNING line:5732 ] 600645.SSE cur_pos = 0, target = 2300
2026-03-21 17:50:20 [ DEBUG line:5738 ] after put_event
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
2026-03-21 17:50:20 [ DEBUG line:5612 ] 上一笔交易未完成
vnpy环境为2025年9月的版本(应该是3.9)请问大佬,这可能是什么原因?
