1、新增SMCPureH1LongStrategy策略
2、修复实盘bug
This commit is contained in:
@@ -4,7 +4,7 @@ import asyncio
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Literal, Type, Dict, Any, List, Optional
|
||||
import pandas as pd
|
||||
import uuid
|
||||
import time
|
||||
|
||||
# 导入你提供的 core_data 中的类型
|
||||
from src.common_utils import is_bar_pre_close_period, is_futures_trading_time
|
||||
@@ -74,9 +74,10 @@ class TqsdkEngine:
|
||||
self._api: TqApi = api
|
||||
|
||||
# 从策略参数中获取主symbol,TqsdkContext 需要知道它
|
||||
self.symbol: str = strategy_params.get("symbol")
|
||||
if not self.symbol:
|
||||
raise ValueError("strategy_params 必须包含 'symbol' 字段")
|
||||
# self.symbol: str = strategy_params.get("symbol")
|
||||
# if not self.symbol:
|
||||
# raise ValueError("strategy_params 必须包含 'symbol' 字段")
|
||||
self.symbol = symbol
|
||||
|
||||
# 获取 K 线数据(Tqsdk 自动处理)
|
||||
# 这里假设策略所需 K 线周期在 strategy_params 中,否则默认60秒(1分钟K线)
|
||||
@@ -119,6 +120,9 @@ class TqsdkEngine:
|
||||
self.quote = api.get_quote(symbol)
|
||||
|
||||
self.partial_bar: Bar = None
|
||||
self.kline_row = None
|
||||
|
||||
self.target_pos_dict = {}
|
||||
|
||||
print("TqsdkEngine: 初始化完成。")
|
||||
|
||||
@@ -161,68 +165,53 @@ class TqsdkEngine:
|
||||
if "SHFE" in order_to_send.symbol:
|
||||
tqsdk_offset = "OPEN"
|
||||
|
||||
try:
|
||||
tq_order = self._api.insert_order(
|
||||
symbol=order_to_send.symbol,
|
||||
direction=tqsdk_direction,
|
||||
offset=tqsdk_offset,
|
||||
volume=order_to_send.volume,
|
||||
# Tqsdk 市价单 limit_price 设为 None,限价单则传递价格
|
||||
limit_price=(
|
||||
order_to_send.limit_price
|
||||
if order_to_send.price_type == "LIMIT"
|
||||
# else self.quote.bid_price1 + (1 if tqsdk_direction == "BUY" else -1)
|
||||
else (
|
||||
self.quote.bid_price1
|
||||
if tqsdk_direction == "SELL"
|
||||
else self.quote.ask_price1
|
||||
)
|
||||
),
|
||||
)
|
||||
# 更新原始 Order 对象与 Tqsdk 的订单ID和状态
|
||||
order_to_send.id = tq_order.order_id
|
||||
# order_to_send.order_id = tq_order.order_id
|
||||
# order_to_send.status = tq_order.status
|
||||
order_to_send.submitted_time = pd.to_datetime(
|
||||
tq_order.insert_date_time, unit="ns", utc=True
|
||||
)
|
||||
if "CLOSE" in order_to_send.direction:
|
||||
current_positions = self._context.get_current_positions()
|
||||
current_pos_volume = current_positions.get(order_to_send.symbol, 0)
|
||||
|
||||
# 等待订单状态更新(成交/撤销/报错)
|
||||
# 在 Tqsdk 中,订单和成交是独立的,通常在 wait_update() 循环中通过 api.is_changing() 检查
|
||||
# 这里为了模拟同步处理,直接等待订单状态最终确定
|
||||
# 注意:实际回测中,不应在这里长时间阻塞,而应在主循环中持续 wait_update
|
||||
# 为了简化适配,这里模拟即时处理,但可能与真实异步行为有差异。
|
||||
# 更健壮的方式是在主循环中通过订单状态回调更新
|
||||
# 这里我们假设订单会很快更新状态,或者在下一个 wait_update() 周期中被检测到
|
||||
self._api.wait_update() # 等待一次更新
|
||||
target_volume = None
|
||||
if order_to_send.direction == 'CLOSE_LONG':
|
||||
target_volume = current_pos_volume - order_to_send.volume
|
||||
elif order_to_send.direction == 'CLOSE_SHORT':
|
||||
target_volume = current_pos_volume + order_to_send.volume
|
||||
|
||||
# # 检查最终订单状态和成交
|
||||
# if tq_order.status == "FINISHED":
|
||||
# # 查找对应的成交记录
|
||||
# for trade_id, tq_trade in self._api.get_trade().items():
|
||||
# if tq_trade.order_id == tq_order.order_id and tq_trade.volume > 0: # 确保是实际成交
|
||||
# # 创建 core_data.Trade 对象
|
||||
# trade = Trade(
|
||||
# order_id=tq_trade.order_id,
|
||||
# fill_time=tafunc.get_datetime_from_timestamp(tq_trade.trade_date_time) if tq_trade.trade_date_time else datetime.now(),
|
||||
# symbol=order_to_send.symbol, # 使用 Context 中的 symbol
|
||||
# direction=tq_trade.direction, # 实际成交方向
|
||||
# volume=tq_trade.volume,
|
||||
# price=tq_trade.price,
|
||||
# commission=tq_trade.commission,
|
||||
# cash_after_trade=self._api.get_account().available,
|
||||
# positions_after_trade=self._context.get_current_positions(),
|
||||
# realized_pnl=tq_trade.realized_pnl, # Tqsdk TqTrade 对象有 realized_pnl
|
||||
# is_open_trade=tq_trade.offset == "OPEN",
|
||||
# is_close_trade=tq_trade.offset in ["CLOSE", "CLOSETODAY", "CLOSEYESTERDAY"]
|
||||
# )
|
||||
# self.trade_history.append(trade)
|
||||
# print(f"Engine: 成交记录: {trade}")
|
||||
# break # 找到成交就跳出
|
||||
# order_to_send.status = tq_order.status # 更新最终状态
|
||||
except Exception as e:
|
||||
print(f"Engine: 发送订单 {order_to_send.id} 失败: {e}")
|
||||
# order_to_send.status = "ERROR"
|
||||
if target_volume is not None:
|
||||
if order_to_send.symbol not in self.target_pos_dict:
|
||||
self.target_pos_dict[order_to_send.symbol] = TargetPosTask(self._api, order_to_send.symbol)
|
||||
|
||||
self.target_pos_dict[order_to_send.symbol].set_target_volume(target_volume)
|
||||
else:
|
||||
try:
|
||||
tq_order = self._api.insert_order(
|
||||
symbol=order_to_send.symbol,
|
||||
direction=tqsdk_direction,
|
||||
offset=tqsdk_offset,
|
||||
volume=order_to_send.volume,
|
||||
# Tqsdk 市价单 limit_price 设为 None,限价单则传递价格
|
||||
limit_price=(
|
||||
order_to_send.limit_price
|
||||
if order_to_send.price_type == "LIMIT"
|
||||
# else self.quote.bid_price1 + (1 if tqsdk_direction == "BUY" else -1)
|
||||
else (
|
||||
self.quote.bid_price1
|
||||
if tqsdk_direction == "SELL"
|
||||
else self.quote.ask_price1
|
||||
)
|
||||
),
|
||||
)
|
||||
# 更新原始 Order 对象与 Tqsdk 的订单ID和状态
|
||||
order_to_send.id = tq_order.order_id
|
||||
# order_to_send.order_id = tq_order.order_id
|
||||
# order_to_send.status = tq_order.status
|
||||
order_to_send.submitted_time = pd.to_datetime(
|
||||
tq_order.insert_date_time, unit="ns", utc=True
|
||||
)
|
||||
|
||||
self._api.wait_update() # 等待一次更新
|
||||
|
||||
except Exception as e:
|
||||
print(f"Engine: 发送订单 {order_to_send.id} 失败: {e}")
|
||||
# order_to_send.status = "ERROR"
|
||||
|
||||
# 处理取消请求
|
||||
while self._context.cancel_queue:
|
||||
@@ -406,15 +395,28 @@ class TqsdkEngine:
|
||||
|
||||
new_bar = False
|
||||
|
||||
if self._api.is_changing(self.klines.iloc[-1], "open"):
|
||||
print(f"TqsdkEngine: open change!, open:{self.klines.iloc[-1].open}, now: {datetime.now()}")
|
||||
|
||||
|
||||
if self._api.is_changing(self.klines.iloc[-1], "datetime"):
|
||||
# 等待到整点-00 或 30 分且秒>1
|
||||
while True:
|
||||
now = datetime.now()
|
||||
minute = now.minute
|
||||
second = now.second
|
||||
if (minute % 30 == 0) and (second > 1):
|
||||
break
|
||||
# 小粒度休眠,防止 CPU 空转
|
||||
time.sleep(0.1)
|
||||
|
||||
# 到这里一定满足“整点-00/30 且秒>1”
|
||||
kline_row = self.klines.iloc[-1]
|
||||
kline_dt = pd.to_datetime(kline_row.datetime, unit="ns", utc=True)
|
||||
kline_dt = kline_dt.tz_convert(BEIJING_TZ)
|
||||
self.kline_row = kline_row
|
||||
|
||||
print(
|
||||
f"TqsdkEngine: 新k线产生,k line datetime:{kline_dt}, now: {datetime.now()}"
|
||||
)
|
||||
print(f"TqsdkEngine: 新k线产生, k line datetime:{kline_dt}, now: {datetime.now()}")
|
||||
self.main(kline_row, self.klines.iloc[-2])
|
||||
|
||||
new_bar = True
|
||||
|
||||
Reference in New Issue
Block a user