diff --git a/main_controller.py b/main_controller.py deleted file mode 100644 index 546f3dc..0000000 --- a/main_controller.py +++ /dev/null @@ -1,267 +0,0 @@ -# coding:utf-8 -from os import popen -import time, sys - -from peewee import ModelSelect -sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8 -import strategy_db -import sfgrid_constants -from sfgrid_trade_controller import StockTradeController -from util import getInstrumentName, getStockPosition -from xtquant.xttrader import XtQuantTrader -from xtquant.xttype import StockAccount, XtOrder, XtTrade -from xtquant import xtdata -from xtquant.xttrader import XtQuantTraderCallback -import datetime - -# 量化核心控制对象 -class SFGridController(XtQuantTraderCallback): - def __init__(self, account_no: str, miniQmtPath: str): - super().__init__() - xtdata.enable_hello = False - strategy_db.db.connect() - strategy_db.db.create_tables([strategy_db.TradeTarget]) - print('- 数据库模块初始化完成') - self.init_trader(miniQmtPath) - self.init_trade_account(account_no, 'STOCK') - self.stock_trade_ctrl = {} - self.init_instrument_pool() - self.seq = None - print('- 三疯交易系统初始化完成') - - def startMarketData(self): - print('- 启动市场数据订阅') - self.seq = xtdata.subscribe_whole_quote(['SH', 'SZ'], callback=self.onDataUpdate) - if self.seq == -1: - print('- 市场数据订阅失败') - else: - print(f'- 市场数据订阅成功, 订阅号={self.seq}') - - - def stopMarketData(self): - print('- 停止市场数据订阅') - if self.seq is not None and self.seq > 0: - xtdata.unsubscribe_quote(self.seq) - - - def add_trade_target(self, stock_code: str): - try: - stock_name = getInstrumentName(stock_code) - new_target = strategy_db.TradeTarget.create( - stock_name=stock_name, - stock_code=stock_code, - current_position=0, - grid_index=0, - last_trade_price=0.0, - current_buy_price=0.0, - current_buy_order_no='', - current_sell_price=0.0, - current_sell_order_no='' - ) - new_target.save() - print(f'新增交易标的 {stock_code} {stock_name}, {new_target.id}') - # 刷新标的持仓 - pos = getStockPosition(stock_code, self.xt_trader, self.account) - strategy_db.TradeTarget.update(current_position=pos).where(strategy_db.TradeTarget.stock_code == stock_code).execute() - # 更新标的池 - self.refresh_targets() - # 添加交易控制器 - stockTradeController = StockTradeController(new_target, self.xt_trader, self.account, new_target.enabled) - self.stock_trade_ctrl[stock_code] = stockTradeController - - except Exception as e: - print(f'新增交易标的失败 {stock_code} {e}') - - - def del_trade_target(self, index:int): - target: strategy_db.TradeTarget = self.instrument_pool[index] - # self.stock_trade_ctrl. - del self.stock_trade_ctrl[target.stock_code] - target.delete_instance() - self.refresh_targets() - - def init_trader(self, path): - session_id = int(time.time()) - self.xt_trader = XtQuantTrader(path, session_id) - self.xt_trader.register_callback(self) - self.xt_trader.start() - self.xt_trader.connect() - print(f'- 交易对象初始化完成, {self.xt_trader.connected}') - - def init_trade_account(self, account_id, account_type): - self.account= StockAccount(account_id, account_type) - print(f'- 交易账号对象初始化完成, 账号: {self.account.account_id}') - - - def init_instrument_pool(self): - self.refresh_targets() - - for tradeTarget in self.instrument_pool: - stockTradeController = StockTradeController(tradeTarget, self.xt_trader, self.account, tradeTarget.enabled) - self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController - - print(f'- 初始化标的池初始化完成 , 共 {len(self.instrument_pool)} 个标的') - - - def refresh_targets(self): - # 更新标的池 - self.instrument_pool:ModelSelect = strategy_db.TradeTarget.select() - self.print_pool() - - def print_pool(self): - print("- 标的池信息") - for i in range(len(self.instrument_pool)): - target: strategy_db.TradeTarget = self.instrument_pool[i] - status = "新建" if target.status == 0 else "已建初始仓" - print(f' [序号-{i}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {target.current_position} 网格索引: {target.grid_index+1} Price {sfgrid_constants.grid_price[target.grid_index]} 状态: {status} 启用交易线程: {target.enabled}') - - def print_position_info(self): - positions = self.xt_trader.query_stock_positions(self.account) - if positions: - print("\n- 持仓信息") - for pos in positions: - if pos.m_nVolume <=0: - continue - print(f"股票代码: {pos.stock_code}-{getInstrumentName(pos.stock_code)}") - print(f"总持仓: {pos.m_nVolume}") - print(f"可用持仓: {pos.m_nCanUseVolume}") - print(f"持仓成本: {pos.avg_price}") - print("---") - else: - print("\n当前无持仓") - - def print_account_info(self): - account_info = self.xt_trader.query_stock_asset(self.account) - - print(f"\n=== 账户信息 {self.account.account_id} ===") - print(f"可用资金: {account_info.m_dCash}") - print(f"总资产: {account_info.m_dTotalAsset}") - print(f"证券市值: {account_info.m_dMarketValue}") - - def print_stock_orders(self): - orders = self.xt_trader.query_stock_orders(self.account, cancelable_only=True) - if orders: - print("\n=== 委托信息 ===") - for order in orders: - print(f"委托编号: {order.order_id}") - print(f"股票代码: {order.stock_code} {getInstrumentName(order.stock_code)}") - print(f"委托方向: {order.offset_flag} ") - print(f"委托价格: {order.price}") - print(f"委托数量: {order.order_volume}") - print(f"已成交数量: {order.traded_volume}") - print(f"委托状态: {order.order_status} ") - print("---") - else: - print("\n当前无委托记录") - - - # 初始化指定标的交易控制器 - def start_stock_trade(self, index: int): - tradeTarget = self.instrument_pool[index] - # check existing thread - if tradeTarget.stock_code in self.stock_trade_ctrl: - tradeController: StockTradeController = self.stock_trade_ctrl[tradeTarget.stock_code] - if tradeController.isEnabled(): - print(f"标的交易控制器已存在且正在运行 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") - else: - print(f"标的交易控制器已存在但未运行,重新启动 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") - tradeController.enabledTrading(True) - else: - stockTradeController = StockTradeController(tradeTarget, self.xt_trader, self.account, tradeTarget.enabled) - self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController - print(f"\t创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}") - - - def pause_stock_trade(self, index: int): - tradeTarget = self.instrument_pool[index] - if tradeTarget.stock_code in self.stock_trade_ctrl: - tradeController: StockTradeController = self.stock_trade_ctrl[tradeTarget.stock_code] - if tradeController.isEnabled(): - print(f"暂停标的交易 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") - tradeController.enabledTrading(False) - else: - print(f"标的交易已暂停 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") - else: - print(f"标的交易控制器不存在 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") - - - - # ====== 市场回调方法 -- 以下方法由XtQuantData调用 ====== - def onDataUpdate(self, data): - if sfgrid_constants.max_enabled_targets <= 0: # 全推 - for stock_code, tickData in data.items(): - lastPrice = tickData['lastPrice'] - if lastPrice == 10.0 and stock_code not in self.stock_trade_ctrl: - print(f'New trade target = {stock_code} - {getInstrumentName(stock_code)} {tickData['lastPrice']}') - self.add_trade_target(stock_code) - self.stock_trade_ctrl[stock_code].enabledTrading(True) - else: # 指定目标 当前主要使用这种模式 - for target in self.instrument_pool: - stock_code = target.stock_code - # 如果存在对应的StockTradeController,则调用其onDataUpdate方法 - if stock_code not in self.stock_trade_ctrl or stock_code not in data: - # print(f"股票代码 {stock_code} 未在交易控制器中找到,跳过处理。\n") - continue - stock_controller: StockTradeController = self.stock_trade_ctrl[stock_code] - stock_controller.onDataUpdate(data) - - - # ====== 市场回调方法 -- 以下方法由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: - """ - stockCode = order.stock_code - ctrl:StockTradeController = self.stock_trade_ctrl[stockCode] - # 如果存在对应的StockTradeController,则调用其onDataUpdate方法 - if ctrl is not None and order.order_remark == ctrl.getName(): - ctrl.onOrderTrade(order) - else: - print(f"委托下单回调 投资备注 {order.order_remark} 不匹配 {ctrl.getName()}") - - def on_stock_trade(self, trade:XtTrade): - """ - 成交变动推送 - :param trade: XtTrade对象 - :return: - """ - stockCode = trade.stock_code - ctrl:StockTradeController = self.stock_trade_ctrl[stockCode] - # 如果存在对应的StockTradeController,则调用其onDataUpdate方法 - if ctrl is not None and trade.order_remark == ctrl.getName(): - ctrl.onOrderTrade(trade) - else: - print(f"委托回调 投资备注 {trade.order_remark} 不匹配 {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(), sys._getframe().f_code.co_name) diff --git a/sfgrid_trade_controller.py b/sfgrid_trade_controller.py deleted file mode 100644 index 0f8d258..0000000 --- a/sfgrid_trade_controller.py +++ /dev/null @@ -1,134 +0,0 @@ -from strategy_db import TradeTarget -import strategy_db -from util import getInstrumentName, getStockPosition - -from xtquant import xttrader, xtdata, xtconstant -from xtquant.xttype import StockAccount, XtOrder, XtTrade -import sfgrid_constants - - -class StockTradeController: - - def __init__(self, tradeTarget: TradeTarget, xt_trader: xttrader.XtQuantTrader, account: StockAccount, enabled: bool = False): - self.tradeTarget = tradeTarget - self.xt_trader = xt_trader - self.account = account - self.currentPosition = getStockPosition(self.tradeTarget.stock_code, self.xt_trader, self.account) - - def getName(self): - return "SFGRID" - - - def enabledTrading(self, enabled: bool): - self.tradeTarget.enabled = enabled - self.tradeTarget.save() - - if enabled: - print(f"|- 标的交易启动 {self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}\n") - # 建仓状态检查 - if self.tradeTarget.current_position == 0 and self.tradeTarget.status == 0: - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓 买单准备中...\n") - self.tradeTarget.grid_index = 1 - self.tradeTarget.save() - self.init_stock_position() - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓 买单已发出 InitBuyOrderId: {self.initBuyOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume}\n") - else: - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 已有仓位或非初始状态 无需建初始仓 当前仓位: {self.tradeTarget.current_position} 状态: {self.tradeTarget.status}\n") - - - def isEnabled(self) -> bool: - return self.tradeTarget.enabled - - def onDataUpdate(self, data): - if self.isEnabled(): - print(f"\n标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 行情数据更新 {data[self.tradeTarget.stock_code]}") - - def onOrderUpdate(self, order:XtOrder): - pass - - def onOrderTrade(self, trade:XtTrade): - indicator = False - if trade.order_id == self.initBuyOrderId and self.tradeTarget.status == 0: - # 此时为建仓成交 - self.tradeTarget.current_position += sfgrid_constants.grid_volume # 当前持仓数,账户原有持仓不在策略范围内 - self.tradeTarget.last_trade_price = trade.traded_price - self.tradeTarget.grid_index = 1 - self.tradeTarget.status = 1 - self.tradeTarget.save() - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓订单ID: {self.initBuyOrderId}已成交 \n") - print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}\n') - print(f' 当前持仓: {self.tradeTarget.current_position}\n') - print(f' 网格坐标: {self.tradeTarget.grid_index}\n') - indicator = True # 双向下单 - elif trade.order_id == self.sellOrderId and self.tradeTarget.status == 1: - # 上涨一格:此时空单成交 - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 上涨 卖单已成交 订单ID: {self.sellOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}\n") - self.tradeTarget.current_position = -sfgrid_constants.grid_volume - self.tradeTarget.last_trade_price = trade.traded_price - self.tradeTarget.grid_index += 1 - self.tradeTarget.save() - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 上涨 卖单已成交 订单ID: {self.sellOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}\n") - print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}\n') - print(f' 当前持仓: {self.tradeTarget.current_position}\n') - print(f' 网格坐标: {self.tradeTarget.grid_index}\n') - indicator = True # 双向下单 - elif trade.order_id == self.buyOrderId and self.tradeTarget.status == 1: - # 下跌一格:此时多单成交 - self.tradeTarget.current_position = +sfgrid_constants.grid_volume - self.tradeTarget.last_trade_price = trade.traded_price - self.tradeTarget.grid_index -= 1 - self.tradeTarget.save() - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 下跌 买单已成交 订单ID: {self.buyOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}\n") - print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}\n') - print(f' 当前持仓: {self.tradeTarget.current_position}\n') - print(f' 网格坐标: {self.tradeTarget.grid_index}\n') - indicator = True # 双向下单 - else: - # 打印订单信息和订单状态 - print(f'非策略内部订单,或订单状态不满足监控条件 {trade.order_id} {trade.stock_code}-{trade.instrument_name} {trade.commission}') - - if indicator and self.isEnabled(): - self.two_way_order() # 双向下单 - - - # Description: 新标的,建基础仓 - def init_stock_position(self): - self.initBuyOrderId = self.xt_trader.order_stock( - self.account, - self.tradeTarget.stock_code, - xtconstant.STOCK_BUY, - sfgrid_constants.grid_volume, - xtconstant.FIX_PRICE, - sfgrid_constants.grid_price[self.tradeTarget.grid_index], - 'sf_grid', f'{self.tradeTarget.stock_code}_init_buy') - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓 买单已发出 InitBuyOrderId: {self.initBuyOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume}\n") - - - # Description: 网格跳格,双向下单 - def two_way_order(self): - if self.tradeTarget.grid_index+1 < len(sfgrid_constants.grid_price): # 价格没有超过网格下边界,可以下多单 - currentPrice = sfgrid_constants.grid_price[self.tradeTarget.grid_index] - buyPrice = sfgrid_constants.grid_price[self.tradeTarget.grid_index+1] - self.buyOrderId = self.xt_trader.order_stock( - self.account, - self.tradeTarget.stock_code, - xtconstant.STOCK_BUY, - sfgrid_constants.grid_volume, - xtconstant.FIX_PRICE, - buyPrice, - 'sf_grid', f'{self.tradeTarget.stock_code}_grid_down_{self.tradeTarget.grid_index}_{currentPrice}_{buyPrice}') - self.tradeTarget.current_buy_price = buyPrice - - if self.tradeTarget.grid_index-1 >=0: # 价格没有超过网格上边界,可以下空单 - currentPrice = sfgrid_constants.grid_price[self.tradeTarget.grid_index] - sellPrice = sfgrid_constants.grid_price[self.tradeTarget.grid_index-1] - self.sellOrderId = self.xt_trader.order_stock( - self.account, - self.tradeTarget.stock_code, - xtconstant.STOCK_SELL, - sfgrid_constants.grid_volume, - xtconstant.FIX_PRICE, - sellPrice, - 'sf_grid', f'{self.tradeTarget.stock_code}_grid_up_{self.tradeTarget.grid_index}_{currentPrice}_{sellPrice}') - self.tradeTarget.current_sell_price = sellPrice - self.tradeTarget.save() \ No newline at end of file diff --git a/starter.py b/starter.py index 61b5699..f51e574 100644 --- a/starter.py +++ b/starter.py @@ -1,13 +1,14 @@ # coding:utf-8 import sys -import csv import chardet -import sfgrid_constants +from ui.ui import InitUI, Loop sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8 -from main_controller import SFGridController +from core.main_controller import ctrl -ctrl:SFGridController +if __name__ == '__main__': + InitUI() + Loop() def interact(): """执行后进入repl模式""" @@ -71,7 +72,4 @@ def help(): print(" stockTradeCtrl(index) - 获取标的交易控制器") print(" ctrl - 访问控制器实例") -if __name__ == '__main__': - ctrl = SFGridController(sfgrid_constants.account_no, sfgrid_constants.miniQMTPath) - # 交互阻塞 - interact() + \ No newline at end of file diff --git a/strategy_db.py b/strategy_db.py deleted file mode 100644 index 4986488..0000000 --- a/strategy_db.py +++ /dev/null @@ -1,23 +0,0 @@ -from peewee import SqliteDatabase, Model, CharField, IntegerField, FloatField, BooleanField - -# 连接到SQLite数据库 -db = SqliteDatabase('example.db') - -# 定义基础模型类 -class BaseModel(Model): - class Meta: - database = db - -# 定义Target类,对应targets表 -class TradeTarget(BaseModel): - stock_code = CharField(unique=True) - stock_name = CharField() - current_position = IntegerField() - grid_index = IntegerField() - last_trade_price = FloatField() - current_buy_price = FloatField() - current_buy_order_no = CharField(default='') - current_sell_price = FloatField() - current_sell_order_no = CharField(default='') - status = IntegerField(default=0) # 0表示新标的,1表示已建初始仓,正常交易中 - enabled = BooleanField(default=False) # 是否启动交易线程 diff --git a/ui/__pycache__/ui.cpython-312.pyc b/ui/__pycache__/ui.cpython-312.pyc new file mode 100644 index 0000000..388aabe Binary files /dev/null and b/ui/__pycache__/ui.cpython-312.pyc differ diff --git a/ui/ui.py b/ui/ui.py new file mode 100644 index 0000000..7bdb383 --- /dev/null +++ b/ui/ui.py @@ -0,0 +1,39 @@ +import sys + +from PySide6.QtWidgets import QApplication, QWidget +from PySide6.QtWidgets import QLabel +from PySide6.QtGui import QFont +from core.main_controller import ctrl + +app:QApplication +window:QWidget + +def InitUI(): + global window, app + app = QApplication(sys.argv) # 创建一个QApplication类的实例 + window = QWidget() # 创建一个窗口 + + window.resize(800, 600) # 设置窗口的尺寸 + window.setWindowTitle("基于PySide6的桌面应用程序") # 设置窗口标题 + + label = QLabel(window) # 创建一个标签控件 + label.setText("这是一个基于PySide6的桌面应用程序") # 设置标签的文本 + + font = QFont("华文行楷", 24, QFont.Weight.ExtraBold) # 创建一个字体对象 + + label.setFont(font) # 设置标签的字体 + + window_size = window.size() # 获取窗口的大小,返回值是QSize类对象 + label_size = label.sizeHint() # 获取标签对象的合适大小,返回值是QSize类对象 + label_x = window_size.width() // 2 - label_size.width() // 2 + label_y = window_size.height() // 2 - label_size.height() // 2 + label.setGeometry(label_x, label_y, label_size.width(), label_size.height())# 设置标签控件的位置和大小 + + label.setStyleSheet("background-color: #99CCFF; color: #FF99CC") # 设置标签的背景颜色和字体颜色 + + window.show() # 展示窗口 + sys.exit(app.exec()) + +def Loop(): + window.show() # 展示窗口 + sys.exit(app.exec())