添加编译文件、打包瘦身、UI逻辑调整

This commit is contained in:
2025-11-05 18:04:52 +08:00
parent c77ff1c0ae
commit df0e9ecb22
9 changed files with 434 additions and 199 deletions
+3 -5
View File
@@ -1,9 +1,7 @@
[config] [config]
; miniqmtpath = /Users/gao/Workspace/quant miniqmtpath = D:/Programs/DTQMT/userdata_mini
miniQMTPath=D:\\Programs\\DTQMT\\userdata_mini grid_price = 11.0,10.0,9.0,8.0,7.0,6.0,5.0,4.0,3.0,2.0,1.0,0.0
; grid_price = 10.9,10.0,9.1,8.2,7.3,6.4,5.5,4.6,3.7,2.8,1.9,1.0 grid_volume = 100
grid_price=1.665,1.660,1.655,1.650,1.645,1.640,1.635,1.630,1.625,1.620,1.615,1.610
grid_volume = 200
account_no = 99082560 account_no = 99082560
max_enabled_targets = 10 max_enabled_targets = 10
+37
View File
@@ -0,0 +1,37 @@
# 定义事件处理函数
MarketDataUpdate = "market_data_update"
ActionEventEnableTrade = "enable_trade"
ResultEventTradeEnabled = "trade_enabled"
ActionEventDisableTrade = "disable_trade"
ResultEventTradeDisabled = "trade_disabled"
# 市场数据监听控制事件
ActionEnableMarketData = "enable_market_data"
ActionDisableMarketData = "disable_market_data"
MarketDataEnabled = "market_data_enabled"
MarketDataDisabled = "market_data_disabled"
class EventBus:
def __init__(self):
self.listeners = {} # 管理各种event的订阅情况
def subscribe(self, event_type, listener):
if event_type not in self.listeners:
self.listeners[event_type] = []
self.listeners[event_type].append(listener)
def publish(self, event_type, data):
if event_type in self.listeners:
for listener in self.listeners[event_type]:
listener(data)
# # 订阅事件
# event_bus.subscribe('my_event', handle_event)
# # 发布事件
# event_bus.publish('my_event', {'key': 'value'})
# 创建事件总线实例
event_bus = EventBus()
+82 -38
View File
@@ -1,10 +1,12 @@
# coding:utf-8 # coding:utf-8
from core.strategy_db import TradeTarget
from typing import Any
from core.eventbus import ActionDisableMarketData, ActionEnableMarketData, ActionEventDisableTrade, ActionEventEnableTrade, MarketDataUpdate, MarketDataEnabled, MarketDataDisabled, ResultEventTradeDisabled, ResultEventTradeEnabled, event_bus
from xtquant.xttrader import XtQuantTrader from xtquant.xttrader import XtQuantTrader
import time, sys import time
from peewee import ModelSelect from peewee import ModelSelect
import xtquant.xtconstant as xtconstant import xtquant.xtconstant as xtconstant
sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8 # type: ignore
import core.strategy_db as strategy_db import core.strategy_db as strategy_db
import sfgrid_constants import sfgrid_constants
from core.sfgrid_strategy import SFGridStrategy from core.sfgrid_strategy import SFGridStrategy
@@ -14,12 +16,16 @@ from xtquant.xttype import StockAccount, XtAsset, XtOrder, XtOrderResponse, XtPo
from xtquant import xtdata from xtquant import xtdata
from xtquant.xttrader import XtQuantTraderCallback from xtquant.xttrader import XtQuantTraderCallback
import datetime import datetime
import core.ui as ui
# 量化核心控制对象 # 量化核心控制对象
class SFGridController(XtQuantTraderCallback): class SFGridController(XtQuantTraderCallback):
def __init__(self, account_no: str, miniQmtPath: str): def __init__(self, account_no: str, miniQmtPath: str):
super().__init__() super().__init__()
self.registerEventHandler()
self.appUi = ui.TradeTargetUI()
xtdata.enable_hello = False xtdata.enable_hello = False
session_id = int(time.time()) session_id = int(time.time())
@@ -49,8 +55,35 @@ class SFGridController(XtQuantTraderCallback):
self.seq = None self.seq = None
print('- [成功]三疯交易系统初始化完成') print('- [成功]三疯交易系统初始化完成')
# 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("add_trade_target", self.onAddTradeTarget)
def onAddTradeTarget(self, stock_code: str):
"""处理添加交易标的事件"""
self.add_trade_target(stock_code)
def onMarketDataEnabled(self, data):
"""处理市场数据监听启用事件"""
self.startMarketData() self.startMarketData()
def onMarketDataDisabled(self, data):
"""处理市场数据监听禁用事件"""
self.stopMarketData()
def onEnableTrade(self, id: int):
self.start_stock_trade(id)
def onDisableTrade(self, id: int):
self.pause_stock_trade(id)
def hold(self):
self.appUi.run()
def startMarketData(self): def startMarketData(self):
print('- 启动市场数据订阅') print('- 启动市场数据订阅')
@@ -58,6 +91,7 @@ class SFGridController(XtQuantTraderCallback):
if self.seq == -1: if self.seq == -1:
print('- 市场数据订阅失败') print('- 市场数据订阅失败')
else: else:
event_bus.publish(MarketDataEnabled, True)
print(f'- 市场数据订阅成功, 订阅号={self.seq}') print(f'- 市场数据订阅成功, 订阅号={self.seq}')
@@ -65,11 +99,22 @@ class SFGridController(XtQuantTraderCallback):
print('- 停止市场数据订阅') print('- 停止市场数据订阅')
if self.seq is not None and self.seq > 0: if self.seq is not None and self.seq > 0:
xtdata.unsubscribe_quote(self.seq) xtdata.unsubscribe_quote(self.seq)
event_bus.publish(MarketDataDisabled, False)
def add_trade_target(self, stock_code: str): def add_trade_target(self, stock_code: str):
try: try:
stock_name = getInstrumentName(stock_code) stock_name = getInstrumentName(stock_code)
if not stock_name:
print(f'无法获取股票代码 {stock_code} 的名称,请检查代码是否正确')
return
# 检查是否已存在该标的
existing_target = strategy_db.TradeTarget.get_or_none(strategy_db.TradeTarget.stock_code == stock_code)
if existing_target:
print(f'交易标的 {stock_code} {stock_name} 已存在')
return
new_target = strategy_db.TradeTarget.create( new_target = strategy_db.TradeTarget.create(
stock_name=stock_name, stock_name=stock_name,
stock_code=stock_code, stock_code=stock_code,
@@ -96,8 +141,8 @@ class SFGridController(XtQuantTraderCallback):
print(f'新增交易标的失败 {stock_code} {e}') print(f'新增交易标的失败 {stock_code} {e}')
def del_trade_target(self, index:int): def del_trade_target(self, id:int):
target: strategy_db.TradeTarget = self.instrument_pool[index] target: strategy_db.TradeTarget = self.instrument_pool[id]
# self.stock_trade_ctrl. # self.stock_trade_ctrl.
del self.stock_trade_ctrl[target.stock_code] del self.stock_trade_ctrl[target.stock_code]
target.delete_instance() target.delete_instance()
@@ -107,28 +152,33 @@ class SFGridController(XtQuantTraderCallback):
def init_instrument_pool(self, xtTrader:XtQuantTrader, account:StockAccount): def init_instrument_pool(self, xtTrader:XtQuantTrader, account:StockAccount):
self.refresh_targets() self.refresh_targets()
for temp in self.instrument_pool: for id in self.instrument_pool:
tradeTarget:strategy_db.TradeTarget = temp tradeTarget:strategy_db.TradeTarget = self.instrument_pool[id]
tradeTarget.current_position = getStockPosition(tradeTarget.stock_code, xtTrader, account) # type: ignore tradeTarget.current_position = getStockPosition(tradeTarget.stock_code, xtTrader, account) # type: ignore
result = tradeTarget.save() result = tradeTarget.save()
print(f' |- 同步当前持仓信息 {tradeTarget.stock_code}, {tradeTarget.current_position}, result = {result}') print(f' |- 同步当前持仓信息 {tradeTarget.stock_code}, {tradeTarget.current_position}, result = {result}')
stockTradeController = SFGridStrategy(tradeTarget, self.xt_trader, self.account, tradeTarget.enabled) # type: ignore stockTradeController = SFGridStrategy(tradeTarget, self.xt_trader, self.account) # type: ignore
self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController
event_bus.publish(MarketDataUpdate, tradeTarget)
print(f'- [成功]交易标的信息初始化, 共 {len(self.instrument_pool)} 个标的') print(f'- [成功]交易标的信息初始化, 共 {len(self.instrument_pool)} 个标的')
def refresh_targets(self): def refresh_targets(self):
# 更新标的池 # 更新标的池
self.instrument_pool:ModelSelect = strategy_db.TradeTarget.select() results:ModelSelect = strategy_db.TradeTarget.select()
self.instrument_pool: dict[int, strategy_db.TradeTarget] = {}
for temp in results:
result :strategy_db.TradeTarget = temp
self.instrument_pool[result.get_id()] = result
self.print_pool() self.print_pool()
def print_pool(self): def print_pool(self):
print("- [信息]标的池信息") print("- [信息]标的池信息")
for i in range(len(self.instrument_pool)): for id in self.instrument_pool:
target: strategy_db.TradeTarget = self.instrument_pool[i] target: strategy_db.TradeTarget = self.instrument_pool[id]
status = "新建" if target.status == 0 else "已建初始仓" status = "新建" if target.status == 0 else "已建初始仓"
print(f' [序号-{i}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {getStockPosition(target.stock_code, self.xt_trader, self.account)} 网格索引: {target.grid_index} 基准价格 {sfgrid_constants.grid_price[target.grid_index]} 状态: {status} 启用交易线程: {'自动交易中' if target.enabled else '交易已停止'}') # type: ignore print(f' [序号-{id}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {getStockPosition(target.stock_code, self.xt_trader, self.account)} 网格索引: {target.grid_index} 基准价格 {sfgrid_constants.grid_price[target.grid_index]} 状态: {status} 启用交易线程: {'自动交易中' if target.enabled else '交易已停止'}') # type: ignore
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)
@@ -173,34 +223,29 @@ class SFGridController(XtQuantTraderCallback):
# 初始化指定标的交易控制器 # 初始化指定标的交易控制器
def start_stock_trade(self, index: int): def start_stock_trade(self, id: int):
tradeTarget = self.instrument_pool[index] tradeTarget: TradeTarget = self.instrument_pool[id]
# check existing thread # check existing thread
if tradeTarget.stock_code in self.stock_trade_ctrl: if tradeTarget.stock_code in self.stock_trade_ctrl:
tradeController: SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code] tradeController: SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code]
if tradeController.isEnabled():
print(f"标的交易控制器已存在且正在运行 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") tradeTarget = tradeController.enabledTrading(True)
self.instrument_pool[id] = tradeTarget
event_bus.publish(ResultEventTradeEnabled, tradeTarget)
else: else:
print(f"标的交易控制器已存在但未运行,重新启动 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n")
tradeController.enabledTrading(True)
else:
stockTradeController = SFGridStrategy(tradeTarget, self.xt_trader, self.account, tradeTarget.enabled) # type: ignore
self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController
print(f"\t创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}") print(f"\t创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}")
def pause_stock_trade(self, index: int): def pause_stock_trade(self, id: int):
tradeTarget = self.instrument_pool[index] localTarget: strategy_db.TradeTarget = self.instrument_pool[id]
if tradeTarget.stock_code in self.stock_trade_ctrl: print(f'暂停标的交易 {localTarget.stock_code} - enabled {localTarget.enabled}')
tradeController: SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code] if localTarget.stock_code in self.stock_trade_ctrl:
if tradeController.isEnabled(): tradeController: SFGridStrategy = self.stock_trade_ctrl[localTarget.stock_code]
print(f"暂停标的交易 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") tradeTarget = tradeController.enabledTrading(False)
tradeController.enabledTrading(False) self.instrument_pool[id] = tradeTarget
event_bus.publish(ResultEventTradeDisabled, tradeTarget)
else: else:
print(f"标的交易已暂停 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") print(f"标的交易控制器不存在 {localTarget.stock_code} {localTarget.stock_name}\n")
else:
print(f"标的交易控制器不存在 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n")
# ====== 市场回调方法 -- 以下方法由XtQuantData调用 ====== # ====== 市场回调方法 -- 以下方法由XtQuantData调用 ======
@@ -213,8 +258,8 @@ class SFGridController(XtQuantTraderCallback):
self.add_trade_target(stock_code) self.add_trade_target(stock_code)
self.stock_trade_ctrl[stock_code].enabledTrading(True) self.stock_trade_ctrl[stock_code].enabledTrading(True)
else: # 指定目标 当前主要使用这种模式 else: # 指定目标 当前主要使用这种模式
for target in self.instrument_pool: for id in self.instrument_pool:
stock_code = target.stock_code stock_code = self.instrument_pool[id].stock_code
# 如果存在对应的StockTradeController,则调用其onDataUpdate方法 # 如果存在对应的StockTradeController,则调用其onDataUpdate方法
if stock_code not in self.stock_trade_ctrl or stock_code not in data: if stock_code not in self.stock_trade_ctrl or stock_code not in data:
# print(f"股票代码 {stock_code} 未在交易控制器中找到,跳过处理。\n") # print(f"股票代码 {stock_code} 未在交易控制器中找到,跳过处理。\n")
@@ -251,8 +296,8 @@ class SFGridController(XtQuantTraderCallback):
else: else:
print(f"委托下单回调 投资备注 orderId: {order.order_sysid} [{order.stock_code}-{order.instrument_name}] volume: {order.order_volume} 订单策略: '{order.strategy_name}'<-->'{ctrl.getName()}'") print(f"委托下单回调 投资备注 orderId: {order.order_sysid} [{order.stock_code}-{order.instrument_name}] volume: {order.order_volume} 订单策略: '{order.strategy_name}'<-->'{ctrl.getName()}'")
def test_sim_trade(self, index: int, orderType: int): def test_sim_trade(self, id: int, orderType: int):
tradeTarget:strategy_db.TradeTarget = self.instrument_pool[index] tradeTarget:strategy_db.TradeTarget = self.instrument_pool[id]
ctrl:SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code] ctrl:SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code]
trade: XtTrade = None # type: ignore trade: XtTrade = None # type: ignore
if orderType == xtconstant.STOCK_BUY: if orderType == xtconstant.STOCK_BUY:
@@ -260,7 +305,7 @@ class SFGridController(XtQuantTraderCallback):
sfgrid_constants.account_no, sfgrid_constants.account_no,
'300083.SZ', '300083.SZ',
xtconstant.STOCK_BUY, xtconstant.STOCK_BUY,
1, 1, tradeTarget.current_buy_price, sfgrid_constants.grid_volume, 1000, 1, 1, tradeTarget.plan_buy_price, sfgrid_constants.grid_volume, 1000,
tradeTarget.current_buy_order_no, tradeTarget.current_buy_order_no,
None, ctrl.getName(), None, None, None, None, None, tradeTarget.stock_name) None, ctrl.getName(), None, None, None, None, None, tradeTarget.stock_name)
else: else:
@@ -306,5 +351,4 @@ class SFGridController(XtQuantTraderCallback):
:param response: XtAccountStatus 对象 :param response: XtAccountStatus 对象
:return: :return:
""" """
print(datetime.datetime.now(), sys._getframe().f_code.co_name) print(datetime.datetime.now(), status)
+40 -24
View File
@@ -1,5 +1,4 @@
from re import L from core.eventbus import MarketDataUpdate, event_bus
from core import util
from core.strategy_db import TradeTarget from core.strategy_db import TradeTarget
from core.util import queryPendingOrder from core.util import queryPendingOrder
@@ -11,33 +10,40 @@ import threading
class SFGridStrategy: class SFGridStrategy:
def __init__(self, tradeTarget: TradeTarget, xt_trader: xttrader.XtQuantTrader, account: StockAccount, enabled: bool = False): def __init__(self, tradeTarget: TradeTarget, xt_trader: xttrader.XtQuantTrader, account: StockAccount):
self.tradeTarget:TradeTarget = tradeTarget self.tradeTarget:TradeTarget = tradeTarget
self.xt_trader: xttrader.XtQuantTrader = xt_trader self.xt_trader: xttrader.XtQuantTrader = xt_trader
self.account:StockAccount = account self.account:StockAccount = account
self.enabledTrading(enabled) self.enabledTrading(bool(tradeTarget.enabled)) # 修复类型兼容性问题
self.dataUpdateLock = threading.Lock() self.dataUpdateLock = threading.Lock()
print(f'标的{self.tradeTarget.targetName()}交易启动状态 {self.tradeTarget.enabled}')
def getName(self): def getName(self):
return "SFGRID" return "SFGRID"
def saveProxy(self):
rc = self.tradeTarget.save()
event_bus.publish(MarketDataUpdate, self.tradeTarget)
return rc
def enabledTrading(self, enabled: bool):
def enabledTrading(self, enabled: bool) -> TradeTarget:
self.tradeTarget.enabled = enabled # type: ignore self.tradeTarget.enabled = enabled # type: ignore
self.tradeTarget.save() self.saveProxy()
pendingOrders = queryPendingOrder(str(self.tradeTarget.stock_code),self.getName(), self.xt_trader,self.account)
if len(pendingOrders) > 0:
print(f' |- 已存在{len(pendingOrders)}订单,全部取消,按需要重下。')
for order in pendingOrders:
self.xt_trader.cancel_order_stock(self.account, order.order_id)
if enabled: if enabled:
print(f" |- 标的{self.tradeTarget.targetName()}交易启动, position {self.tradeTarget.current_position}") print(f" |- 标的{self.tradeTarget.targetName()}交易启动, position {self.tradeTarget.current_position}")
# 建仓状态检查 # 建仓状态检查
if int(self.tradeTarget.current_position) == 0 and int(self.tradeTarget.status) == 0: # type: ignore if int(self.tradeTarget.current_position) == 0 and int(self.tradeTarget.status) == 0: # type: ignore
self.tradeTarget.grid_index = 1 # type: ignore self.tradeTarget.grid_index = 1 # type: ignore
self.tradeTarget.save() self.saveProxy()
orders = queryPendingOrder(str(self.tradeTarget.stock_code),self.getName(), self.xt_trader,self.account)
if len([order for order in orders if order.order_type == xtconstant.STOCK_BUY and order.price == sfgrid_constants.grid_price[1]]) > 0:
# 已存在未交易的多单
order = [order for order in orders if order.order_type == xtconstant.STOCK_BUY and order.price == sfgrid_constants.grid_price[1]][0]
print(f' |- 已存在未交易的建仓单,不重复下单:{order.order_id}')
else:
self.initBuyOrderId = self.xt_trader.order_stock_async( self.initBuyOrderId = self.xt_trader.order_stock_async(
self.account, self.account,
str(self.tradeTarget.stock_code), str(self.tradeTarget.stock_code),
@@ -45,7 +51,7 @@ class SFGridStrategy:
sfgrid_constants.grid_volume, sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE, xtconstant.FIX_PRICE,
sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)], # type: ignore sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)], # type: ignore
'sf_grid', f'{self.tradeTarget.stock_code}_init_buy') self.getName(), f'{self.tradeTarget.stock_code}_init_buy')
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓 买单已发出 InitBuyOrderSeq: {self.initBuyOrderId} Price: {sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)]} Volume: {sfgrid_constants.grid_volume}\n") # type: ignore print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓 买单已发出 InitBuyOrderSeq: {self.initBuyOrderId} Price: {sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)]} Volume: {sfgrid_constants.grid_volume}\n") # type: ignore
else: else:
# 交易阶段,检查仓位,检查现有订单 # 交易阶段,检查仓位,检查现有订单
@@ -55,13 +61,18 @@ class SFGridStrategy:
print(f' |- 仓位检查: 持仓需求充足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}') print(f' |- 仓位检查: 持仓需求充足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}')
else: else:
print(f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}') print(f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}')
else:
print(f" |- 标的{self.tradeTarget.targetName()}交易监控暂停")
return self.tradeTarget
def isEnabled(self) -> bool: def isEnabled(self) -> bool:
return bool(self.tradeTarget.enabled) print(f'|- 检查交易状态[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - {self.tradeTarget.enabled}')
return bool(self.tradeTarget.enabled) # 修复返回类型问题
def onDataUpdate(self, data): def onDataUpdate(self, data):
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - START') print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - START')
if self.tradeTarget.enabled and self.tradeTarget.status == 1: # 交易中
self.dataUpdateLock.acquire() self.dataUpdateLock.acquire()
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - LOCKED') print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - LOCKED')
try: try:
@@ -71,6 +82,7 @@ class SFGridStrategy:
highPrice = sfgrid_constants.grid_price[int(index) - 1] # pyright: ignore[reportArgumentType] highPrice = sfgrid_constants.grid_price[int(index) - 1] # pyright: ignore[reportArgumentType]
lastPrice = float("{:.3f}".format(data[self.tradeTarget.stock_code]['lastPrice'])) lastPrice = float("{:.3f}".format(data[self.tradeTarget.stock_code]['lastPrice']))
self.tradeTarget.market_price = lastPrice # type: ignore
print(f"|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 价格: {lastPrice}, 网格序号: {index}, 网格价格: {price}, 计划多单价: {lowPrice}, 计划空单价: {highPrice}") print(f"|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 价格: {lastPrice}, 网格序号: {index}, 网格价格: {price}, 计划多单价: {lowPrice}, 计划空单价: {highPrice}")
if lastPrice <= lowPrice: # 下下方多单 if lastPrice <= lowPrice: # 下下方多单
@@ -90,7 +102,7 @@ class SFGridStrategy:
self.getName(), # strategy_name self.getName(), # strategy_name
self.tradeTarget.stock_code # remark # type: ignore self.tradeTarget.stock_code # remark # type: ignore
) )
self.tradeTarget.current_buy_price = float(lowPrice) # type: ignore self.tradeTarget.plan_buy_price = float(lowPrice) # type: ignore
print(f' |- 下网格多单号 {self.tradeTarget.current_buy_order_no}, 网格基准价 {price}, 下单价 {lowPrice}, 下单量 {sfgrid_constants.grid_volume}') print(f' |- 下网格多单号 {self.tradeTarget.current_buy_order_no}, 网格基准价 {price}, 下单价 {lowPrice}, 下单量 {sfgrid_constants.grid_volume}')
elif lastPrice == highPrice: # 下上方空单 elif lastPrice == highPrice: # 下上方空单
orders = queryPendingOrder(str(self.tradeTarget.stock_code), self.getName(), self.xt_trader, self.account) orders = queryPendingOrder(str(self.tradeTarget.stock_code), self.getName(), self.xt_trader, self.account)
@@ -108,14 +120,18 @@ class SFGridStrategy:
highPrice, highPrice,
self.getName(), self.getName(),
self.tradeTarget.stock_code) # type: ignore self.tradeTarget.stock_code) # type: ignore
self.tradeTarget.current_sell_price = float(highPrice) # type: ignore self.tradeTarget.plan_sell_price = float(highPrice) # type: ignore
print(f' |- 下网格空单号 {self.tradeTarget.current_sell_order_no}, 网格基准价 {price}, 下单价 {highPrice}, 下单量 {sfgrid_constants.grid_volume}') print(f' |- 下网格空单号 {self.tradeTarget.current_sell_order_no}, 网格基准价 {price}, 下单价 {highPrice}, 下单量 {sfgrid_constants.grid_volume}')
self.tradeTarget.save()
finally: finally:
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - release lock') print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - release lock')
event_bus.publish('market_data', self.tradeTarget)
self.saveProxy()
self.dataUpdateLock.release() self.dataUpdateLock.release()
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - END') print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - END')
elif self.tradeTarget.enabled and self.tradeTarget.status == 0: # 交易中
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 交易中但未建初始仓,仅更新市场价")
self.tradeTarget.market_price = float("{:.3f}".format(data[self.tradeTarget.stock_code]['lastPrice'])) # type: ignore
self.saveProxy()
def onAsyncOrderResponse(self, order:XtOrderResponse): def onAsyncOrderResponse(self, order:XtOrderResponse):
print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:START') print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:START')
@@ -131,7 +147,7 @@ class SFGridStrategy:
self.tradeTarget.current_sell_order_no = order.order_id self.tradeTarget.current_sell_order_no = order.order_id
else: else:
print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]: 不在策略监控范围内') print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]: 不在策略监控范围内')
rc = self.tradeTarget.save() rc = self.saveProxy()
finally: finally:
print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:release lock') print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:release lock')
self.dataUpdateLock.release() self.dataUpdateLock.release()
@@ -148,7 +164,7 @@ class SFGridStrategy:
self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore
self.tradeTarget.grid_index = 1 # type: ignore self.tradeTarget.grid_index = 1 # type: ignore
self.tradeTarget.status = 1 # type: ignore self.tradeTarget.status = 1 # type: ignore
self.tradeTarget.save() self.saveProxy()
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓订单ID: {self.initBuyOrderId}已成交 ") print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓订单ID: {self.initBuyOrderId}已成交 ")
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}')
print(f' 当前持仓: {self.tradeTarget.current_position}') print(f' 当前持仓: {self.tradeTarget.current_position}')
@@ -158,7 +174,7 @@ class SFGridStrategy:
self.tradeTarget.current_position = int(self.tradeTarget.current_position) - trade.traded_volume # type: ignore self.tradeTarget.current_position = int(self.tradeTarget.current_position) - trade.traded_volume # type: ignore
self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore
self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) - 1 # type: ignore self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) - 1 # type: ignore
self.tradeTarget.save() self.saveProxy()
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 上涨 卖单已成交 订单ID: {self.tradeTarget.current_sell_order_no} Price: {sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)]} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}\n") # type: ignore print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 上涨 卖单已成交 订单ID: {self.tradeTarget.current_sell_order_no} Price: {sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)]} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}\n") # type: ignore
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}')
print(f' 当前持仓: {self.tradeTarget.current_position}') print(f' 当前持仓: {self.tradeTarget.current_position}')
@@ -168,7 +184,7 @@ class SFGridStrategy:
self.tradeTarget.current_position = int(self.tradeTarget.current_position) + trade.traded_volume # type: ignore self.tradeTarget.current_position = int(self.tradeTarget.current_position) + trade.traded_volume # type: ignore
self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore
self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) + 1 # type: ignore self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) + 1 # type: ignore
self.tradeTarget.save() self.saveProxy()
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 下跌 买单已成交 订单ID: {self.tradeTarget.current_buy_order_no} Price: {trade.traded_price} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}") print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 下跌 买单已成交 订单ID: {self.tradeTarget.current_buy_order_no} Price: {trade.traded_price} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}")
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}')
print(f' 当前持仓: {self.tradeTarget.current_position}') print(f' 当前持仓: {self.tradeTarget.current_position}')
+3 -2
View File
@@ -14,10 +14,11 @@ class TradeTarget(BaseModel):
stock_name = CharField() stock_name = CharField()
current_position = IntegerField() current_position = IntegerField()
grid_index = IntegerField() grid_index = IntegerField()
market_price = FloatField()
last_trade_price = FloatField() last_trade_price = FloatField()
current_buy_price = FloatField() plan_buy_price = FloatField()
current_buy_order_no = CharField(default='') current_buy_order_no = CharField(default='')
current_sell_price = FloatField() plan_sell_price = FloatField()
current_sell_order_no = CharField(default='') current_sell_order_no = CharField(default='')
status = IntegerField(default=0) # 0表示新标的,1表示已建初始仓,正常交易中 status = IntegerField(default=0) # 0表示新标的,1表示已建初始仓,正常交易中
enabled = BooleanField(default=False) # 是否启动交易线程 enabled = BooleanField(default=False) # 是否启动交易线程
+167 -64
View File
@@ -1,26 +1,48 @@
import random
import tkinter as tk import tkinter as tk
from tkinter import ttk, messagebox, filedialog from tkinter import ttk, messagebox, filedialog
from typing import List, Optional
from datetime import datetime from datetime import datetime
from core.eventbus import ActionDisableMarketData, ActionEnableMarketData, ActionEventDisableTrade, ActionEventEnableTrade, MarketDataUpdate, MarketDataEnabled, MarketDataDisabled, ResultEventTradeDisabled, ResultEventTradeEnabled, event_bus
from core.strategy_db import TradeTarget from core.strategy_db import TradeTarget
import configparser import configparser
import sfgrid_constants import sfgrid_constants
class TradeTargetUI: class TradeTargetUI:
def __init__(self, trade_targets: List[TradeTarget]): def __init__(self):
self.data:dict[str, TradeTarget] = {} self.data:dict[int, TradeTarget] = {}
for temp in trade_targets: self.market_data_enabled = True # 添加市场数据监听状态变量
target:TradeTarget = temp self.registerEventHandler()
self.data[str(target.get_id())] = target
self.root = tk.Tk() self.root = tk.Tk()
self.root.title("三疯交易系统") self.root.title("三疯交易系统")
self.root.geometry("1200x700") self.root.geometry("1200x700")
# 创建界面 # 创建界面
self.create_ui() self.create_ui()
def registerEventHandler(self):
event_bus.subscribe(MarketDataUpdate, self.onTradeTargetUpdated)
event_bus.subscribe(ResultEventTradeEnabled, self.onTradeEnabled)
event_bus.subscribe(ResultEventTradeDisabled, self.onTradeDisabled)
event_bus.subscribe(MarketDataEnabled, self.onMarketDataToggled)
event_bus.subscribe(MarketDataDisabled, self.onMarketDataToggled)
def onMarketDataToggled(self, data:bool):
self.market_data_enabled = self.market_data_switch_var.get()
self.add_log("INFO", "市场数据监听已" + ("启用" if data else "禁用"))
def onTradeEnabled(self, target:TradeTarget):
self.add_log("INFO", f"交易启用: {target.stock_code} - {target.stock_name}")
def onTradeDisabled(self, target:TradeTarget):
self.add_log("INFO", f"交易禁用: {target.stock_code} - {target.stock_name}")
def onTradeTargetUpdated(self, target:TradeTarget):
# 更新或添加数据到本地缓存
self.data[target.get_id()] = target
# 刷新表格显示
self.refresh_table()
def create_ui(self): def create_ui(self):
"""创建UI界面""" """创建UI界面"""
# 创建菜单栏 # 创建菜单栏
@@ -30,9 +52,55 @@ class TradeTargetUI:
main_frame = ttk.Frame(self.root) main_frame = ttk.Frame(self.root)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 创建工具栏
toolbar_frame = ttk.Frame(main_frame)
toolbar_frame.pack(fill=tk.X, pady=(0, 10))
# 工具栏按钮
ttk.Button(toolbar_frame, text="▶️ 启动交易",
command=self.start_selected_trade, width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text="⏸ 暂停交易",
command=self.pause_selected_trade, width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text=" 添加标的",
command=self.add_trade_target, width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text="🗑 删除标的",
command=self.delete_selected_trade, width=12).pack(side=tk.LEFT, padx=2)
# 添加分隔符
ttk.Separator(toolbar_frame, orient='vertical').pack(side=tk.LEFT, fill=tk.Y, padx=10)
# 市场数据监听开关
self.market_data_switch_var = tk.BooleanVar(value=True)
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.log_toggle_btn = ttk.Button(toolbar_frame, text="📋 显示日志",
command=self.toggle_log_panel, width=12)
self.log_toggle_btn.pack(side=tk.LEFT, padx=2)
# 添加清空日志按钮
ttk.Button(toolbar_frame, text="🗑 清空日志",
command=self.clear_logs, width=12).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:
event_bus.publish(ActionEnableMarketData, True)
else:
event_bus.publish(ActionDisableMarketData, True)
def create_menu_bar(self): def create_menu_bar(self):
"""创建菜单栏""" """创建菜单栏"""
menubar = tk.Menu(self.root) menubar = tk.Menu(self.root)
@@ -65,33 +133,9 @@ class TradeTargetUI:
def create_trade_target_table(self, parent): def create_trade_target_table(self, parent):
"""创建交易标的表格""" """创建交易标的表格"""
# 创建工具栏
toolbar_frame = ttk.Frame(parent)
toolbar_frame.pack(fill=tk.X, pady=(0, 10))
# 工具栏按钮
ttk.Button(toolbar_frame, text="▶️ 启动交易",
command=self.start_selected_trade, width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text="⏸ 暂停交易",
command=self.pause_selected_trade, width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text=" 添加标的",
command=self.add_trade_target, width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text="🗑 删除标的",
command=self.delete_selected_trade, width=12).pack(side=tk.LEFT, padx=2)
# 添加分隔符
ttk.Separator(toolbar_frame, orient='vertical').pack(side=tk.LEFT, fill=tk.Y, padx=10)
# 日志显示/隐藏按钮
self.log_toggle_btn = ttk.Button(toolbar_frame, text="📋 显示日志",
command=self.toggle_log_panel, width=12)
self.log_toggle_btn.pack(side=tk.LEFT, padx=2)
# 添加分隔线
ttk.Separator(parent, orient='horizontal').pack(fill=tk.X, pady=5)
columns = ("ID", columns = ("ID",
"股票代码", "股票名称", "持仓数量", "网格索引", "股票代码", "股票名称", "市场价", "持仓数量", "网格索引",
"最新成交价", "计划买入价", "买入订单号", "计划卖出价", "卖出订单号", "最新成交价", "计划买入价", "买入订单号", "计划卖出价", "卖出订单号",
"启用状态", "交易状态" "启用状态", "交易状态"
) )
@@ -103,15 +147,16 @@ class TradeTargetUI:
"ID": (50, tk.CENTER), "ID": (50, tk.CENTER),
"股票代码": (90, tk.CENTER), "股票代码": (90, tk.CENTER),
"股票名称": (100, tk.CENTER), "股票名称": (100, tk.CENTER),
"市场价": (60, tk.CENTER),
"持仓数量": (90, tk.CENTER), "持仓数量": (90, tk.CENTER),
"网格索引": (80, tk.CENTER), "网格索引": (50, tk.CENTER),
"最新成交价": (100, tk.CENTER), "最新成交价": (60, tk.CENTER),
"计划买入价": (100, tk.CENTER), "计划买入价": (60, tk.CENTER),
"买入订单号": (100, tk.CENTER), "买入订单号": (100, tk.CENTER),
"计划卖出价": (100, tk.CENTER), "计划卖出价": (60, tk.CENTER),
"卖出订单号": (100, tk.CENTER), "卖出订单号": (100, tk.CENTER),
"启用状态": (80, tk.CENTER), "启用状态": (100, tk.CENTER),
"交易状态": (80, tk.CENTER) "交易状态": (100, tk.CENTER)
} }
for col in columns: for col in columns:
@@ -143,9 +188,9 @@ class TradeTargetUI:
else: else:
return "🔴 错误状态" return "🔴 错误状态"
def get_trade_status_indicator(self, status: int) -> str: def get_trade_enabled_indicator(self, enabled: bool) -> str:
"""获取交易状态指示器""" """获取交易状态指示器"""
if status == 1: if enabled:
return "🟢 策略运行" return "🟢 策略运行"
else: else:
return "🟡 策略暂停" return "🟡 策略暂停"
@@ -158,15 +203,16 @@ class TradeTargetUI:
target.id, # type: ignore target.id, # type: ignore
target.stock_code, target.stock_code,
target.stock_name, target.stock_name,
f"{target.market_price:.3f}",
target.current_position, target.current_position,
target.grid_index, target.grid_index,
f"{target.last_trade_price:.2f}", f"{target.last_trade_price:.2f}",
f"{target.current_buy_price:.2f}", f"{target.plan_buy_price:.2f}",
target.current_buy_order_no, target.current_buy_order_no,
f"{target.current_sell_price:.2f}", f"{target.plan_sell_price:.2f}",
target.current_sell_order_no, target.current_sell_order_no,
self.get_status_indicator(target), self.get_status_indicator(target),
self.get_trade_status_indicator(target.status) # type: ignore self.get_trade_enabled_indicator(target.enabled) # type: ignore
] ]
self.trade_table.insert('', tk.END, values=values) self.trade_table.insert('', tk.END, values=values)
@@ -178,9 +224,9 @@ class TradeTargetUI:
self.log_table = ttk.Treeview(parent, columns=columns, show='headings', height=8) self.log_table = ttk.Treeview(parent, columns=columns, show='headings', height=8)
log_column_configs = { log_column_configs = {
"timestamp": ("时间", 120), "timestamp": ("时间", 100),
"level": ("级别", 60), "level": ("级别", 50),
"message": ("消息", 200) "message": ("消息", 850)
} }
for col in columns: for col in columns:
@@ -191,12 +237,6 @@ class TradeTargetUI:
# 填充示例日志 # 填充示例日志
sample_logs = [ sample_logs = [
("2024-01-15 10:30:15", "INFO", "系统启动成功"), ("2024-01-15 10:30:15", "INFO", "系统启动成功"),
("2024-01-15 10:31:22", "DEBUG", "加载交易标的: 5个"),
("2024-01-15 10:32:45", "INFO", "000001 - 网格交易线程启动"),
("2024-01-15 10:33:10", "WARNING", "601318 - 未启用交易"),
("2024-01-15 10:34:30", "ERROR", "300750 - 订单提交失败"),
("2024-01-15 10:35:18", "INFO", "600036 - 买入订单创建成功"),
("2024-01-15 10:36:05", "INFO", "数据刷新完成")
] ]
for log in sample_logs: for log in sample_logs:
@@ -239,11 +279,15 @@ class TradeTargetUI:
# 从列表中找到对应的target对象 # 从列表中找到对应的target对象
for id in self.data: for id in self.data:
if target_id == id: # type: ignore if int(target_id) == id: # type: ignore
return self.data[id] return self.data[id]
return None return None
def onLog(self, level: str, message: str):
"""接收外部日志消息并显示在日志组件中"""
self.add_log(level, message)
def start_selected_trade(self): def start_selected_trade(self):
"""启动选中的交易""" """启动选中的交易"""
target = self.get_selected_target() target = self.get_selected_target()
@@ -263,9 +307,13 @@ class TradeTargetUI:
if result: if result:
target.enabled = True # type: ignore target.enabled = True # type: ignore
self.add_log("INFO", f"已启动交易: {target.stock_code} - {target.stock_name}") event_bus.publish(ActionEventEnableTrade, target.get_id())
self.refresh_table() # self.add_log("INFO", f"已启动交易: {target.stock_code} - {target.stock_name}")
messagebox.showinfo("启动成功", f"已启动 {target.stock_code} ({target.stock_name}) 的交易") # self.refresh_table()
# messagebox.showinfo("启动成功", f"已启动 {target.stock_code} ({target.stock_name}) 的交易")
def on_trade_enabled(self, target: TradeTarget):
event_bus.publish(ActionEventEnableTrade, target)
def pause_selected_trade(self): def pause_selected_trade(self):
"""暂停选中的交易""" """暂停选中的交易"""
@@ -286,9 +334,10 @@ class TradeTargetUI:
if result: if result:
target.enabled = False # type: ignore target.enabled = False # type: ignore
self.add_log("INFO", f"已暂停交易: {target.stock_code} - {target.stock_name}") event_bus.publish(ActionEventDisableTrade, target.get_id())
self.refresh_table() # self.add_log("INFO", f"已暂停交易: {target.stock_code} - {target.stock_name}")
messagebox.showinfo("暂停成功", f"已暂停 {target.stock_code} ({target.stock_name}) 的交易") # self.refresh_table()
# messagebox.showinfo("暂停成功", f"已暂停 {target.stock_code} ({target.stock_name}) 的交易")
def delete_selected_trade(self): def delete_selected_trade(self):
"""删除选中的交易标的""" """删除选中的交易标的"""
@@ -317,8 +366,56 @@ class TradeTargetUI:
def add_trade_target(self): def add_trade_target(self):
"""添加新的交易标的""" """添加新的交易标的"""
# TODO: 实现添加交易标的的对话框 # 创建顶层窗口
messagebox.showinfo("提示", "添加交易标的功能待实现") add_window = tk.Toplevel(self.root)
add_window.title("添加交易标的")
add_window.geometry("400x150")
add_window.resizable(False, False)
# 设置窗口模态
add_window.transient(self.root)
add_window.grab_set()
# 居中显示
self.root.update_idletasks()
x = self.root.winfo_x() + (self.root.winfo_width() // 2) - 200
y = self.root.winfo_y() + (self.root.winfo_height() // 2) - 75
add_window.geometry(f"400x150+{x}+{y}")
# 创建输入框架
input_frame = ttk.Frame(add_window, padding=20)
input_frame.pack(fill=tk.BOTH, expand=True)
# 股票代码输入
ttk.Label(input_frame, text="股票代码:").grid(row=0, column=0, sticky=tk.W, pady=5)
stock_code_entry = ttk.Entry(input_frame, width=30)
stock_code_entry.grid(row=0, column=1, pady=5, padx=(10, 0))
stock_code_entry.focus()
# 按钮框架
button_frame = ttk.Frame(input_frame)
button_frame.grid(row=1, column=0, columnspan=2, pady=20)
def confirm_add():
stock_code = stock_code_entry.get().strip()
if not stock_code:
messagebox.showwarning("输入错误", "请输入股票代码")
return
# 发布事件通知主控制器添加标的
event_bus.publish("add_trade_target", stock_code)
add_window.destroy()
def cancel_add():
add_window.destroy()
# 确认和取消按钮
ttk.Button(button_frame, text="确认", command=confirm_add, width=10).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="取消", command=cancel_add, width=10).pack(side=tk.LEFT, padx=5)
# 绑定回车键确认
stock_code_entry.bind('<Return>', lambda event: confirm_add())
self.add_log("INFO", "点击添加交易标的按钮") self.add_log("INFO", "点击添加交易标的按钮")
def toggle_log_panel(self): def toggle_log_panel(self):
@@ -348,6 +445,13 @@ class TradeTargetUI:
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.log_table.insert('', 0, values=(timestamp, level, message)) self.log_table.insert('', 0, values=(timestamp, level, message))
def clear_logs(self):
"""清空日志记录"""
# 删除所有日志项
for item in self.log_table.get_children():
self.log_table.delete(item)
self.add_log("INFO", "日志已清空")
def system_settings(self): def system_settings(self):
"""系统设置""" """系统设置"""
settings_window = tk.Toplevel(self.root) settings_window = tk.Toplevel(self.root)
@@ -355,7 +459,7 @@ class TradeTargetUI:
# 设置窗口大小 # 设置窗口大小
window_width = 700 window_width = 700
window_height = 600 window_height = 550
# 先设置为模态窗口 # 先设置为模态窗口
settings_window.transient(self.root) settings_window.transient(self.root)
@@ -652,4 +756,3 @@ class TradeTargetUI:
def run(self): def run(self):
"""运行程序""" """运行程序"""
self.root.mainloop() self.root.mainloop()
+2 -3
View File
@@ -1,6 +1,3 @@
from typing import Any
import sfgrid_constants import sfgrid_constants
import xtquant.xtconstant as xtconstant import xtquant.xtconstant as xtconstant
from xtquant import xtdata, xttrader from xtquant import xtdata, xttrader
@@ -43,6 +40,8 @@ def is_trading_time():
def getInstrumentName(stock_code): def getInstrumentName(stock_code):
# print(f"getInstrumentName: 获取标的名称 {stock_code}") # print(f"getInstrumentName: 获取标的名称 {stock_code}")
detail = xtdata.get_instrument_detail(stock_code, False) detail = xtdata.get_instrument_detail(stock_code, False)
if detail is None:
return "UnNamed"
return detail['InstrumentName'] return detail['InstrumentName']
+7 -7
View File
@@ -1,10 +1,13 @@
# coding:utf-8 # coding:utf-8
import sys
sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8 # type: ignore
from core import strategy_db from core import strategy_db
from core.main_controller import SFGridController from core.main_controller import SFGridController
import sfgrid_constants as sdConstants import sfgrid_constants as sdConstants
import ui
def startTrade(index: int):
ctrl.start_stock_trade(index)
def pauseTrade(index: int):
ctrl.pause_stock_trade(index)
if __name__ == '__main__': if __name__ == '__main__':
sdConstants.initConfig() sdConstants.initConfig()
@@ -12,10 +15,7 @@ if __name__ == '__main__':
strategy_db.db.create_tables([strategy_db.TradeTarget]) strategy_db.db.create_tables([strategy_db.TradeTarget])
print('- [成功]数据库模块初始化') print('- [成功]数据库模块初始化')
targets = strategy_db.TradeTarget.select()
appUi = ui.TradeTargetUI(trade_targets=targets)
print(f'{sdConstants.account_no} : {sdConstants.miniQMTPath}') print(f'{sdConstants.account_no} : {sdConstants.miniQMTPath}')
ctrl: SFGridController = SFGridController(sdConstants.account_no, sdConstants.miniQMTPath) ctrl: SFGridController = SFGridController(sdConstants.account_no, sdConstants.miniQMTPath)
appUi.run() ctrl.hold()
+37
View File
@@ -0,0 +1,37 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['starter.py'],
pathex=[],
binaries=[],
datas=[('config.ini', '.')], # 明确包含配置文件
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=['PyQt5', 'PyQt6', 'PySide2', 'PySide6', 'matplotlib', 'numpy', 'pandas', 'jupyter', 'notebook', 'ipython'], # 排除不必要的包
noarchive=False,
optimize=2, # 启用最高级别优化
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='starter',
debug=False,
bootloader_ignore_signals=False,
strip=True, # 去除调试符号
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)