new update
This commit is contained in:
+1
-13
@@ -1,22 +1,10 @@
|
||||
# 定义事件处理函数
|
||||
ActionEventEnableTrade = "enable_trade"
|
||||
ResultEventTradeEnabled = "trade_enabled"
|
||||
ActionEventDisableTrade = "disable_trade"
|
||||
ResultEventTradeDisabled = "trade_disabled"
|
||||
|
||||
# 市场数据监听控制事件
|
||||
MarketDataUpdate = "market_data_update"
|
||||
ActionEnableMarketData = "enable_market_data"
|
||||
ActionDisableMarketData = "disable_market_data"
|
||||
MarketDataEnabled = "market_data_enabled"
|
||||
MarketDataDisabled = "market_data_disabled"
|
||||
# 删除交易标的事件
|
||||
EventTradeTargetUpdate = "trade_target_update"
|
||||
ActionEventAddTradeTarget = "add_trade_target"
|
||||
ResultEventTradeTargetAdded = "trade_target_added"
|
||||
ActionEventDeleteTradeTarget = "delete_trade_target"
|
||||
ResultEventTradeTargetDeleted = "trade_target_deleted"
|
||||
# 网格修正事件
|
||||
ActionEventGridFix = "grid_fix"
|
||||
# Pring Log
|
||||
EventPrintLog = "print_log"
|
||||
|
||||
|
||||
@@ -76,6 +76,13 @@ class QmtV(XtQuantTraderCallback):
|
||||
orderRemark # remark # type: ignore
|
||||
)
|
||||
|
||||
def getInstrumentName(self, stock_code:str):
|
||||
# print(f"getInstrumentName: 获取标的名称 {stock_code}")
|
||||
detail = xtdata.get_instrument_detail(stock_code, False)
|
||||
if detail is None:
|
||||
return None
|
||||
return detail['InstrumentName']
|
||||
|
||||
# def print_position_info(self):
|
||||
# positions:list[XtPosition] = self.xt_trader.query_stock_positions(self.account)
|
||||
# if positions:
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# 删除交易标的事件
|
||||
EventTradeTargetUpdate = "trade_target_update"
|
||||
ActionEventAddTradeTarget = "add_trade_target"
|
||||
ResultEventTradeTargetAdded = "trade_target_added"
|
||||
ActionEventDeleteTradeTarget = "delete_trade_target"
|
||||
ResultEventTradeTargetDeleted = "trade_target_deleted"
|
||||
# 网格修正事件
|
||||
ActionEventGridFix = "grid_fix"
|
||||
|
||||
# 定义事件处理函数
|
||||
ActionEventEnableTrade = "enable_trade"
|
||||
ResultEventTradeEnabled = "trade_enabled"
|
||||
ActionEventDisableTrade = "disable_trade"
|
||||
ResultEventTradeDisabled = "trade_disabled"
|
||||
@@ -1,6 +1,10 @@
|
||||
# coding:utf-8
|
||||
from typing import Any
|
||||
|
||||
|
||||
from core.sfgrid.model import SFGridTradeTarget as TradeTarget
|
||||
from core.eventbus import ActionDisableMarketData, ActionEnableMarketData, ActionEventAddTradeTarget, ActionEventDeleteTradeTarget, ActionEventDisableTrade, ActionEventEnableTrade, EventTradeTargetUpdate, MarketDataUpdate, MarketDataEnabled, MarketDataDisabled, ResultEventTradeDisabled, ResultEventTradeEnabled, ResultEventTradeTargetDeleted, ActionEventGridFix, event_bus
|
||||
from .bus_events import ActionEventAddTradeTarget, ActionEventDeleteTradeTarget, ActionEventDisableTrade, ActionEventEnableTrade, EventTradeTargetUpdate, ResultEventTradeDisabled, ResultEventTradeEnabled, ResultEventTradeTargetAdded, ResultEventTradeTargetDeleted, ActionEventGridFix
|
||||
from core.eventbus import event_bus, MarketDataEnabled, MarketDataDisabled, MarketDataUpdate
|
||||
from xtquant import xttrader
|
||||
from xtquant.xttrader import XtQuantTrader
|
||||
import time
|
||||
@@ -9,7 +13,7 @@ from peewee import ModelSelect
|
||||
import core.sfgrid.model as model
|
||||
import config
|
||||
from core.sfgrid.sfgrid_strategy import SFGridStrategy
|
||||
from core.util import getInstrumentName, getStockPosition, queryPendingOrder
|
||||
from core.util import getStockPosition, queryPendingOrder
|
||||
from xtquant.xttrader import XtQuantTrader
|
||||
from xtquant.xttype import StockAccount, XtAsset, XtOrder, XtPosition, XtTrade
|
||||
from xtquant import xtdata
|
||||
@@ -21,52 +25,79 @@ from core.qmt import qmtv
|
||||
from core.sfgrid.objects import GridFixData
|
||||
|
||||
# 量化核心控制对象
|
||||
class SFGridController(XtQuantTraderCallback):
|
||||
class SFGridController:
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.registerEventHandler()
|
||||
|
||||
self.listening_stock = []
|
||||
self.stock_trade_ctrl = {}
|
||||
self.init_instrument_pool(qmtv.xttrader, qmtv.account) # type: ignore
|
||||
|
||||
self.seq = None
|
||||
PrintLog(LogLevel.INFO, '- [成功]三疯交易系统初始化完成')
|
||||
self.startMarketData()
|
||||
|
||||
|
||||
def registerEventHandler(self):
|
||||
event_bus.subscribe(ActionEventEnableTrade, self.onEnableTrade)
|
||||
event_bus.subscribe(ActionEventDisableTrade, self.onDisableTrade)
|
||||
event_bus.subscribe(ActionEnableMarketData, self.onMarketDataEnabled)
|
||||
event_bus.subscribe(ActionDisableMarketData, self.onMarketDataDisabled)
|
||||
event_bus.subscribe(ActionEventAddTradeTarget, self.onAddTradeTarget)
|
||||
event_bus.subscribe(ActionEventDeleteTradeTarget, self.onDeleteTradeTarget)
|
||||
event_bus.subscribe(ActionEventGridFix, self.onGridFix)
|
||||
|
||||
def onDeleteTradeTarget(self, id: int):
|
||||
def onDeleteTradeTarget(self, target: TradeTarget):
|
||||
"""处理删除交易标的事件"""
|
||||
self.del_trade_target(id)
|
||||
# 发布删除完成事件
|
||||
event_bus.publish(ResultEventTradeTargetDeleted, id)
|
||||
id = target.get_id()
|
||||
try:
|
||||
# 从数据库中删除
|
||||
target.delete_instance()
|
||||
|
||||
PrintLog(LogLevel.INFO, f"已删除交易标的: id{id} {target.stock_code} - {target.stock_name}")
|
||||
# 发布删除完成事件
|
||||
event_bus.publish(ResultEventTradeTargetDeleted, target)
|
||||
except Exception as e:
|
||||
PrintLog(LogLevel.ERROR, f"删除交易标的失败 ID {id}: {str(e)}")
|
||||
|
||||
def onAddTradeTarget(self, stock_code: str):
|
||||
"""处理添加交易标的事件"""
|
||||
self.add_trade_target(stock_code)
|
||||
try:
|
||||
stock_name = qmtv.getInstrumentName(stock_code)
|
||||
if not stock_name:
|
||||
PrintLog(LogLevel.ERROR, f'无法获取股票代码 {stock_code} 的名称,请检查代码是否正确')
|
||||
return
|
||||
|
||||
def onMarketDataEnabled(self, data):
|
||||
"""处理市场数据监听启用事件"""
|
||||
self.startMarketData()
|
||||
# 检查是否已存在该标的
|
||||
existing_target = TradeTarget.get_or_none(TradeTarget.stock_code == stock_code)
|
||||
if existing_target:
|
||||
PrintLog(LogLevel.INFO, f'交易标的 {stock_code} {stock_name} 已存在')
|
||||
return
|
||||
|
||||
def onMarketDataDisabled(self, data):
|
||||
"""处理市场数据监听禁用事件"""
|
||||
self.stopMarketData()
|
||||
# 刷新标的持仓
|
||||
pos = qmtv.getStockPosition(stock_code) # type: ignore
|
||||
new_target = TradeTarget.create(
|
||||
stock_name=stock_name,
|
||||
stock_code=stock_code,
|
||||
market_price=0.0,
|
||||
current_position=pos,
|
||||
grid_index=0,
|
||||
last_trade_price=0.0,
|
||||
plan_buy_price=0.0,
|
||||
plan_sell_price=0.0,
|
||||
current_order_price=0.0,
|
||||
current_order_no='',
|
||||
current_order_type=''
|
||||
)
|
||||
new_target.save()
|
||||
# 更新标的池
|
||||
event_bus.publish(ResultEventTradeTargetAdded, new_target)
|
||||
|
||||
except Exception as e:
|
||||
PrintLog(LogLevel.ERROR, f'新增交易标的失败 {stock_code} {e}')
|
||||
|
||||
def onEnableTrade(self, id: int):
|
||||
self.start_stock_trade(id)
|
||||
pass
|
||||
# self.start_stock_trade(id)
|
||||
|
||||
def onDisableTrade(self, id: int):
|
||||
self.pause_stock_trade(id)
|
||||
pass
|
||||
# self.pause_stock_trade(id)
|
||||
|
||||
def onGridFix(self, data: GridFixData):
|
||||
"""处理网格修正事件"""
|
||||
@@ -82,29 +113,10 @@ class SFGridController(XtQuantTraderCallback):
|
||||
target.grid_index = grid_index
|
||||
target.save()
|
||||
|
||||
# 更新内存中的交易标的
|
||||
if target.get_id() in self.instrument_pool:
|
||||
self.instrument_pool[target.get_id()] = target
|
||||
|
||||
# 更新交易控制器中的网格信息
|
||||
if target.stock_code in self.stock_trade_ctrl:
|
||||
trade_controller: SFGridStrategy = self.stock_trade_ctrl[target.stock_code]
|
||||
trade_controller.updateGridIndex(grid_index) # type: ignore
|
||||
|
||||
PrintLog(LogLevel.INFO, f"网格修正已应用: {target.stock_code} - {target.stock_name}, 网格索引: {grid_index}")
|
||||
except Exception as e:
|
||||
PrintLog(LogLevel.ERROR, f"网格修正更新失败: {str(e)}")
|
||||
|
||||
def startMarketData(self):
|
||||
PrintLog(LogLevel.INFO, '- 启动市场数据订阅')
|
||||
|
||||
self.seq = xtdata.subscribe_whole_quote(['SH', 'SZ'], callback=self.onDataUpdate)
|
||||
if self.seq == -1:
|
||||
PrintLog(LogLevel.ERROR, '- 市场数据订阅失败')
|
||||
else:
|
||||
event_bus.publish(MarketDataEnabled, True)
|
||||
PrintLog(LogLevel.INFO, f'- 市场数据订阅成功, 订阅号={self.seq}')
|
||||
|
||||
|
||||
|
||||
def stopMarketData(self):
|
||||
@@ -115,221 +127,52 @@ class SFGridController(XtQuantTraderCallback):
|
||||
event_bus.publish(MarketDataDisabled, False)
|
||||
|
||||
|
||||
def add_trade_target(self, stock_code: str):
|
||||
try:
|
||||
stock_name = getInstrumentName(stock_code)
|
||||
if not stock_name:
|
||||
PrintLog(LogLevel.ERROR, f'无法获取股票代码 {stock_code} 的名称,请检查代码是否正确')
|
||||
return
|
||||
# # 初始化指定标的交易控制器
|
||||
# def start_stock_trade(self, tradeTarget: TradeTarget):
|
||||
# # check existing thread
|
||||
# if tradeTarget.stock_code in self.stock_trade_ctrl:
|
||||
# tradeController: SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code]
|
||||
|
||||
# 检查是否已存在该标的
|
||||
existing_target = TradeTarget.get_or_none(TradeTarget.stock_code == stock_code)
|
||||
if existing_target:
|
||||
PrintLog(LogLevel.INFO, f'交易标的 {stock_code} {stock_name} 已存在')
|
||||
return
|
||||
|
||||
new_target = TradeTarget.create(
|
||||
stock_name=stock_name,
|
||||
stock_code=stock_code,
|
||||
market_price=0.0,
|
||||
current_position=0,
|
||||
grid_index=0,
|
||||
last_trade_price=0.0,
|
||||
plan_buy_price=0.0,
|
||||
plan_sell_price=0.0,
|
||||
current_order_price=0.0,
|
||||
current_order_no='',
|
||||
current_order_type=''
|
||||
)
|
||||
new_target.save()
|
||||
PrintLog(LogLevel.INFO, f'新增交易标的 {stock_code} {stock_name}, {new_target.id}')
|
||||
# 刷新标的持仓
|
||||
pos = getStockPosition(stock_code, self.xt_trader, self.account) # type: ignore
|
||||
TradeTarget.update(current_position=pos).where(TradeTarget.stock_code == stock_code).execute()
|
||||
# 更新标的池
|
||||
self.refresh_targets()
|
||||
# 添加交易控制器
|
||||
stockTradeController = SFGridStrategy(new_target, self.xt_trader, self.account) # type: ignore
|
||||
self.stock_trade_ctrl[stock_code] = stockTradeController
|
||||
|
||||
except Exception as e:
|
||||
PrintLog(LogLevel.ERROR, f'新增交易标的失败 {stock_code} {e}')
|
||||
# tradeTarget = tradeController.enabledTrading(True)
|
||||
# self.instrument_pool[id] = tradeTarget
|
||||
# event_bus.publish(ResultEventTradeEnabled, tradeTarget)
|
||||
# else:
|
||||
# PrintLog(LogLevel.INFO, f"\t创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}")
|
||||
|
||||
|
||||
def del_trade_target(self, id:int):
|
||||
try:
|
||||
# 检查标的是否存在
|
||||
if id not in self.instrument_pool:
|
||||
PrintLog(LogLevel.ERROR, f"交易标的 ID {id} 不存在")
|
||||
return
|
||||
|
||||
target: TradeTarget = self.instrument_pool[id]
|
||||
|
||||
# 如果存在交易控制器,先停止交易
|
||||
if target.stock_code in self.stock_trade_ctrl:
|
||||
# 停止交易控制器
|
||||
del self.stock_trade_ctrl[target.stock_code]
|
||||
|
||||
# 从数据库中删除
|
||||
target.delete_instance()
|
||||
|
||||
# 从内存中删除
|
||||
del self.instrument_pool[id]
|
||||
|
||||
# 刷新标的池
|
||||
self.refresh_targets()
|
||||
|
||||
PrintLog(LogLevel.INFO, f"已删除交易标的: {target.stock_code} - {target.stock_name}")
|
||||
except Exception as e:
|
||||
PrintLog(LogLevel.ERROR, f"删除交易标的失败 ID {id}: {str(e)}")
|
||||
|
||||
def init_instrument_pool(self, xtTrader:XtQuantTrader, account:StockAccount):
|
||||
self.refresh_targets()
|
||||
|
||||
for id in self.instrument_pool:
|
||||
target:TradeTarget = self.instrument_pool[id]
|
||||
status = "新建" if target.status == 0 else "已建初始仓"
|
||||
PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {getStockPosition(target.stock_code, self.xt_trader, self.account)} 网格索引: {target.grid_index} 基准价格 {config.grid_price[target.grid_index]} 状态: {status} 启用交易线程: {'自动交易中' if target.enabled else '交易已停止'}') # type: ignore
|
||||
|
||||
tradeTarget:TradeTarget = self.instrument_pool[id]
|
||||
tradeTarget.current_position = getStockPosition(tradeTarget.stock_code, xtTrader, account) # type: ignore
|
||||
result = tradeTarget.save()
|
||||
PrintLog(LogLevel.INFO, f' |- 同步[{target.stock_code}-{target.stock_name}]持仓信息[{'成功' if result == 1 else '失败'}]')
|
||||
stockTradeController = SFGridStrategy(tradeTarget, self.xt_trader, self.account) # type: ignore
|
||||
self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController
|
||||
event_bus.publish(EventTradeTargetUpdate, tradeTarget)
|
||||
|
||||
PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.instrument_pool)} 个标的')
|
||||
|
||||
|
||||
def refresh_targets(self):
|
||||
# 更新标的池
|
||||
results:ModelSelect = TradeTarget.select()
|
||||
self.instrument_pool: dict[int, TradeTarget] = {}
|
||||
for temp in results:
|
||||
result :TradeTarget = temp
|
||||
self.instrument_pool[result.get_id()] = result
|
||||
|
||||
|
||||
# 初始化指定标的交易控制器
|
||||
def start_stock_trade(self, id: int):
|
||||
tradeTarget: TradeTarget = self.instrument_pool[id]
|
||||
# check existing thread
|
||||
if tradeTarget.stock_code in self.stock_trade_ctrl:
|
||||
tradeController: SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code]
|
||||
|
||||
tradeTarget = tradeController.enabledTrading(True)
|
||||
self.instrument_pool[id] = tradeTarget
|
||||
event_bus.publish(ResultEventTradeEnabled, tradeTarget)
|
||||
else:
|
||||
PrintLog(LogLevel.INFO, f"\t创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}")
|
||||
|
||||
|
||||
def pause_stock_trade(self, id: int):
|
||||
localTarget: TradeTarget = self.instrument_pool[id]
|
||||
print(f'暂停标的交易 {localTarget.stock_code} - enabled {localTarget.enabled}')
|
||||
if localTarget.stock_code in self.stock_trade_ctrl:
|
||||
tradeController: SFGridStrategy = self.stock_trade_ctrl[localTarget.stock_code]
|
||||
tradeTarget = tradeController.enabledTrading(False)
|
||||
orders = queryPendingOrder(localTarget.stock_code, tradeController.getName(), self.xt_trader, self.account) # type: ignore
|
||||
for order in orders:
|
||||
qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id)
|
||||
print(f'取消未成交订单 {len(orders)}')
|
||||
self.instrument_pool[id] = tradeTarget
|
||||
event_bus.publish(ResultEventTradeDisabled, tradeTarget)
|
||||
else:
|
||||
print(f"标的交易控制器不存在 {localTarget.stock_code} {localTarget.stock_name}\n")
|
||||
# def pause_stock_trade(self, id: int):
|
||||
# localTarget: TradeTarget = self.instrument_pool[id]
|
||||
# print(f'暂停标的交易 {localTarget.stock_code} - enabled {localTarget.enabled}')
|
||||
# if localTarget.stock_code in self.stock_trade_ctrl:
|
||||
# tradeController: SFGridStrategy = self.stock_trade_ctrl[localTarget.stock_code]
|
||||
# tradeTarget = tradeController.enabledTrading(False)
|
||||
# orders = queryPendingOrder(localTarget.stock_code, tradeController.getName(), self.xt_trader, self.account) # type: ignore
|
||||
# for order in orders:
|
||||
# qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id)
|
||||
# print(f'取消未成交订单 {len(orders)}')
|
||||
# self.instrument_pool[id] = tradeTarget
|
||||
# event_bus.publish(ResultEventTradeDisabled, tradeTarget)
|
||||
# else:
|
||||
# print(f"标的交易控制器不存在 {localTarget.stock_code} {localTarget.stock_name}\n")
|
||||
|
||||
|
||||
# ====== 市场回调方法 -- 以下方法由XtQuantData调用 ======
|
||||
def onDataUpdate(self, data):
|
||||
# 收集所有市场数据用于市场监控
|
||||
for stock_code, tickData in data.items():
|
||||
if stock_code in self.stock_trade_ctrl:
|
||||
stock_controller: SFGridStrategy = self.stock_trade_ctrl[stock_code]
|
||||
stock_controller.onDataUpdate(data)
|
||||
else:
|
||||
# 非目标交易,发布市场数据更新事件用于市场监控
|
||||
lastPrice = tickData['lastPrice']
|
||||
if lastPrice == 10 or stock_code in self.listening_stock:
|
||||
# 发布市场数据更新事件用于市场监控
|
||||
market_target = TradeTarget()
|
||||
market_target.stock_code = stock_code
|
||||
market_target.stock_name = getInstrumentName(stock_code) # type: ignore
|
||||
market_target.market_price = lastPrice # type: ignore
|
||||
event_bus.publish(MarketDataUpdate, market_target)
|
||||
if stock_code not in self.listening_stock:
|
||||
self.listening_stock.append(stock_code)
|
||||
# def onDataUpdate(self, data):
|
||||
# # 收集所有市场数据用于市场监控
|
||||
# for stock_code, tickData in data.items():
|
||||
# if stock_code in self.stock_trade_ctrl:
|
||||
# stock_controller: SFGridStrategy = self.stock_trade_ctrl[stock_code]
|
||||
# stock_controller.onDataUpdate(data)
|
||||
# else:
|
||||
# # 非目标交易,发布市场数据更新事件用于市场监控
|
||||
# lastPrice = tickData['lastPrice']
|
||||
# if lastPrice == 10 or stock_code in self.listening_stock:
|
||||
# # 发布市场数据更新事件用于市场监控
|
||||
# market_target = TradeTarget()
|
||||
# market_target.stock_code = stock_code
|
||||
# market_target.stock_name = getInstrumentName(stock_code) # type: ignore
|
||||
# market_target.market_price = lastPrice # type: ignore
|
||||
# event_bus.publish(MarketDataUpdate, market_target)
|
||||
# if stock_code not in self.listening_stock:
|
||||
# self.listening_stock.append(stock_code)
|
||||
|
||||
|
||||
# ====== 市场回调方法 -- 以下方法由XtQuantTrader调用 ======
|
||||
def on_connected(self):
|
||||
"""
|
||||
连接成功推送
|
||||
"""
|
||||
print(datetime.datetime.now(), '连接成功回调')
|
||||
|
||||
def on_disconnected(self):
|
||||
"""
|
||||
连接断开
|
||||
:return:
|
||||
"""
|
||||
print(datetime.datetime.now(), '连接断开回调')
|
||||
|
||||
def on_stock_order(self, order:XtOrder):
|
||||
"""
|
||||
委托回报推送
|
||||
:param order: XtOrder对象
|
||||
:return:
|
||||
"""
|
||||
print(f'orderd {order.strategy_name}-{order.stock_code} {order.order_id} {order.order_volume}-{order.order_status}')
|
||||
stockCode = order.stock_code
|
||||
ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode]
|
||||
# 如果存在对应的StockTradeController,则调用其onDataUpdate方法
|
||||
if ctrl is not None and order.strategy_name == ctrl.getName():
|
||||
print(f'controller info {ctrl.getName()}')
|
||||
ctrl.onAsyncOrderResponse(order) # type: ignore
|
||||
else:
|
||||
print(f"委托下单回调 投资备注 orderId: {order.order_sysid} [{order.stock_code}-{order.instrument_name}] volume: {order.order_volume} 订单策略: '{order.strategy_name}'<-->'{ctrl.getName()}'")
|
||||
|
||||
|
||||
def on_stock_trade(self, trade:XtTrade):
|
||||
"""
|
||||
成交变动推送
|
||||
:param trade: XtTrade对象
|
||||
:return:
|
||||
"""
|
||||
stockCode = trade.stock_code
|
||||
ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode]
|
||||
# 如果存在对应的StockTradeController,则调用其onDataUpdate方法
|
||||
if ctrl is not None and trade.strategy_name == ctrl.getName():
|
||||
ctrl.onOrderTrade(trade)
|
||||
else:
|
||||
print(f"委托回调 投资备注 {trade.strategy_name} 不匹配 {ctrl.getName()}")
|
||||
|
||||
# def on_order_stock_async_response(self, response:XtOrderResponse):
|
||||
# stockCode = response.order_remark
|
||||
# ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode]
|
||||
# # 如果存在对应的StockTradeController,则调用其onDataUpdate方法
|
||||
# if ctrl is not None and response.strategy_name == ctrl.getName():
|
||||
# ctrl.onAsyncOrderResponse(response)
|
||||
# else:
|
||||
# print(f"委托回调 投资备注 {response.strategy_name} 不匹配 {ctrl.getName()}")
|
||||
|
||||
def on_order_error(self, order_error):
|
||||
"""
|
||||
委托失败推送
|
||||
:param order_error:XtOrderError 对象
|
||||
:return:
|
||||
"""
|
||||
# print("on order_error callback")
|
||||
# print(order_error.order_id, order_error.error_id, order_error.error_msg)
|
||||
print(f"\n委托报错回调 {order_error.order_remark} {order_error.error_msg}")
|
||||
|
||||
|
||||
def on_account_status(self, status):
|
||||
"""
|
||||
:param response: XtAccountStatus 对象
|
||||
:return:
|
||||
"""
|
||||
print(datetime.datetime.now(), status)
|
||||
@@ -1,12 +1,13 @@
|
||||
from core.qmt import qmtv
|
||||
from core.sfgrid.bus_events import EventTradeTargetUpdate
|
||||
import core.sfgrid.model as model
|
||||
from core import constants
|
||||
from core.eventbus import EventTradeTargetUpdate, event_bus
|
||||
from core.eventbus import event_bus
|
||||
from core.constants import OrderTypeBuy, OrderTypeInit, OrderTypeSell
|
||||
from core.util import queryPendingOrder, is_trading_time
|
||||
|
||||
from xtquant import xttrader, xtconstant
|
||||
from xtquant.xttype import StockAccount, XtOrder, XtTrade
|
||||
from xtquant import xtconstant
|
||||
from xtquant.xttype import XtOrder, XtTrade
|
||||
import config
|
||||
import threading
|
||||
|
||||
|
||||
+22
-46
@@ -7,25 +7,28 @@ import threading
|
||||
import time
|
||||
import core.eventbus as eBus
|
||||
from core.logger import LogLevel, PrintLog
|
||||
from core.sfgrid.bus_events import ActionEventAddTradeTarget, ActionEventDeleteTradeTarget, ActionEventDisableTrade, ActionEventEnableTrade, ActionEventGridFix, EventTradeTargetUpdate, ResultEventTradeTargetAdded, ResultEventTradeTargetDeleted
|
||||
from core.sfgrid.model import SFGridTradeTarget
|
||||
import configparser
|
||||
import config
|
||||
from core.sfgrid.objects import GridFixData
|
||||
from core.qmt import qmtv
|
||||
from core.sfgrid.sfgrid_controller import SFGridController
|
||||
from core.sfgrid.sfgrid_strategy import SFGridStrategy
|
||||
|
||||
|
||||
class TradeTargetUI(ttk.Frame):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.controller = SFGridController()
|
||||
|
||||
self.tradeTargetData:dict[int, SFGridTradeTarget] = {} # id->trade_target
|
||||
self.strategy_ctrl:dict[str, SFGridStrategy] = {} # stock_code->trade_target
|
||||
self.strategy_ctrl:dict[int, SFGridStrategy] = {} # stock_code->trade_target
|
||||
self.init_trade_target_pool()
|
||||
self.registerEventHandler()
|
||||
|
||||
# 创建刷新线程标志
|
||||
self.refresh_thread_running = True # 默认不启动刷新线程
|
||||
self.refresh_thread_running = False # 默认不启动刷新线程
|
||||
|
||||
# 市场监控数据
|
||||
self.marketData: dict[str, Any] = {} # 存储市场数据 {stock_code: {stock_name, last_price, time}}
|
||||
@@ -33,6 +36,8 @@ class TradeTargetUI(ttk.Frame):
|
||||
# 创建界面
|
||||
self.create_ui()
|
||||
|
||||
self.start_ui_refresh()
|
||||
|
||||
def refresh_targets(self):
|
||||
# 更新标的池
|
||||
results = SFGridTradeTarget.select()
|
||||
@@ -52,20 +57,21 @@ class TradeTargetUI(ttk.Frame):
|
||||
result = tradeTarget.save()
|
||||
PrintLog(LogLevel.INFO, f' |- 同步[{tradeTarget.stock_code}-{tradeTarget.stock_name}]持仓信息[{'成功' if result == 1 else '失败'}]')
|
||||
stockTradeController = SFGridStrategy(tradeTarget) # type: ignore
|
||||
self.strategy_ctrl[tradeTarget.stock_code] = stockTradeController # pyright: ignore[reportArgumentType]
|
||||
self.strategy_ctrl[id] = stockTradeController # pyright: ignore[reportArgumentType]
|
||||
# eBus.event_bus.publish(eBus.EventTradeTargetUpdate, tradeTarget)
|
||||
|
||||
PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的')
|
||||
|
||||
|
||||
def registerEventHandler(self):
|
||||
# eBus.event_bus.subscribe(eBus.EventTradeTargetUpdate, self.onTradeTargetUpdated)
|
||||
eBus.event_bus.subscribe(EventTradeTargetUpdate, self.onTradeTargetUpdated)
|
||||
# eBus.event_bus.subscribe(eBus.MarketDataUpdate, self.onMarketDataUpdated)
|
||||
# eBus.event_bus.subscribe(eBus.ResultEventTradeEnabled, self.onTradeEnabled)
|
||||
# eBus.event_bus.subscribe(eBus.ResultEventTradeDisabled, self.onTradeDisabled)
|
||||
# eBus.event_bus.subscribe(eBus.MarketDataEnabled, self.onMarketDataToggled)
|
||||
# eBus.event_bus.subscribe(eBus.MarketDataDisabled, self.onMarketDataToggled)
|
||||
eBus.event_bus.subscribe(eBus.ResultEventTradeTargetDeleted, self.onTradeTargetDeleted)
|
||||
eBus.event_bus.subscribe(ResultEventTradeTargetDeleted, self.onTradeTargetDeleted)
|
||||
eBus.event_bus.subscribe(ResultEventTradeTargetAdded, self.onTradeTargetUpdated)
|
||||
|
||||
def start_refresh_thread(self):
|
||||
"""启动刷新线程"""
|
||||
@@ -84,22 +90,17 @@ class TradeTargetUI(ttk.Frame):
|
||||
"""停止刷新线程"""
|
||||
self.refresh_thread_running = False
|
||||
|
||||
def onTradeTargetDeleted(self, id: int):
|
||||
def onTradeTargetDeleted(self, target: SFGridTradeTarget):
|
||||
"""处理交易标的删除完成事件"""
|
||||
# 从本地数据中删除
|
||||
id = target.get_id()
|
||||
if id in self.tradeTargetData:
|
||||
PrintLog(LogLevel.DEBUG, f"删除交易标的,ID: {id}")
|
||||
del self.tradeTargetData[id]
|
||||
del self.strategy_ctrl[id]
|
||||
# 添加日志
|
||||
PrintLog(LogLevel.INFO, f"交易标的已删除,ID: {id}")
|
||||
|
||||
def onMarketDataToggled(self, data:bool):
|
||||
self.market_data_enabled = self.market_data_switch_var.get()
|
||||
PrintLog(LogLevel.INFO, "市场数据监听已" + ("启用" if data else "禁用"))
|
||||
# 同步UI刷新线程状态
|
||||
if data:
|
||||
self.start_ui_refresh()
|
||||
else:
|
||||
self.stop_ui_refresh()
|
||||
|
||||
def onTradeEnabled(self, target:SFGridTradeTarget):
|
||||
PrintLog(LogLevel.INFO, f"交易启用: {target.stock_code} - {target.stock_name}")
|
||||
@@ -147,33 +148,9 @@ class TradeTargetUI(ttk.Frame):
|
||||
# 添加分隔符
|
||||
ttk.Separator(toolbar_frame, orient='vertical').pack(side=tk.LEFT, fill=tk.Y, padx=10)
|
||||
|
||||
# 市场数据监听开关
|
||||
self.market_data_switch_var = tk.BooleanVar(value=False)
|
||||
# self.market_data_switch = ttk.Checkbutton(
|
||||
# toolbar_frame,
|
||||
# text="📊 市场数据",
|
||||
# variable=self.market_data_switch_var,
|
||||
# command=self.toggle_market_data,
|
||||
# width=12
|
||||
# )
|
||||
# self.market_data_switch.pack(side=tk.LEFT, padx=2)
|
||||
|
||||
# 表格区域
|
||||
self.create_tables_area(main_frame)
|
||||
|
||||
def toggle_market_data(self):
|
||||
"""切换市场数据监听状态"""
|
||||
print(f'市场数据监听开关')
|
||||
self.market_data_enabled = self.market_data_switch_var.get()
|
||||
if self.market_data_enabled:
|
||||
eBus.event_bus.publish(eBus.ActionEnableMarketData, True)
|
||||
# 同步开启UI刷新线程
|
||||
self.start_ui_refresh()
|
||||
else:
|
||||
eBus.event_bus.publish(eBus.ActionDisableMarketData, True)
|
||||
# 同步关闭UI刷新线程
|
||||
self.stop_ui_refresh()
|
||||
|
||||
def start_ui_refresh(self):
|
||||
"""启动UI刷新线程"""
|
||||
if not self.refresh_thread_running:
|
||||
@@ -333,7 +310,7 @@ class TradeTargetUI(ttk.Frame):
|
||||
|
||||
if result:
|
||||
# 发布事件通知主控制器添加标的
|
||||
eBus.event_bus.publish(eBus.ActionEventAddTradeTarget, stock_code)
|
||||
eBus.event_bus.publish(ActionEventAddTradeTarget, stock_code)
|
||||
PrintLog(LogLevel.INFO, f"已发送添加请求: {stock_code} - {stock_name}")
|
||||
|
||||
def get_status_indicator(self, target: SFGridTradeTarget) -> str:
|
||||
@@ -432,12 +409,12 @@ class TradeTargetUI(ttk.Frame):
|
||||
|
||||
if result:
|
||||
target.enabled = True # type: ignore
|
||||
eBus.event_bus.publish(eBus.ActionEventEnableTrade, target.get_id())
|
||||
eBus.event_bus.publish(ActionEventEnableTrade, target.get_id())
|
||||
# self.add_log("INFO", f"已启动交易: {target.stock_code} - {target.stock_name}")
|
||||
# messagebox.showinfo("启动成功", f"已启动 {target.stock_code} ({target.stock_name}) 的交易")
|
||||
|
||||
def on_trade_enabled(self, target: SFGridTradeTarget):
|
||||
eBus.event_bus.publish(eBus.ActionEventEnableTrade, target)
|
||||
eBus.event_bus.publish(ActionEventEnableTrade, target)
|
||||
|
||||
def pause_selected_trade(self):
|
||||
"""暂停选中的交易"""
|
||||
@@ -458,7 +435,7 @@ class TradeTargetUI(ttk.Frame):
|
||||
|
||||
if result:
|
||||
target.enabled = False # type: ignore
|
||||
eBus.event_bus.publish(eBus.ActionEventDisableTrade, target.get_id())
|
||||
eBus.event_bus.publish(ActionEventDisableTrade, target.get_id())
|
||||
# self.add_log("INFO", f"已暂停交易: {target.stock_code} - {target.stock_name}")
|
||||
# messagebox.showinfo("暂停成功", f"已暂停 {target.stock_code} ({target.stock_name}) 的交易")
|
||||
|
||||
@@ -479,7 +456,7 @@ class TradeTargetUI(ttk.Frame):
|
||||
|
||||
if result:
|
||||
# 通过事件总线发出删除动作
|
||||
eBus.event_bus.publish(eBus.ActionEventDeleteTradeTarget, target.get_id())
|
||||
eBus.event_bus.publish(ActionEventDeleteTradeTarget, target)
|
||||
PrintLog(LogLevel.INFO, f"已发送删除请求: {target.stock_code} - {target.stock_name}")
|
||||
|
||||
def add_trade_target(self):
|
||||
@@ -524,7 +501,7 @@ class TradeTargetUI(ttk.Frame):
|
||||
return
|
||||
|
||||
# 发布事件通知主控制器添加标的
|
||||
eBus.event_bus.publish(eBus.ActionEventAddTradeTarget, stock_code)
|
||||
eBus.event_bus.publish(ActionEventAddTradeTarget, stock_code)
|
||||
add_window.destroy()
|
||||
|
||||
def cancel_add():
|
||||
@@ -540,7 +517,6 @@ class TradeTargetUI(ttk.Frame):
|
||||
PrintLog(LogLevel.INFO, "点击添加交易标的按钮")
|
||||
|
||||
|
||||
|
||||
def refresh_table(self):
|
||||
"""刷新表格数据"""
|
||||
# 保存当前选中的项
|
||||
@@ -1039,7 +1015,7 @@ class TradeTargetUI(ttk.Frame):
|
||||
|
||||
# 发布网格修正事件,传递GridFixData对象
|
||||
grid_fix_data = GridFixData(new_grid_index, target)
|
||||
eBus.event_bus.publish(eBus.ActionEventGridFix, grid_fix_data)
|
||||
eBus.event_bus.publish(ActionEventGridFix, grid_fix_data)
|
||||
|
||||
# 关闭窗口
|
||||
window.destroy()
|
||||
|
||||
@@ -37,13 +37,6 @@ def is_trading_time():
|
||||
|
||||
return False
|
||||
|
||||
def getInstrumentName(stock_code):
|
||||
# print(f"getInstrumentName: 获取标的名称 {stock_code}")
|
||||
detail = xtdata.get_instrument_detail(stock_code, False)
|
||||
if detail is None:
|
||||
return "UnNamed"
|
||||
return detail['InstrumentName']
|
||||
|
||||
|
||||
def getStockPosition(stock_code: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount):
|
||||
volume = 0
|
||||
|
||||
Reference in New Issue
Block a user