Files
claude_dev 70d72f35bb chore(vendor): vendor vnpy_qmt 0.3.3 源码自行维护
vnpy_qmt 是唯一券商交易 gateway(关键路径),社区包断更有风险。
按 vnpy_v4.4.0 同一套约定 vendor 源码、sys.path 引用、不 pip install。
- vnpy_qmt_v0.3.3/vnpy_qmt/ (5文件587行) + LICENSE(Apache-2.0) + README
- run_web.py 加 if-exists 路径块,import 方式不变 (from vnpy_qmt import QmtGateway)
Mac 验证: py_compile 全过 + import 解析到 vendor 副本(仅卡 xtquant Win-only,符合预期)
VPS 生产切换(Part B: rsync+pip uninstall+重启+实证) 待确认
2026-07-15 21:15:53 +08:00

150 lines
5.5 KiB
Python

# -*- coding:utf-8 -*-
"""
@FileName :md.py
@Time :2022/11/8 17:14
@Author :fsksf
"""
from vnpy.trader.object import (
CancelRequest, OrderRequest, SubscribeRequest, TickData,
ContractData
)
import xtquant.xtdata
import xtquant.xttrader
import xtquant.xttype
from vnpy_qmt.utils import (
From_VN_Exchange_map, TO_VN_Exchange_map, to_vn_contract,
TO_VN_Product, to_vn_product, timestamp_to_datetime,
to_qmt_code
)
from vnpy.trader.utility import ZoneInfo
ZONE_INFO = ZoneInfo("Asia/Shanghai")
class MD:
def __init__(self, gateway):
self.gateway = gateway
self.th = None
self.limit_ups = {}
self.limit_downs = {}
def close(self) -> None:
pass
def subscribe(self, req: SubscribeRequest) -> None:
return xtquant.xtdata.subscribe_quote(
stock_code=f'{req.symbol}.{From_VN_Exchange_map[req.exchange]}',
period='tick',
callback=self.on_tick
)
def connect(self, setting: dict) -> None:
self.get_contract()
return
def get_contract(self):
self.write_log('开始获取标的信息')
contract_ids = set()
bk = ['上期所', '上证A股', '上证B股', '中金所', '创业板', '大商所',
'沪市ETF', '沪市指数', '沪深A股',
'沪深B股', '沪深ETF', '沪深指数', '深市ETF',
'深市基金', '深市指数', '深证A股', '深证B股', '科创板', '科创板CDR',
]
for sector in bk:
print(sector)
stock_list = xtquant.xtdata.get_stock_list_in_sector(sector_name=sector)
for symbol in stock_list:
if symbol in contract_ids:
continue
contract_ids.add(symbol)
info = xtquant.xtdata.get_instrument_detail(symbol)
contract_type = xtquant.xtdata.get_instrument_type(symbol)
if info is None or contract_type is None:
continue
try:
exchange = TO_VN_Exchange_map[info['ExchangeID']]
except KeyError:
print('本gateway不支持的标的', symbol)
continue
if exchange not in self.gateway.exchanges:
continue
product = to_vn_product(contract_type)
if product not in self.gateway.TRADE_TYPE:
continue
c = ContractData(
gateway_name=self.gateway.gateway_name,
symbol=info['InstrumentID'],
exchange=exchange,
name=info['InstrumentName'],
product=product,
pricetick=info['PriceTick'],
size=100,
min_volume=100
)
self.limit_ups[c.vt_symbol] = info['UpStopPrice']
self.limit_downs[c.vt_symbol] = info['DownStopPrice']
self.gateway.on_contract(c)
self.write_log('获取标的信息完成')
def on_tick(self, datas):
for code, data_list in datas.items():
symbol, suffix = code.rsplit('.')
exchange = TO_VN_Exchange_map[suffix]
for data in data_list:
ask_price = data['askPrice']
ask_vol = data['askVol']
bid_price = data['bidPrice']
bid_vol = data['bidVol']
dt = timestamp_to_datetime(data['time'])
dt = dt.replace(tzinfo=ZONE_INFO)
tick = TickData(
gateway_name=self.gateway.gateway_name,
symbol=symbol,
exchange=exchange,
datetime=dt,
last_price=data['lastPrice'],
volume=data['volume'],
open_price=data['open'],
high_price=data['high'],
low_price=data['low'],
pre_close=data['lastClose'],
limit_down=0,
limit_up=0,
ask_price_1=ask_price[0],
ask_price_2=ask_price[1],
ask_price_3=ask_price[2],
ask_price_4=ask_price[3],
ask_price_5=ask_price[4],
ask_volume_1=ask_vol[0],
ask_volume_2=ask_vol[1],
ask_volume_3=ask_vol[2],
ask_volume_4=ask_vol[3],
ask_volume_5=ask_vol[4],
bid_price_1=bid_price[0],
bid_price_2=bid_price[1],
bid_price_3=bid_price[2],
bid_price_4=bid_price[3],
bid_price_5=bid_price[4],
bid_volume_1=bid_vol[0],
bid_volume_2=bid_vol[1],
bid_volume_3=bid_vol[2],
bid_volume_4=bid_vol[3],
bid_volume_5=bid_vol[4],
)
contract = self.gateway.get_contract(tick.vt_symbol)
if contract:
tick.name = contract.name
tick.limit_up = self.limit_ups.get(tick.vt_symbol, None)
tick.limit_down = self.limit_downs.get(tick.vt_symbol, None)
self.gateway.on_tick(tick)
def write_log(self, msg):
self.gateway.write_log(f"[ md ] {msg}")