""" Dummy QMT 模拟器 - 用于在非 Windows 环境下模拟 QMT 交易功能 """ import datetime import threading import time import random import config import core.eventbus as eBus from core.logger import LogLevel, PrintLog class DummyPosition: """模拟持仓""" def __init__(self, stock_code, stock_name, volume, yesterday_vol=0): self.stock_code = stock_code self.stock_name = stock_name self.volume = volume self.can_use_volume = volume self.yesterday_volume = yesterday_vol class DummyOrder: """模拟订单""" def __init__(self, stock_code, order_id, status, price, volume): self.stock_code = stock_code self.order_id = order_id self.order_status = status self.order_price = price self.volume = volume class DummyTrade: """模拟成交""" def __init__(self, stock_code, trade_id, price, volume, strategy_name): self.stock_code = stock_code self.trade_id = trade_id self.trade_price = price self.trade_volume = volume self.strategy_name = strategy_name class DummyOrderResponse: """模拟下单响应""" def __init__(self, order_id, stock_code, seq, error_msg, strategy_name): self.order_id = order_id self.stock_code = stock_code self.seq = seq self.error_msg = error_msg self.strategy_name = strategy_name class DummyQmtV: """ Dummy QMT 模拟器 模拟 QmtV 类的接口,用于在没有 miniQMT 的环境下运行和测试 """ def __init__(self) -> None: self.inited = False self.details = {} self.lastMarketDataUpdateTimestamp = time.time() self.isMarketActive = True self.connected = False self.account = None self._positions = {} self._pending_orders = [] self._market_data_thread = None self._counter = 0 def getTrader(self): return self def init_qmtv(self): """初始化交易器""" PrintLog(LogLevel.INFO, f'- [模拟] QMT 交易器初始化') self.connected = True self.inited = True def connect(self) -> bool: """连接 QMT (模拟总是成功)""" PrintLog(LogLevel.INFO, f'- [成功] 市场交易连接 (模拟模式)') # 创建模拟账号 try: from xtquant.xttype import StockAccount self.account = StockAccount(config.account_no, 'STOCK') except ImportError: self.account = type('StockAccount', (), {'account_id': config.account_no})() PrintLog(LogLevel.INFO, f'- [成功] 交易账号: {config.account_no}') self._init_dummy_positions() self.startMarketDataSubscription() return self.inited def _init_dummy_positions(self): """初始化模拟持仓数据""" dummy_stocks = [ ('600519', '贵州茅台', 100, 2800.0), ('000858', '五粮液', 200, 180.0), ('600036', '招商银行', 500, 42.0), ('000001', '平安银行', 300, 13.5), ] for code, name, volume, price in dummy_stocks: self._positions[code] = { 'stock_code': code, 'stock_name': name, 'volume': volume, 'can_use_volume': volume, 'open_cost': price, 'market_value': volume * price } PrintLog(LogLevel.INFO, f'- [模拟] 已加载 {len(self._positions)} 个持仓') def getStockPosition(self, stock_code: str): """获取持仓 (模拟)""" if stock_code in self._positions: pos = self._positions[stock_code] return type('DummyPos', (), pos)() return None def queryPendingOrder(self, stock_code: str, tag: str) -> list: """查询挂单""" return [o for o in self._pending_orders if o.stock_code == stock_code and (tag is None or getattr(o, 'strategy_name', None) == tag)] def orderAsync(self, stock_code, orderVolume, orderType, orderPrice, priceType, orderRemark, strategy_name): """异步下单 (模拟)""" self._counter += 1 order_id = f"DUMMY{self._counter:06d}" seq = self._counter order = DummyOrder( stock_code=stock_code, order_id=order_id, status='reported', price=orderPrice, volume=orderVolume ) order.strategy_name = strategy_name order.order_remark = orderRemark self._pending_orders.append(order) response = DummyOrderResponse( order_id=order_id, stock_code=stock_code, seq=seq, error_msg='成功', strategy_name=strategy_name ) response.order_remark = orderRemark eBus.event_bus.publish(eBus.MarketOrderCreated, response) PrintLog(LogLevel.INFO, f'- [模拟下单] {stock_code} 数量:{orderVolume} 价格:{orderPrice} 订单号:{order_id}') # 模拟成交 (80% 概率) if random.random() > 0.2: threading.Timer(random.uniform(0.5, 3.0), self._simulate_trade, args=(stock_code, order_id, orderPrice, orderVolume, strategy_name)).start() return 0 def _simulate_trade(self, stock_code, order_id, price, volume, strategy_name): """模拟成交""" trade = DummyTrade( stock_code=stock_code, trade_id=f"TRADE{self._counter:06d}", price=price, volume=volume, strategy_name=strategy_name ) trade.trade_time = int(time.strftime('%H%M%S')) trade.order_remark = stock_code if stock_code in self._positions: self._positions[stock_code]['volume'] += volume self._positions[stock_code]['can_use_volume'] += volume eBus.event_bus.publish(eBus.MarketOrderTraded, trade) PrintLog(LogLevel.INFO, f'- [模拟成交] {stock_code} 数量:{volume} 价格:{price}') def cacheStockDetail(self, stock_code: str): """获取股票详情 (模拟)""" if stock_code not in self.details: self.details[stock_code] = { 'InstrumentName': self._get_dummy_name(stock_code), 'UpStopPrice': 0, 'DownStopPrice': 0 } return self.details[stock_code] def _get_dummy_name(self, stock_code: str) -> str: """获取模拟股票名称""" names = { '600519': '贵州茅台', '000858': '五粮液', '600036': '招商银行', '000001': '平安银行', '000002': '万科A', '600000': '浦发银行' } return names.get(stock_code, f'股票{stock_code}') def getInstrumentName(self, stock_code: str) -> str: """获取股票名称""" return self.cacheStockDetail(stock_code)['InstrumentName'] def dailyUpStop(self, stock_code: str): """获取涨停价 (模拟)""" cacheStock = self.cacheStockDetail(stock_code) PrintLog(LogLevel.INFO, f'- [模拟] 获取股票详情: {stock_code} {cacheStock["InstrumentName"]} 涨停价: 0') return 0.0 def dailyDownStop(self, stock_code: str): """获取跌停价 (模拟)""" return 0.0 def startMarketDataSubscription(self): """启动市场数据订阅 (模拟)""" try: self._market_data_thread = threading.Thread(target=self._generate_market_data, daemon=True) self._market_data_thread.start() PrintLog(LogLevel.INFO, f'- [市场数据订阅成功-模拟]') except Exception as e: PrintLog(LogLevel.ERROR, f'- [市场数据订阅失败-{e}]') def stopMarketDataSubscription(self): """停止市场数据订阅""" PrintLog(LogLevel.INFO, '- 停止市场数据订阅 (模拟)') def _generate_market_data(self): """生成模拟市场数据""" stocks = ['600519', '000858', '600036', '000001', '000002', '600000'] base_prices = [2800.0, 180.0, 42.0, 13.5, 10.0, 10.0] while True: try: for i, stock in enumerate(stocks): data = { 'stock_code': stock, 'last_price': base_prices[i] + random.uniform(-1, 1), 'open_price': base_prices[i], 'high_price': base_prices[i] + random.uniform(0, 2), 'low_price': base_prices[i] - random.uniform(0, 2), 'volume': random.randint(1000, 10000), 'timestamp': time.time() } eBus.event_bus.publish(eBus.MarketDataUpdate, data) base_prices[i] = data['last_price'] self.lastMarketDataUpdateTimestamp = time.time() self.isMarketActive = True eBus.event_bus.publish(eBus.EventMarketActiveSwitch, True) time.sleep(3) except Exception as e: PrintLog(LogLevel.ERROR, f'- [市场数据模拟异常-{e}]') time.sleep(1) def on_connected(self): print(datetime.datetime.now(), '模拟连接成功') def on_disconnected(self): print(datetime.datetime.now(), '模拟连接断开') def on_stock_order(self, order): pass def on_stock_trade(self, trade): eBus.event_bus.publish(eBus.MarketOrderTraded, trade) def on_order_stock_async_response(self, response): eBus.event_bus.publish(eBus.MarketOrderCreated, response) def on_order_error(self, order_error): print(f"\n模拟委托报错回调 {order_error}") def on_account_status(self, status): print(datetime.datetime.now(), status) qmtv = DummyQmtV()