From f37c1158ee8bc1994f0a909b2a8ac705129269e7 Mon Sep 17 00:00:00 2001 From: "GDP\\solonot" Date: Mon, 27 Oct 2025 17:38:49 +0800 Subject: [PATCH] init --- callbacks.py | 68 +++++++++++++++++++++++++++ example.db | Bin 0 -> 12288 bytes sfgrid.py | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ strategy_db.py | 20 ++++++++ trade_thread.py | 33 +++++++++++++ util.py | 18 +++++++ 6 files changed, 261 insertions(+) create mode 100644 callbacks.py create mode 100644 example.db create mode 100644 sfgrid.py create mode 100644 strategy_db.py create mode 100644 trade_thread.py create mode 100644 util.py diff --git a/callbacks.py b/callbacks.py new file mode 100644 index 0000000..191d2fb --- /dev/null +++ b/callbacks.py @@ -0,0 +1,68 @@ + +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 new file mode 100644 index 0000000000000000000000000000000000000000..ba8d1bafc36e12d8e28f57a4613e009abcfe412b GIT binary patch literal 12288 zcmeI$Jx{_w7zgk>FhPuO8=G88NFW+RFod{Su~A~JTEVDGQ=pngq@+EJx=Gv^TwR^~ z5XSgb95m6{FW^B0YD8Vt{GVLg%iYs^?tWXlwW-?NV*8GJWO6n~CJCivfiXhJkhp^4 z>PA3x+GE|I-Oe}9Au@a18WRbD@o6%CBW?%?KmY;|fB*y_009U<00I#B?E+_kP-H$v z&*OHjVx4f;tXSN14=iqY+$kR#Wk(G3M}s+CkqZhdYWdBg!t&aZvcn`_g6}nnt!p3V zB$kl+t4hh{HVs8$F?!)~vsCq$@hup5uUL>5Rprxic104KC@9N{&b0Lc(~7FfHuU_O ztnac_Wp{@8E3$1_&#lOMBAv-3d-=Vbnt5bNU*?n>u4~n}QFlC>+fMCsVX@GGYgdd8 z<-qBx>2afTIHT^`Wl>FVs{WmHtCSk2Kc#q9wK^~-+5R@C6Awf*1Oy-e0SG_<0uX=z z1Rwwb2tWV=e^g+KhDkI&+>TT#oz7-wxAvYcTQ67l&&}({+q)5QE;{i_L_0?H literal 0 HcmV?d00001 diff --git a/sfgrid.py b/sfgrid.py new file mode 100644 index 0000000..9370acf --- /dev/null +++ b/sfgrid.py @@ -0,0 +1,122 @@ +# coding:utf-8 +import threading +import time, sys +sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8 +import strategy_db +from trade_thread import StockTradeThread +from util import getInstrumentName +from xtquant.xttrader import XtQuantTrader +from xtquant.xttype import StockAccount + + +class SFGridController: + def __init__(self, account_no: str = '99082560'): + print('\n=== 数据库模块初始化 ===\n') + strategy_db.db.connect() + strategy_db.db.create_tables([strategy_db.TradeTarget]) + + + print('\n=== 三疯网络策略控制器初始化 ===\n') + self.init_instrument_pool() + self.init_trader(r'D:\\Programs\\DTQMT\\userdata_mini') + self.init_trade_account(account_no, 'STOCK') + self.grid_price = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] + print('\n=== 三疯网络策略控制器初始化完成 ===\n') + + def add_trade_target(self, stock_code): + 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_sell_price=0.0 + ) + new_target.save() + print(f'新增交易标的 {stock_code} {stock_name}, {new_target.id}') + except Exception as e: + print(f'新增交易标的失败 {stock_code} {e}') + + def init_instrument_pool(self): + self.instrument_pool = strategy_db.TradeTarget.select() + print(f'初始化标的池初始化完成, {self.instrument_pool}') + + def init_trader(self, path): + session_id = int(time.time()) + self.xt_trader = XtQuantTrader(path, session_id) + 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}') + + 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}") + + 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_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 interact(self): + """执行后进入repl模式""" + import code + code.InteractiveConsole(locals=globals()).interact() + + def init_stock_trade_threads(self): + for stock_code in self.instrument_pool: + new_job = StockTradeThread(stock_code) + new_job.name = f"StockTradeThread-{stock_code}" + new_job.start() + + def stock_trade_thread(self, stock_code): + print(f"启动标的交易线程 {stock_code} {getInstrumentName(stock_code)}\n") + threading.Event().wait(2) # 模拟交易操作的等待时间 + + +if __name__ == '__main__': + ctrl = SFGridController('99082560') + ctrl.print_account_info() + ctrl.print_stock_orders() + + ctrl.init_stock_trade_threads() + + # 交互阻塞 + ctrl.interact() + + diff --git a/strategy_db.py b/strategy_db.py new file mode 100644 index 0000000..08d84db --- /dev/null +++ b/strategy_db.py @@ -0,0 +1,20 @@ +from peewee import SqliteDatabase, Model, CharField, IntegerField, FloatField + +# 连接到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_sell_price = FloatField() + status = IntegerField(default=1) # 1表示启用,0表示停止 \ No newline at end of file diff --git a/trade_thread.py b/trade_thread.py new file mode 100644 index 0000000..bc7d610 --- /dev/null +++ b/trade_thread.py @@ -0,0 +1,33 @@ +import threading +import time +from strategy_db import TradeTarget +from util import getInstrumentName, getStockPosition +from xtquant import xttrader +from xtquant.xttype import StockAccount + +class StockTradeThread(threading.Thread): + def __init__(self, tradeTarget: TradeTarget, xt_trader: xttrader.XtQuantTrader, account: StockAccount): + super().__init__() #必须调用父类的初始化方法 + self.tradeTarget = tradeTarget + self.xt_trader = xt_trader + self.account = account + + def run(self) -> None: + print(f"启动标的交易线程 {self.tradeTarget.stock_code} {getInstrumentName(self.tradeTarget.stock_code)}\n") + while True: + print('{} is running >> {}'.format(threading.current_thread().name, self.tradeTarget.stock_code)) + time.sleep(2) + + + # Description: 程序启动后 + def check_stock_position(self): + volume = getStockPosition(self.stock_code, self.xt_trader, self.account) + pass + + # Description: 新标的,建基础仓 + def init_stock_position(self): + pass + + # Description: 双向下单 + def two_way_order(self): + pass \ No newline at end of file diff --git a/util.py b/util.py new file mode 100644 index 0000000..9d6a238 --- /dev/null +++ b/util.py @@ -0,0 +1,18 @@ +from xtquant import xtdata, xttrader +from xtquant.xttype import StockAccount + +def getInstrumentName(stock_code): + # print(f"getInstrumentName: 获取标的名称 {stock_code}") + detail = xtdata.get_instrument_detail(stock_code, False) + return detail['InstrumentName'] + + +def getStockPosition(stock_code: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount): + volume = 0 + positions = xt_trader.query_stock_positions(account) + if positions: + for pos in positions: + if pos.stock_code == stock_code: + volume = pos.m_nVolume + break + return volume \ No newline at end of file