28 浏览
0
import os, sys
sys.path.insert(0, "/Users/davidsh/tq回测")
from dotenv import load_dotenv; load_dotenv("/Users/davidsh/tq回测/.env")
import datetime as _dt
from datetime import date
from tqsdk import TqApi, TqSim, TqBacktest, TqAuth, BacktestFinished
 auth = TqAuth(os.environ["TQ_ACCOUNT"], os.environ["TQ_PASSWORD"])
api = TqApi(account=TqSim(init_balance=5_000_000),
            backtest=TqBacktest(start_dt=date(2025, 3, 4), end_dt=date(2025, 3, 5)),
            auth=auth)
 sym = "KQ.i@DCE.jm"
kline_1m = api.get_kline_serial(sym, 60, data_length=5)
quote = api.get_quote(sym)
pos = api.get_position(sym)
ordered = False
order_buy = None
order_sell = None
update_count = 0
 try:
    while True:
        api.wait_update()
        update_count += 1
         if api.is_changing(kline_1m.iloc[-1], "datetime"):
            bar = kline_1m.iloc[-2]
            bar_dt = _dt.datetime.fromtimestamp(int(bar["datetime"]) / 1e9)
             # 9:04 收盘时下单(即 9:05 这根 bar 刚开始时)
            if bar_dt.hour == 9 and bar_dt.minute == 4 and not ordered:
                ordered = True
                new_bar = kline_1m.iloc[-1]
                limit_buy  = float(new_bar["open"]) + 3 * quote.price_tick
                limit_sell = float(new_bar["open"]) - 3 * quote.price_tick
                print(f"[update#{update_count}] 9:04 收盘,触发下单")
                print(f"  9:04 bar: O={bar['open']:.1f} H={bar['high']:.1f} L={bar['low']:.1f} C={bar['close']:.1f}")
                print(f"  9:05 new bar open={new_bar['open']:.1f}")
                print(f"  quote: last={quote.last_price:.1f} bid1={quote.bid_price1:.1f} ask1={quote.ask_price1:.1f}")
                print(f"  BUY  limit={limit_buy:.1f}  (open+3tick)")
                print(f"  SELL limit={limit_sell:.1f}  (open-3tick)")
                order_buy  = api.insert_order(sym, direction="BUY",  offset="OPEN", volume=1, limit_price=limit_buy)
                order_sell = api.insert_order(sym, direction="SELL", offset="OPEN", volume=1, limit_price=limit_sell)
                print(f"  下单后: buy.status={order_buy.status}  sell.status={order_sell.status}")
         # 下单后每次 wait_update 打印状态,直到两单都结束
        if ordered and order_buy is not None:
            bar_new = kline_1m.iloc[-1]
            new_dt = _dt.datetime.fromtimestamp(int(bar_new["datetime"]) / 1e9)
            if new_dt.hour == 9 and new_dt.minute in (5, 6):
                print(f"[update#{update_count}] bar={new_dt.strftime('%H:%M')} "
                      f"OHLC={bar_new['open']:.1f}/{bar_new['high']:.1f}/{bar_new['low']:.1f}/{bar_new['close']:.1f} "
                      f"bid1={quote.bid_price1:.1f} ask1={quote.ask_price1:.1f} "
                      f"buy={order_buy.status} sell={order_sell.status} "
                      f"pos_long={pos.pos_long} pos_short={pos.pos_short}")
         if ordered and order_buy is not None:
            if api.is_changing(order_buy, "status") and order_buy.status == "FINISHED":
                trade = list(order_buy.trade_records.values())[-1] if order_buy.trade_records else None
                print(f"[update#{update_count}] BUY 成交! price={trade['price'] if trade else 'N/A'}")
            if api.is_changing(order_sell, "status") and order_sell.status == "FINISHED":
                trade = list(order_sell.trade_records.values())[-1] if order_sell.trade_records else None
                print(f"[update#{update_count}] SELL 成交! price={trade['price'] if trade else 'N/A'}")
         if ordered and order_buy is not None and order_buy.status == "FINISHED" and order_sell.status == "FINISHED":
            break
 except BacktestFinished:
    pass
finally:
    api.close()


请看,我订阅了1分钟的k线数据,9:04 这根k线结束的时候,实际就是9:05 这根k线开盘状态时委托下单,但是实际的撮合成交 是在9:05结束,即9:06开盘状态时才成交

[update#252] 9:04 收盘,触发下单
9:04 bar: O=1111.1 H=1111.6 L=1105.4 C=1106.2
9:05 new bar open=1106.2
quote: last=1106.2 bid1=1105.7 ask1=1106.7
BUY limit=1107.7 (open+3tick)
SELL limit=1104.7 (open-3tick)
下单后: buy.status=ALIVE sell.status=ALIVE
[update#252] bar=09:05 OHLC=1106.2/1106.2/1106.2/1106.2 bid1=1105.7 ask1=1106.7 buy=ALIVE sell=ALIVE pos_long=0 pos_short=0
[update#253] bar=09:05 OHLC=1106.2/1106.2/1106.2/1106.2 bid1=1105.7 ask1=1106.7 buy=ALIVE sell=ALIVE pos_long=0 pos_short=0
[update#254] bar=09:05 OHLC=1106.2/1107.6/1105.1/1107.1 bid1=1106.6 ask1=1107.6 buy=ALIVE sell=ALIVE pos_long=0 pos_short=0
[update#255] bar=09:05 OHLC=1106.2/1107.6/1105.1/1107.1 bid1=1106.6 ask1=1107.6 buy=ALIVE sell=ALIVE pos_long=0 pos_short=0
INFO – 模拟交易下单 TQSIM, PYSDK_insert_85893b2066de771dc978a597650bef30: 时间: 2025-03-04 09:06:00.000000, 合约: KQ.i@DCE.jm, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1107.7
INFO – 模拟交易委托单 TQSIM, PYSDK_insert_85893b2066de771dc978a597650bef30: 全部成交
INFO – 模拟交易下单 TQSIM, PYSDK_insert_556b9c3df4bb2631acfb0c65e91b671d: 时间: 2025-03-04 09:06:00.000000, 合约: KQ.i@DCE.jm, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1104.7
INFO – 模拟交易委托单 TQSIM, PYSDK_insert_556b9c3df4bb2631acfb0c65e91b671d: 全部成交
[update#256] bar=09:06 OHLC=1107.1/1107.1/1107.1/1107.1 bid1=1106.6 ask1=1107.6 buy=FINISHED sell=FINISHED pos_long=1 pos_short=1
[update#256] BUY 成交! price=1107.7
[update#256] SELL 成交! price=1104.7
INFO – 模拟交易成交记录, 账户: TQSIM

chaos 已回答的问题 6小时 前
0

insert_order() 不是立刻撮合,而是下一次 wait_update() 才真正发出
回测中K线只在开始和结束的时候才更新,下一次wait_update也更新了K线的状态,然后基于这个K线的行情来撮合,所以可能表现为你描述的那样

chaos 已回答的问题 6小时 前
您正在查看1个答案中的1个,单击此处查看所有答案。