new update

This commit is contained in:
2025-11-11 17:45:56 +08:00
parent 662a1ea7c1
commit 54fd7c9545
7 changed files with 148 additions and 326 deletions
+1 -13
View File
@@ -1,22 +1,10 @@
# 定义事件处理函数
ActionEventEnableTrade = "enable_trade"
ResultEventTradeEnabled = "trade_enabled"
ActionEventDisableTrade = "disable_trade"
ResultEventTradeDisabled = "trade_disabled"
# 市场数据监听控制事件 # 市场数据监听控制事件
MarketDataUpdate = "market_data_update" MarketDataUpdate = "market_data_update"
ActionEnableMarketData = "enable_market_data" ActionEnableMarketData = "enable_market_data"
ActionDisableMarketData = "disable_market_data" ActionDisableMarketData = "disable_market_data"
MarketDataEnabled = "market_data_enabled" MarketDataEnabled = "market_data_enabled"
MarketDataDisabled = "market_data_disabled" 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 # Pring Log
EventPrintLog = "print_log" EventPrintLog = "print_log"
+7
View File
@@ -76,6 +76,13 @@ class QmtV(XtQuantTraderCallback):
orderRemark # remark # type: ignore 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): # def print_position_info(self):
# positions:list[XtPosition] = self.xt_trader.query_stock_positions(self.account) # positions:list[XtPosition] = self.xt_trader.query_stock_positions(self.account)
# if positions: # if positions:
+14
View File
@@ -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"
+94 -251
View File
@@ -1,6 +1,10 @@
# coding:utf-8 # coding:utf-8
from typing import Any
from core.sfgrid.model import SFGridTradeTarget as TradeTarget 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 import xttrader
from xtquant.xttrader import XtQuantTrader from xtquant.xttrader import XtQuantTrader
import time import time
@@ -9,7 +13,7 @@ from peewee import ModelSelect
import core.sfgrid.model as model import core.sfgrid.model as model
import config import config
from core.sfgrid.sfgrid_strategy import SFGridStrategy 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.xttrader import XtQuantTrader
from xtquant.xttype import StockAccount, XtAsset, XtOrder, XtPosition, XtTrade from xtquant.xttype import StockAccount, XtAsset, XtOrder, XtPosition, XtTrade
from xtquant import xtdata from xtquant import xtdata
@@ -21,52 +25,79 @@ from core.qmt import qmtv
from core.sfgrid.objects import GridFixData from core.sfgrid.objects import GridFixData
# 量化核心控制对象 # 量化核心控制对象
class SFGridController(XtQuantTraderCallback): class SFGridController:
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.registerEventHandler() self.registerEventHandler()
self.listening_stock = []
self.stock_trade_ctrl = {}
self.init_instrument_pool(qmtv.xttrader, qmtv.account) # type: ignore
self.seq = None self.seq = None
PrintLog(LogLevel.INFO, '- [成功]三疯交易系统初始化完成') PrintLog(LogLevel.INFO, '- [成功]三疯交易系统初始化完成')
self.startMarketData()
def registerEventHandler(self): def registerEventHandler(self):
event_bus.subscribe(ActionEventEnableTrade, self.onEnableTrade) event_bus.subscribe(ActionEventEnableTrade, self.onEnableTrade)
event_bus.subscribe(ActionEventDisableTrade, self.onDisableTrade) 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(ActionEventAddTradeTarget, self.onAddTradeTarget)
event_bus.subscribe(ActionEventDeleteTradeTarget, self.onDeleteTradeTarget) event_bus.subscribe(ActionEventDeleteTradeTarget, self.onDeleteTradeTarget)
event_bus.subscribe(ActionEventGridFix, self.onGridFix) event_bus.subscribe(ActionEventGridFix, self.onGridFix)
def onDeleteTradeTarget(self, id: int): def onDeleteTradeTarget(self, target: TradeTarget):
"""处理删除交易标的事件""" """处理删除交易标的事件"""
self.del_trade_target(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, id) event_bus.publish(ResultEventTradeTargetDeleted, target)
except Exception as e:
PrintLog(LogLevel.ERROR, f"删除交易标的失败 ID {id}: {str(e)}")
def onAddTradeTarget(self, stock_code: str): 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): # 检查是否已存在该标的
"""处理市场数据监听启用事件""" existing_target = TradeTarget.get_or_none(TradeTarget.stock_code == stock_code)
self.startMarketData() if existing_target:
PrintLog(LogLevel.INFO, f'交易标的 {stock_code} {stock_name} 已存在')
return
def onMarketDataDisabled(self, data): # 刷新标的持仓
"""处理市场数据监听禁用事件""" pos = qmtv.getStockPosition(stock_code) # type: ignore
self.stopMarketData() 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): def onEnableTrade(self, id: int):
self.start_stock_trade(id) pass
# self.start_stock_trade(id)
def onDisableTrade(self, id: int): def onDisableTrade(self, id: int):
self.pause_stock_trade(id) pass
# self.pause_stock_trade(id)
def onGridFix(self, data: GridFixData): def onGridFix(self, data: GridFixData):
"""处理网格修正事件""" """处理网格修正事件"""
@@ -82,29 +113,10 @@ class SFGridController(XtQuantTraderCallback):
target.grid_index = grid_index target.grid_index = grid_index
target.save() 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}") PrintLog(LogLevel.INFO, f"网格修正已应用: {target.stock_code} - {target.stock_name}, 网格索引: {grid_index}")
except Exception as e: except Exception as e:
PrintLog(LogLevel.ERROR, f"网格修正更新失败: {str(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): def stopMarketData(self):
@@ -115,221 +127,52 @@ class SFGridController(XtQuantTraderCallback):
event_bus.publish(MarketDataDisabled, False) event_bus.publish(MarketDataDisabled, False)
def add_trade_target(self, stock_code: str): # # 初始化指定标的交易控制器
try: # def start_stock_trade(self, tradeTarget: TradeTarget):
stock_name = getInstrumentName(stock_code) # # check existing thread
if not stock_name: # if tradeTarget.stock_code in self.stock_trade_ctrl:
PrintLog(LogLevel.ERROR, f'无法获取股票代码 {stock_code} 的名称,请检查代码是否正确') # tradeController: SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code]
return
# 检查是否已存在该标的 # tradeTarget = tradeController.enabledTrading(True)
existing_target = TradeTarget.get_or_none(TradeTarget.stock_code == stock_code) # self.instrument_pool[id] = tradeTarget
if existing_target: # event_bus.publish(ResultEventTradeEnabled, tradeTarget)
PrintLog(LogLevel.INFO, f'交易标的 {stock_code} {stock_name} 已存在') # else:
return # PrintLog(LogLevel.INFO, f"\t创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}")
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}')
def del_trade_target(self, id:int): # def pause_stock_trade(self, id: int):
try: # localTarget: TradeTarget = self.instrument_pool[id]
# 检查标的是否存在 # print(f'暂停标的交易 {localTarget.stock_code} - enabled {localTarget.enabled}')
if id not in self.instrument_pool: # if localTarget.stock_code in self.stock_trade_ctrl:
PrintLog(LogLevel.ERROR, f"交易标的 ID {id} 不存在") # tradeController: SFGridStrategy = self.stock_trade_ctrl[localTarget.stock_code]
return # tradeTarget = tradeController.enabledTrading(False)
# orders = queryPendingOrder(localTarget.stock_code, tradeController.getName(), self.xt_trader, self.account) # type: ignore
target: TradeTarget = self.instrument_pool[id] # for order in orders:
# qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id)
# 如果存在交易控制器,先停止交易 # print(f'取消未成交订单 {len(orders)}')
if target.stock_code in self.stock_trade_ctrl: # self.instrument_pool[id] = tradeTarget
# 停止交易控制器 # event_bus.publish(ResultEventTradeDisabled, tradeTarget)
del self.stock_trade_ctrl[target.stock_code] # else:
# print(f"标的交易控制器不存在 {localTarget.stock_code} {localTarget.stock_name}\n")
# 从数据库中删除
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")
# ====== 市场回调方法 -- 以下方法由XtQuantData调用 ====== # ====== 市场回调方法 -- 以下方法由XtQuantData调用 ======
def onDataUpdate(self, data): # def onDataUpdate(self, data):
# 收集所有市场数据用于市场监控 # # 收集所有市场数据用于市场监控
for stock_code, tickData in data.items(): # for stock_code, tickData in data.items():
if stock_code in self.stock_trade_ctrl: # if stock_code in self.stock_trade_ctrl:
stock_controller: SFGridStrategy = self.stock_trade_ctrl[stock_code] # stock_controller: SFGridStrategy = self.stock_trade_ctrl[stock_code]
stock_controller.onDataUpdate(data) # 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: # else:
# print(f"委托回调 投资备注 {response.strategy_name} 不匹配 {ctrl.getName()}") # # 非目标交易,发布市场数据更新事件用于市场监控
# 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 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)
+4 -3
View File
@@ -1,12 +1,13 @@
from core.qmt import qmtv from core.qmt import qmtv
from core.sfgrid.bus_events import EventTradeTargetUpdate
import core.sfgrid.model as model import core.sfgrid.model as model
from core import constants 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.constants import OrderTypeBuy, OrderTypeInit, OrderTypeSell
from core.util import queryPendingOrder, is_trading_time from core.util import queryPendingOrder, is_trading_time
from xtquant import xttrader, xtconstant from xtquant import xtconstant
from xtquant.xttype import StockAccount, XtOrder, XtTrade from xtquant.xttype import XtOrder, XtTrade
import config import config
import threading import threading
+22 -46
View File
@@ -7,25 +7,28 @@ import threading
import time import time
import core.eventbus as eBus import core.eventbus as eBus
from core.logger import LogLevel, PrintLog 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 from core.sfgrid.model import SFGridTradeTarget
import configparser import configparser
import config import config
from core.sfgrid.objects import GridFixData from core.sfgrid.objects import GridFixData
from core.qmt import qmtv from core.qmt import qmtv
from core.sfgrid.sfgrid_controller import SFGridController
from core.sfgrid.sfgrid_strategy import SFGridStrategy from core.sfgrid.sfgrid_strategy import SFGridStrategy
class TradeTargetUI(ttk.Frame): class TradeTargetUI(ttk.Frame):
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent) super().__init__(parent)
self.controller = SFGridController()
self.tradeTargetData:dict[int, SFGridTradeTarget] = {} # id->trade_target 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.init_trade_target_pool()
self.registerEventHandler() self.registerEventHandler()
# 创建刷新线程标志 # 创建刷新线程标志
self.refresh_thread_running = True # 默认不启动刷新线程 self.refresh_thread_running = False # 默认不启动刷新线程
# 市场监控数据 # 市场监控数据
self.marketData: dict[str, Any] = {} # 存储市场数据 {stock_code: {stock_name, last_price, time}} self.marketData: dict[str, Any] = {} # 存储市场数据 {stock_code: {stock_name, last_price, time}}
@@ -33,6 +36,8 @@ class TradeTargetUI(ttk.Frame):
# 创建界面 # 创建界面
self.create_ui() self.create_ui()
self.start_ui_refresh()
def refresh_targets(self): def refresh_targets(self):
# 更新标的池 # 更新标的池
results = SFGridTradeTarget.select() results = SFGridTradeTarget.select()
@@ -52,20 +57,21 @@ class TradeTargetUI(ttk.Frame):
result = tradeTarget.save() result = tradeTarget.save()
PrintLog(LogLevel.INFO, f' |- 同步[{tradeTarget.stock_code}-{tradeTarget.stock_name}]持仓信息[{'成功' if result == 1 else '失败'}]') PrintLog(LogLevel.INFO, f' |- 同步[{tradeTarget.stock_code}-{tradeTarget.stock_name}]持仓信息[{'成功' if result == 1 else '失败'}]')
stockTradeController = SFGridStrategy(tradeTarget) # type: ignore 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) # eBus.event_bus.publish(eBus.EventTradeTargetUpdate, tradeTarget)
PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的') PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的')
def registerEventHandler(self): 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.MarketDataUpdate, self.onMarketDataUpdated)
# eBus.event_bus.subscribe(eBus.ResultEventTradeEnabled, self.onTradeEnabled) # eBus.event_bus.subscribe(eBus.ResultEventTradeEnabled, self.onTradeEnabled)
# eBus.event_bus.subscribe(eBus.ResultEventTradeDisabled, self.onTradeDisabled) # eBus.event_bus.subscribe(eBus.ResultEventTradeDisabled, self.onTradeDisabled)
# eBus.event_bus.subscribe(eBus.MarketDataEnabled, self.onMarketDataToggled) # eBus.event_bus.subscribe(eBus.MarketDataEnabled, self.onMarketDataToggled)
# eBus.event_bus.subscribe(eBus.MarketDataDisabled, 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): def start_refresh_thread(self):
"""启动刷新线程""" """启动刷新线程"""
@@ -84,22 +90,17 @@ class TradeTargetUI(ttk.Frame):
"""停止刷新线程""" """停止刷新线程"""
self.refresh_thread_running = False self.refresh_thread_running = False
def onTradeTargetDeleted(self, id: int): def onTradeTargetDeleted(self, target: SFGridTradeTarget):
"""处理交易标的删除完成事件""" """处理交易标的删除完成事件"""
# 从本地数据中删除 # 从本地数据中删除
id = target.get_id()
if id in self.tradeTargetData: if id in self.tradeTargetData:
PrintLog(LogLevel.DEBUG, f"删除交易标的,ID: {id}")
del self.tradeTargetData[id] del self.tradeTargetData[id]
del self.strategy_ctrl[id]
# 添加日志 # 添加日志
PrintLog(LogLevel.INFO, f"交易标的已删除,ID: {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): def onTradeEnabled(self, target:SFGridTradeTarget):
PrintLog(LogLevel.INFO, f"交易启用: {target.stock_code} - {target.stock_name}") 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) 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) 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): def start_ui_refresh(self):
"""启动UI刷新线程""" """启动UI刷新线程"""
if not self.refresh_thread_running: if not self.refresh_thread_running:
@@ -333,7 +310,7 @@ class TradeTargetUI(ttk.Frame):
if result: 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}") PrintLog(LogLevel.INFO, f"已发送添加请求: {stock_code} - {stock_name}")
def get_status_indicator(self, target: SFGridTradeTarget) -> str: def get_status_indicator(self, target: SFGridTradeTarget) -> str:
@@ -432,12 +409,12 @@ class TradeTargetUI(ttk.Frame):
if result: if result:
target.enabled = True # type: ignore 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}") # self.add_log("INFO", f"已启动交易: {target.stock_code} - {target.stock_name}")
# messagebox.showinfo("启动成功", f"已启动 {target.stock_code} ({target.stock_name}) 的交易") # messagebox.showinfo("启动成功", f"已启动 {target.stock_code} ({target.stock_name}) 的交易")
def on_trade_enabled(self, target: SFGridTradeTarget): 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): def pause_selected_trade(self):
"""暂停选中的交易""" """暂停选中的交易"""
@@ -458,7 +435,7 @@ class TradeTargetUI(ttk.Frame):
if result: if result:
target.enabled = False # type: ignore 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}") # self.add_log("INFO", f"已暂停交易: {target.stock_code} - {target.stock_name}")
# messagebox.showinfo("暂停成功", 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: 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}") PrintLog(LogLevel.INFO, f"已发送删除请求: {target.stock_code} - {target.stock_name}")
def add_trade_target(self): def add_trade_target(self):
@@ -524,7 +501,7 @@ class TradeTargetUI(ttk.Frame):
return return
# 发布事件通知主控制器添加标的 # 发布事件通知主控制器添加标的
eBus.event_bus.publish(eBus.ActionEventAddTradeTarget, stock_code) eBus.event_bus.publish(ActionEventAddTradeTarget, stock_code)
add_window.destroy() add_window.destroy()
def cancel_add(): def cancel_add():
@@ -540,7 +517,6 @@ class TradeTargetUI(ttk.Frame):
PrintLog(LogLevel.INFO, "点击添加交易标的按钮") PrintLog(LogLevel.INFO, "点击添加交易标的按钮")
def refresh_table(self): def refresh_table(self):
"""刷新表格数据""" """刷新表格数据"""
# 保存当前选中的项 # 保存当前选中的项
@@ -1039,7 +1015,7 @@ class TradeTargetUI(ttk.Frame):
# 发布网格修正事件,传递GridFixData对象 # 发布网格修正事件,传递GridFixData对象
grid_fix_data = GridFixData(new_grid_index, target) 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() window.destroy()
-7
View File
@@ -37,13 +37,6 @@ def is_trading_time():
return False 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): def getStockPosition(stock_code: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount):
volume = 0 volume = 0