diff --git a/callbacks.py b/callbacks.py deleted file mode 100644 index 191d2fb..0000000 --- a/callbacks.py +++ /dev/null @@ -1,68 +0,0 @@ - -from xttrader import XtQuantTraderCallback -import datetime - -class MyXtQuantTraderCallback(XtQuantTraderCallback): - - def on_disconnected(self): - """ - 连接断开 - :return: - """ - print(datetime.datetime.now(), '连接断开回调') - - def on_stock_order(self, order): - """ - 委托回报推送 - :param order: XtOrder对象 - :return: - """ - print(datetime.datetime.now(), '委托回调 投资备注', order.order_remark) - - def on_stock_trade(self, trade): - """ - 成交变动推送 - :param trade: XtTrade对象 - :return: - """ - print(datetime.datetime.now(), '成交回调', trade.order_remark, f"委托方向(48买 49卖) {trade.offset_flag} 成交价格 {trade.traded_price} 成交数量 {trade.traded_volume}") - - 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"委托报错回调 {order_error.order_remark} {order_error.error_msg}") - - def on_cancel_error(self, cancel_error): - """ - 撤单失败推送 - :param cancel_error: XtCancelError 对象 - :return: - """ - print(datetime.datetime.now(), sys._getframe().f_code.co_name) - - def on_order_stock_async_response(self, response): - """ - 异步下单回报推送 - :param response: XtOrderResponse 对象 - :return: - """ - print(f"异步委托回调 投资备注: {response.order_remark}") - - def on_cancel_order_stock_async_response(self, response): - """ - :param response: XtCancelOrderResponse 对象 - :return: - """ - print(datetime.datetime.now(), sys._getframe().f_code.co_name) - - def on_account_status(self, status): - """ - :param response: XtAccountStatus 对象 - :return: - """ - print(datetime.datetime.now(), sys._getframe().f_code.co_name) diff --git a/example.db b/example.db index ece04f1..66cbb62 100644 Binary files a/example.db and b/example.db differ diff --git a/strategy_controller.py b/main_controller.py similarity index 65% rename from strategy_controller.py rename to main_controller.py index 89c3cb7..8394417 100644 --- a/strategy_controller.py +++ b/main_controller.py @@ -2,37 +2,40 @@ import time, sys sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8 import strategy_db -from stock_trade_controller import StockTradeController +import sfgrid_constants +from sfgrid_trade_controller import StockTradeController from util import getInstrumentName, getStockPosition from xtquant.xttrader import XtQuantTrader from xtquant.xttype import StockAccount from xtquant import xtdata +from xtquant.xttrader import XtQuantTraderCallback +import datetime -class SFGridController: - def __init__(self, account_no: str = '99082560'): - print('=== 数据库模块初始化 ===\n') +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('=== 三疯网格策略控制器初始化 ===\n') - self.init_instrument_pool() - self.init_trader(r'D:\\Programs\\DTQMT\\userdata_mini') + print('- 数据库模块初始化完成') + self.init_trader(miniQmtPath) self.init_trade_account(account_no, 'STOCK') - self.grid_price = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] self.stock_trade_ctrl = {} + self.init_instrument_pool() self.seq = None - print('=== 三疯网格策略控制器初始化完成 ===\n') + print('- 三疯交易系统初始化完成') def startMarketData(self): - print('=== 三疯网格策略 启动市场数据接收 ===\n') + print('- 启动市场数据订阅') self.seq = xtdata.subscribe_whole_quote(['SH', 'SZ'], callback=self.onDataUpdate) if self.seq == -1: - print('市场数据订阅失败\n') + print('- 市场数据订阅失败') else: - print(f'市场数据订阅成功, 订阅号={self.seq}\n') + print(f'- 市场数据订阅成功, 订阅号={self.seq}') def stopMarketData(self): - print('=== 三疯网格策略 停止市场数据接收 ===\n') + print('- 停止市场数据订阅') if self.seq is not None and self.seq > 0: xtdata.unsubscribe_quote(self.seq) @@ -80,13 +83,14 @@ class SFGridController: 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}') + 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}') + print(f'- 交易账号对象初始化完成, 账号: {self.account.account_id}') def init_instrument_pool(self): self.instrument_pool = strategy_db.TradeTarget.select() @@ -95,20 +99,20 @@ class SFGridController: stockTradeController = StockTradeController(tradeTarget, self.xt_trader, self.account, tradeTarget.enabled) self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController - print(f'初始化标的池初始化完成 , 共 {len(self.instrument_pool)} 个标的\n') self.print_pool() + print(f'- 初始化标的池初始化完成 , 共 {len(self.instrument_pool)} 个标的') def print_pool(self): - print("\n=== 标的池信息 ===") + 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"[Index-{i}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {target.current_position} 网格索引: {target.grid_index+1} Price {self.grid_price[target.grid_index]} 状态: {status} 启用交易线程: {target.enabled}") + 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=== 持仓信息 ===") + print("\n- 持仓信息") for pos in positions: if pos.m_nVolume <=0: continue @@ -145,7 +149,7 @@ class SFGridController: print("\n当前无委托记录") - # 初始化指定标的交易线程 + # 初始化指定标的交易控制器 def start_stock_trade(self, index: int): tradeTarget = self.instrument_pool[index] # check existing thread @@ -159,7 +163,7 @@ class SFGridController: else: stockTradeController = StockTradeController(tradeTarget, self.xt_trader, self.account, tradeTarget.enabled) self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController - print(f"创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") + print(f"|- 创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}") def pause_stock_trade(self, index: int): @@ -174,3 +178,75 @@ class SFGridController: else: print(f"标的交易控制器不存在 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}\n") + + # ====== 市场回调方法 -- 以下方法由XtQuantTrader调用 ====== + + + def on_connected(self): + """ + 连接成功推送 + """ + print(datetime.datetime.now(), '连接成功回调') + + def on_disconnected(self): + """ + 连接断开 + :return: + """ + print(datetime.datetime.now(), '连接断开回调') + + def on_stock_order(self, order): + """ + 委托回报推送 + :param order: XtOrder对象 + :return: + """ + print(datetime.datetime.now(), '委托回调 投资备注', order.order_remark) + + def on_stock_trade(self, trade): + """ + 成交变动推送 + :param trade: XtTrade对象 + :return: + """ + print(datetime.datetime.now(), '成交回调', trade.order_remark, f"委托方向(48买 49卖) {trade.offset_flag} 成交价格 {trade.traded_price} 成交数量 {trade.traded_volume}") + + 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"委托报错回调 {order_error.order_remark} {order_error.error_msg}") + + def on_cancel_error(self, cancel_error): + """ + 撤单失败推送 + :param cancel_error: XtCancelError 对象 + :return: + """ + print(datetime.datetime.now(), sys._getframe().f_code.co_name) + + def on_order_stock_async_response(self, response): + """ + 异步下单回报推送 + :param response: XtOrderResponse 对象 + :return: + """ + print(f"异步委托回调 投资备注: {response.order_remark}") + + def on_cancel_order_stock_async_response(self, response): + """ + :param response: XtCancelOrderResponse 对象 + :return: + """ + print(datetime.datetime.now(), sys._getframe().f_code.co_name) + + def on_account_status(self, status): + """ + :param response: XtAccountStatus 对象 + :return: + """ + print(datetime.datetime.now(), sys._getframe().f_code.co_name) diff --git a/sfgrid_constants.py b/sfgrid_constants.py new file mode 100644 index 0000000..25dc66f --- /dev/null +++ b/sfgrid_constants.py @@ -0,0 +1,4 @@ +miniQMTPath = r'D:\\Programs\\DTQMT\\userdata_mini' # miniQMT软件的安装路径 +grid_price = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 网格价格设置,从高到低 +grid_volume = 100 # 每个网格的交易手数 +account_no = '99082560' # 交易账号 \ No newline at end of file diff --git a/stock_trade_controller.py b/sfgrid_trade_controller.py similarity index 64% rename from stock_trade_controller.py rename to sfgrid_trade_controller.py index e4eca53..3c2e3ed 100644 --- a/stock_trade_controller.py +++ b/sfgrid_trade_controller.py @@ -1,33 +1,43 @@ -import threading -import time from strategy_db import TradeTarget import strategy_db from util import getInstrumentName, getStockPosition -from xtquant import xttrader, xtdata + +from xtquant import xttrader, xtdata, xtconstant from xtquant.xttype import StockAccount +import sfgrid_constants class StockTradeController: def __init__(self, tradeTarget: TradeTarget, xt_trader: xttrader.XtQuantTrader, account: StockAccount, enabled: bool = False): - super().__init__() #必须调用父类的初始化方法 self.tradeTarget = tradeTarget self.xt_trader = xt_trader self.account = account self.currentPosition = getStockPosition(self.tradeTarget.stock_code, self.xt_trader, self.account) self.tradeRecords = strategy_db.TradeRecord.select().where(strategy_db.TradeRecord.stock_code == self.tradeTarget.stock_code).order_by(strategy_db.TradeRecord.trade_time.desc()) - print(f"创建标的交易线程 {self.tradeTarget.stock_code} {getInstrumentName(self.tradeTarget.stock_code)} {tradeTarget}\n") - xtdata.subscribe_quote(tradeTarget.stock_code, period='tick', start_time='', end_time='', count=0, callback=self.onDataUpdate) + print(f"|- 创建标的 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)} 交易控制器") def enabledTrading(self, enabled: bool): self.tradeTarget.enabled = enabled self.tradeTarget.save() + + # 建仓状态检查 + if self.tradeTarget.current_position == 0 and self.tradeTarget.status == 0: + self.tradeTarget.grid_index = 1 + self.tradeTarget.save() + 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') def isEnabled(self) -> bool: return self.tradeTarget.enabled - def onDataUpdate(self, data): if self.isEnabled(): print(f"标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 行情数据更新 {data[self.tradeTarget.stock_code]}\n") diff --git a/sfgrid.py b/starter.py similarity index 82% rename from sfgrid.py rename to starter.py index 428a957..a315a05 100644 --- a/sfgrid.py +++ b/starter.py @@ -1,7 +1,9 @@ # coding:utf-8 import sys + +import sfgrid_constants sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8 -from strategy_controller import SFGridController +from main_controller import SFGridController ctrl:SFGridController @@ -37,8 +39,8 @@ def pauseTrade(index:int): def help(): print("可用命令:") print(" ===================================================") - print(" startMarketData() - 启动市场数据接收") - print(" stopMarketData() - 停止市场数据接收") + print(" startMarketData() - 启动市场数据接收") + print(" stopMarketData() - 停止市场数据接收") print(" addTradeTarget(stock_code) - 添加交易标的") print(" accountInfo() - 打印账户信息") print(" positionInfo() - 打印持仓信息") @@ -49,6 +51,6 @@ def help(): print(" ctrl - 访问控制器实例") if __name__ == '__main__': - ctrl = SFGridController('99082560') + ctrl = SFGridController(sfgrid_constants.account_no, sfgrid_constants.miniQMTPath) # 交互阻塞 interact()