修复未来函数bug

This commit is contained in:
2025-07-15 22:45:51 +08:00
parent 5de1a43b02
commit 5a2d0fb984
19 changed files with 15019 additions and 9388 deletions

View File

@@ -66,7 +66,7 @@ class TqsdkEngine:
self.roll_over_mode = roll_over_mode
self.history_length = history_length
self.close_bar_delta = close_bar_delta
self.next_close_time = None
# Tqsdk API 和模拟器
@@ -112,15 +112,13 @@ class TqsdkEngine:
self.klines = api.get_kline_serial(
symbol, duration_seconds, data_length=history_length + 2
)
self.klines_1min = api.get_kline_serial(
symbol, 60
)
self.klines_1min = api.get_kline_serial(symbol, 60)
self.now = None
self.quote = None
if roll_over_mode:
self.quote = api.get_quote(symbol)
self.kline_row = None
self.partial_bar: Bar = None
print("TqsdkEngine: 初始化完成。")
@@ -338,14 +336,19 @@ class TqsdkEngine:
self._strategy.trading = False
is_trading_time = is_futures_trading_time()
for i in range(self.history_length + 1, 0 if not is_trading_time else 1, -1):
kline_row = self.klines.iloc[-i]
kline_dt = pd.to_datetime(kline_row.datetime, unit="ns", utc=True)
kline_dt = kline_dt.tz_convert(BEIJING_TZ)
self.main(kline_row, self.klines.iloc[-i - 1])
print(f"TqsdkEngine: 加载历史k线完成, bars数量:{len(self.all_bars)},last bar datetime:{self.all_bars[-1].datetime}")
print(
f"TqsdkEngine: 加载历史k线完成, bars数量:{len(self.all_bars)},last bar datetime:{self.all_bars[-1].datetime}"
)
for bar in self.all_bars[-5:]:
print(bar)
self._strategy.trading = True
self._last_underlying_symbol = self.quote.underlying_symbol
@@ -357,7 +360,9 @@ class TqsdkEngine:
# 初始化策略 (如果策略有 on_init 方法)
if hasattr(self._strategy, "on_init"):
self._strategy.on_init()
new_bar = False
if is_trading_time:
print(f"TqsdkEngine: 当前是交易时间处理最新一根k线")
@@ -367,10 +372,12 @@ class TqsdkEngine:
self.kline_row = kline_row
self.main(self.klines.iloc[-1], self.klines.iloc[-2])
new_bar = True
# 迭代 K 线数据
# 使用 self._api.get_kline_serial 获取到的 K 线是 Pandas DataFrame
# 直接迭代其行Bar更符合回测逻辑
print(f"TqsdkEngine: 开始等待最新数据")
while True:
# Tqsdk API 的 wait_update() 确保数据更新
@@ -383,14 +390,21 @@ class TqsdkEngine:
self._last_underlying_symbol = self.quote.underlying_symbol
if self._api.is_changing(self.klines_1min.iloc[-1], "datetime"):
kline_dt = pd.to_datetime(self.kline_row.datetime, unit="ns", utc=True)
kline_dt = kline_dt.tz_convert(BEIJING_TZ)
if self.kline_row is not None:
kline_dt = pd.to_datetime(self.kline_row.datetime, unit="ns", utc=True)
kline_dt = kline_dt.tz_convert(BEIJING_TZ)
is_close_bar = is_bar_pre_close_period(kline_dt, int(self.kline_row.duration), pre_close_minutes=3)
is_close_bar = is_bar_pre_close_period(
kline_dt, int(self.kline_row.duration), pre_close_minutes=3
)
if is_close_bar:
print(f'TqsdkEngine: close bar, kline_dt:{kline_dt}, now: {datetime.now()}')
self.close_bar(kline_row)
if is_close_bar and new_bar:
print(
f"TqsdkEngine: close bar, kline_dt:{kline_dt}, now: {datetime.now()}"
)
self.close_bar(kline_row)
new_bar = False
if self._api.is_changing(self.klines.iloc[-1], "datetime"):
kline_row = self.klines.iloc[-1]
@@ -403,6 +417,8 @@ class TqsdkEngine:
)
self.main(kline_row, self.klines.iloc[-2])
new_bar = True
def close_bar(self, kline_row):
kline_dt = pd.to_datetime(kline_row.datetime, unit="ns", utc=True)
kline_dt = kline_dt.tz_convert(BEIJING_TZ)
@@ -419,13 +435,6 @@ class TqsdkEngine:
open_oi=kline_row.open_oi,
close_oi=kline_row.close_oi,
)
self.all_bars[-1] = current_bar
self.close_list[-1] = current_bar.close
self.open_list[-1] = current_bar.open
self.high_list[-1] = current_bar.high
self.low_list[-1] = current_bar.low
self.volume_list[-1] = current_bar.volume
self.last_processed_bar = current_bar
@@ -436,64 +445,37 @@ class TqsdkEngine:
self._process_queued_requests()
def main(self, kline_row, prev_kline_row):
if True:
kline_dt = pd.to_datetime(prev_kline_row.datetime, unit="ns", utc=True)
kline_dt = kline_dt.tz_convert(BEIJING_TZ)
if len(self.all_bars) > 0:
# 创建 core_data.Bar 对象
current_bar = Bar(
datetime=kline_dt,
symbol=self._last_underlying_symbol,
open=prev_kline_row.open,
high=prev_kline_row.high,
low=prev_kline_row.low,
close=prev_kline_row.close,
volume=prev_kline_row.volume,
open_oi=prev_kline_row.open_oi,
close_oi=prev_kline_row.close_oi,
)
self.all_bars[-1] = current_bar
kline_dt = pd.to_datetime(kline_row.datetime, unit="ns", utc=True)
kline_dt = kline_dt.tz_convert(BEIJING_TZ)
self.close_list[-1] = current_bar.close
self.open_list[-1] = current_bar.open
self.high_list[-1] = current_bar.high
self.low_list[-1] = current_bar.low
self.volume_list[-1] = current_bar.volume
self.last_processed_bar = current_bar
# if self._strategy.trading is True:
# self._strategy.on_close_bar(current_bar)
# # 处理订单和取消请求
# self._process_queued_requests()
# on open bar --------------------------------------
# 创建 core_data.Bar 对象
kline_dt = pd.to_datetime(kline_row.datetime, unit="ns", utc=True)
kline_dt = kline_dt.tz_convert(BEIJING_TZ)
current_bar = Bar(
datetime=kline_dt,
symbol=self._last_underlying_symbol,
open=kline_row.open,
high=kline_row.high,
low=kline_row.low,
close=kline_row.close,
volume=kline_row.volume,
open_oi=kline_row.open_oi,
close_oi=kline_row.close_oi,
if self.partial_bar is not None:
last_bar = Bar(
datetime=pd.to_datetime(prev_kline_row.datetime, unit="ns", utc=True).tz_convert(BEIJING_TZ),
symbol=self.partial_bar.symbol,
open=prev_kline_row.open,
high=prev_kline_row.high,
low=prev_kline_row.low,
close=prev_kline_row.close,
volume=prev_kline_row.volume,
open_oi=prev_kline_row.open_oi,
close_oi=prev_kline_row.close_oi,
)
# 设置当前 Bar 到 Context
self._context.set_current_bar(current_bar)
self.all_bars.append(last_bar)
self.close_list.append(last_bar.close)
self.open_list.append(last_bar.open)
self.high_list.append(last_bar.high)
self.low_list.append(last_bar.low)
self.volume_list.append(last_bar.volume)
self.last_processed_bar = last_bar
# Tqsdk 的 is_changing 用于判断数据是否有变化,对于回测遍历 K 线,每次迭代都算作新 Bar
# 如果 kline_row.datetime 与上次不同,则认为是新 Bar
if (
self.roll_over_mode
and self.last_processed_bar is not None
and self._last_underlying_symbol != self.last_processed_bar.symbol
and self._strategy.trading is True
and self._strategy.trading
):
self._is_rollover_bar = True
print(
@@ -507,27 +489,22 @@ class TqsdkEngine:
self.last_processed_bar.symbol, self._last_underlying_symbol
)
else:
self._is_rollover_bar = False
self._strategy.on_open_bar(kline_row.open, self._last_underlying_symbol)
# 处理订单和取消请求
if self._strategy.trading is True:
self._process_queued_requests()
self.all_bars.append(current_bar)
self.close_list.append(current_bar.close)
self.open_list.append(current_bar.open)
self.high_list.append(current_bar.high)
self.low_list.append(current_bar.low)
self.volume_list.append(current_bar.volume)
self.last_processed_bar = current_bar
# 调用策略的 on_bar 方法
self._strategy.on_open_bar(current_bar)
# 处理订单和取消请求
if self._strategy.trading is True:
self._process_queued_requests()
# 记录投资组合快照
self._record_portfolio_snapshot(current_bar.datetime)
self.partial_bar = Bar(
datetime=kline_dt,
symbol=self.quote.underlying_symbol,
open=0,
high=0,
low=0,
close=0,
volume=0,
open_oi=0,
close_oi=0,
)
def run(self):
"""