全部
文章&策略
学习干货
问答
官方
用户头像六哥假装量化
2026-06-20 发布
我的一大堆文件就这样消失了????重新登陆也不行!
浏览13
评论1
收藏0
用户头像sh_*178rxh
2026-06-20 发布
最简单的问句就报错了。query_iwencai("市值>1000亿,日成交额>30亿,换手率大于4.5%") --------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) /opt/conda/lib/python3.8/site-packages/mgquant_mod_mindgo/data/trading_dates_store.pyc in __init__(self, f, table, process_fn) /opt/conda/lib/python3.8/site-packages/bcolz/toplevel.py in open(rootdir, mode) 139 else: --> 140 return bcolz.carray(rootdir=rootdir, mode=mode) 141 bcolz/carray_ext.pyx in bcolz.carray_ext.carray.__cinit__() bcolz/carray_ext.pyx in bcolz.carray_ext.carray._read_meta() FileNotFoundError: [Errno 2] No such file or directory: '/home/jovyan/backtest-data/mgquant/stock/trading_dates.bcolz/meta/sizes' During handling of the above exception, another exception occurred: OSError Traceback (most recent call last) /opt/conda/lib/python3.8/site-packages/IPython/core/interactiveshell.py in transform_cell(self, raw_cell) 3207 # use prefilter_lines to handle trailing newlines 3208 # restore trailing newline for ast.parse -> 3209 cell = self.prefilter_manager.prefilter_lines(cell) + '\n' 3210 3211 lines = cell.splitlines(keepends=True) /opt/conda/lib/python3.8/site-packages/IPython/core/prefilter.py in prefilter_lines(self, lines, continue_prompt) 333 for lnum, line in enumerate(llines) ]) 334 else: --> 335 out = self.prefilter_line(llines[0], continue_prompt) 336 337 return out /opt/conda/lib/python3.8/site-packages/IPython/core/prefilter.py in prefilter_line(self, line, continue_prompt) 308 return normal_handler.handle(line_info) 309 --> 310 prefiltered = self.prefilter_line_info(line_info) 311 # print "prefiltered line: %r" % prefiltered 312 return prefiltered /opt/conda/lib/python3.8/site-packages/IPython/core/prefilter.py in prefilter_line_info(self, line_info) 250 """ 251 # print "prefilter_line_info: ", line_info --> 252 handler = self.find_handler(line_info) 253 return handler.handle(line_info) 254 /opt/conda/lib/python3.8/site-packages/IPython/core/prefilter.py in find_handler(self, line_info) 257 for checker in self.checkers: 258 if checker.enabled: --> 259 handler = checker.check(line_info) 260 if handler: 261 return handler /opt/conda/lib/python3.8/site-packages/IPython/core/prefilter.py in check(self, line_info) 414 def check(self, line_info): 415 obj = self.shell.user_ns.get(line_info.ifun) --> 416 if isinstance(obj, Macro): 417 return self.prefilter_manager.get_handler_by_name('macro') 418 else: /opt/conda/lib/python3.8/site-packages/mgquant/utils/lazyimport.pyc in __getattribute__(self, attr) /opt/conda/lib/python3.8/site-packages/mgquant/utils/lazyimport.pyc in _resolve(self) /opt/conda/lib/python3.8/site-packages/mgquant/utils/lazyimport.pyc in _import(self, scope, name) /opt/conda/lib/python3.8/site-packages/mgquant_mod_stock/research_api.pyc in <module> /opt/conda/lib/python3.8/site-packages/mgquant_mod_mindgo/research/research_api.pyc in <module> /opt/conda/lib/python3.8/site-packages/mgquant_mod_stock/data/data_proxy.pyc in __init__(self, data_source) /opt/conda/lib/python3.8/site-packages/mgquant_mod_stock/data/fast_data_source.pyc in get_trading_calendar(self) /opt/conda/lib/python3.8/site-packages/mgquant_mod_mindgo/utils/wrap_utils.pyc in __get__(self, instance, owner) /opt/conda/lib/python3.8/site-packages/mgquant_mod_stock/data/fast_data_source.pyc in _trading_dates(self) /opt/conda/lib/python3.8/site-packages/mgquant_mod_mindgo/data/trading_dates_store.pyc in __init__(self, f, table, process_fn) /opt/conda/lib/python3.8/os.py in makedirs(name, mode, exist_ok) 211 if head and tail and not path.exists(head): 212 try: --> 213 makedirs(head, exist_ok=exist_ok) 214 except FileExistsError: 215 # Defeats race condition when another thread created the path /opt/conda/lib/python3.8/os.py in makedirs(name, mode, exist_ok) 221 return 222 try: --> 223 mkdir(name, mode) 224 except OSError: 225 # Cannot rely on checking for EEXIST, since the operating system OSError: [Errno 30] Read-only file system: '/home/jovyan/backtest-data/mgquant'
浏览10
评论0
收藏0

精华 长期有效,公开征集意见反馈。

用户头像量化官方小助理
2023-03-09 发布
请大家不要客气,任何意见建议可以在这里评论提出。 被采纳后我们将奖励1G研究环境内存 3个月。
浏览22242
评论179
收藏8
用户头像me_361829775857
2026-06-19 发布
最近好几个朋友在后台问,想研究外盘期货,数据从哪找。我一开始也头大,各种交易所格式不统一,自己爬又麻烦。后来发现一个叫CMES金融数据库的地方,东西还挺全,就把它当主要数据源了。今天不聊策略,就单纯扒拉一下它里面到底有哪些数据,每个数据文件里都装着什么字段。看完这篇,你大概就知道这些数据能不能满足你的需求了。 先说说整体感觉吧。这个数据库主要覆盖的是主流的境外期货交易所,比如大家常听的LME(伦敦金属)、CME(芝商所)、ICE(洲际)、EUREX(欧交所)这些。数据种类分得挺细,有最原始的逐笔成交(Tick),有整理好的分钟线,还有日线。对做高频、中频或者单纯想回测个长周期策略的人来说,基本都够用了。 一、 最细的粒度:逐笔成交与委托数据 如果你在研究订单流或者盘口动力学,这个数据跑不掉。但说实话,新手慎入,数据量太大了,一个活跃合约一天的数据就能轻松上G,处理起来挺费劲的。 它里面主要包含这些字段,我拿CME的ES(标普500指数期货)举个例子: timestamp (时间戳): 精确到毫秒的成交时间。这是所有分析的基准,对齐不同数据源就靠它。 price (成交价): 这一笔交易达成的价格。 volume (成交量): 这一笔交易的合约数量。 bid_price / ask_price (买一价/卖一价): 这笔成交发生时的最优买卖报价。注意不是全档位。 bid_size / ask_size (买一量/卖一量): 对应报价上的订单数量。 trade_type (交易类型): 这个挺重要,标识是普通成交、大宗交易还是跨期价差交易等等。不同交易所的标识符可能不同。 有的交易所数据还会有**order_id(订单号)**的变化,能让你跟踪单个订单的生命周期,但这属于更精细的Level 2甚至Level 3范畴了,不是所有品种都有。 为了验证一些盘口微观结构,我调取了CMES金融数据库中过去三年的主力合约数据进行回测,清洗和匹配这些tick数据确实是体力活。如果你只是好奇,可以用他们的接口先下个小样本看看结构,下面是个简单的Python调用示例: # 示例:调用CMES数据接口获取tick数据样例 # 注意:需要先安装他们的SDK,通常 pip install cmes-sdk 就行(具体看官方文档) import cmes_client # 初始化客户端,需要你的认证密钥 client = cmes_client.Client(api_key='your_api_key_here') # 请求ES合约的tick数据,注意参数格式要严格按照文档来 # 这里请求2023年某一天的数据作为例子 try: tick_data = client.get_tick_data( exchange='CME', symbol='ES', date='2023-10-26', data_type='trade' # 获取成交数据 ) print(f"获取到 {len(tick_data)} 条tick记录") # 看看前几条长啥样 print(tick_data.head()) except Exception as e: print(f"调用出错:{e}。请检查入参是否正确,以及账户权限和调用频率限制。") 二、 更常用的:分钟线与日线数据 对于大多数不需要tick级精度的策略回测,分钟线和日线是主力。数据规整,量也小得多。 分钟线数据通常包含以下字段: 字段名 说明 备注 datetime K线起始时间 通常是每分钟的第一秒 open 分钟内的开盘价 high 分钟内的最高价 low 分钟内的最低价 close 分钟内的收盘价 volume 分钟内的总成交量 累计值 open_interest 持仓量 不是所有交易所或周期都提供,日线更常见 日线数据字段和分钟线类似,就是时间周期变成了一天。但日线数据有时会包含调整后的收盘价,用于处理合约展期、分红等事件,这对长期回测避免断层至关重要。我一开始用原始价格回测,结果在换月的时候净值曲线跳得跟心电图似的,后来换了调整后数据才正常。 三、 都覆盖哪些交易所? 这是大家最关心的,我把自己常用的几个交易所和其主打品种列一下,不全,但主流的基本在了: LME (伦敦金属交易所): 铜、铝、锌、镍等基础金属。它的数据结构有点特殊,因为是环形交易,但数据库里一般会处理成连续的电子盘价格。 CME Group (芝商所集团): 这是个巨无霸,旗下包括: CME: 股指期货(标普500、纳斯达克100)、外汇、利率产品。 CBOT: 农产品(大豆、玉米、小麦)、美国国债。 NYMEX: 能源(WTI原油、天然气)、金属(黄金、白银)。 COMEX: 高级金属(黄金、白银、铜)。 ICE (洲际交易所): 布伦特原油、糖、咖啡、可可等软商品,以及美元指数等。 EUREX (欧洲期货交易所): 欧元区股指期货(如德国DAX)、欧洲利率产品。 SGX (新加坡交易所): 富时中国A50指数期货,日经225指数期货等,玩亚太市场的关注。 JPX (日本交易所集团): 日经225、TOPIX指数期货。 HKEX (香港交易所): 恒生指数期货、H股指数期货。 每个交易所的数据细节会有差异,比如价格单位、合约代码规则、交易时间(是否包含盘前盘后)等。下载的时候最好先看看数据说明文档。 四、 一些零散但重要的点 数据质量: 历史数据难免有异常值或缺失。这个数据库的数据是经过基础清洗的,比如过滤明显错误的价格,但使用者最好还是自己再做一遍简单的合理性检查,比如价格跳变是否在合理范围内。 更新频率: 历史数据一般是T+1更新。如果你需要实时的,那是另外的服务。 格式: 通常提供CSV格式,方便用Python的pandas或者R直接读取。也有直接对接数据库的API方式,适合集成到自动化系统里。 找到一份规整、可靠的数据能省下很多前期清洗和整理的功夫,让你更专注于策略逻辑本身。不过也要记住,没有完美的数据,了解你所用数据的来源、处理方法和潜在缺陷,和设计策略本身一样重要。 好了,关于数据字段和内容就先聊这么多。这东西写起来比想象中枯燥,希望能帮到正在找数据的你。如果有什么字段没讲清楚,或者你用的时候发现了什么有意思的细节,欢迎留言聊聊。
浏览36
评论0
收藏0

柜台仿真市价单

用户头像Theworldha
2026-06-18 发布
在柜台仿真环境中,为什么下打单子都是限价单啊?
浏览25
评论1
收藏0
用户头像sh_***174w0d
2026-06-18 发布
在充满不确定性的市场中,能够穿越牛熊、实现长期稳定复利的策略是每位宽客的终极追求。今天,我们将为大家深度揭秘一个经过10年超长周期验证、累计收益高达 3815.57%(38倍)的硬核量化策略。 该策略不仅在收益上具备极强的爆发力,更在防御端做到了极致——长达十年的时间跨度内,最大回撤仅 22.21%。它是如何做到的?我们来看看它的核心亮点与底层逻辑。 ? 核心数据亮点 惊人的收益复利 累计收益:3815.57% 年化收益:45.84% 十年时间实现资产跨越式增长。无论是牛市的主升浪,还是震荡市的局部行情,策略都把握得斩钉截铁。 无惧牛熊的极佳防守(核心优势) 最大回撤:仅 22.21%(且回撤区间在2017-2018年的极端熊市) 索提诺比率:2.402(惩罚下行波动的指标,远大于1,说明下行风险极小) 相比基准收益仅24.09%,策略的超额收益高达3055%,这意味着收益并非靠“死扛”大盘Beta,而是刀刀见血的Alpha(Alpha值高达0.428)。 卓越的盈亏性价比(不对称优势) 盈亏比:2.35(平均每次赚钱的幅度是亏钱的2.3倍) 胜率:53.9% (盈利次数642次,亏损548次) 策略不过度追求不切实际的极限胜率,而是通过“截断亏损,让利润奔跑”,实现了极高的容错率。高达 1.719 的夏普比率证明了其极高的单位风险回报。 ⚙️ 策略底层逻辑揭秘:为什么它能稳赚10年? 通过深度解析策略的底层架构,我们总结出其持续盈利的四大核心武器: 灵敏的“大小盘择时”与“空仓避险”机制(顺势而为) 策略并没有死守某一种风格,而是通过对比代表大盘(沪深300)与小盘(399101)前10日的涨跌动能(Momentum)进行动态切换: 小盘占优时:果断切入高爆发的小市值股票; 大盘占优时:切换至白马/蓝筹阵营避险; 极端泥沙俱下时(大小盘均下跌):策略直接触发**“持币观望”**机制。空仓是规避系统性风险最强大的武器,这也是为什么策略能在历次股灾中保全本金的核心原因。 独创“市场冷暖温度计”,自适应选股 在切换到大盘股(白马股)时,策略引入了独创的市场温度感知模型(Market Temperature)。通过衡量当前大盘处于近一年来的相对高低位,将市场定义为“Cold(冷)”、“Warm(暖)”和“Hot(热)”: 冷冬市场:聚焦极端低估值(PB<1)、高分红潜力的深度价值股; 温和市场:兼顾价值与成长,选取经营现金流与利润均向好的复苏型企业; 过热市场:拥抱高景气度、高成长性(净利润年增>20%)的强势龙头。 这种动态切换避免了传统价值投资的“估值陷阱”,也避开了成长投资的高位接盘。 符合最新“国九条”的高质量微盘股筛选 在小市值选股上,该策略提前迎合了最苛刻的监管与价值要求。并不是无脑炒垃圾股,而是: 严格过滤 ST、新股、停牌股; 硬核财务底线:归母净利润必须>0,且营业总收入 > 1亿!精准清除了潜在的微盘“退市雷”和保壳垃圾股; 在高财务安全垫的基础上,通过 ROE(净资产收益率)和 ROA(总资产收益率)双剑合璧选出真正的“小而美”。 铁血的日内“双重止损防线”(拒绝死扛) 高盈亏比的根源在于其铁血的除草机制: 个股 8% 硬止损:盘中 14:30 和 14:50 分两次检测,跌破成本价8%(平均成本*0.92)立刻无条件清仓,绝不允许单只股票造成重创。 打板监控:对前一日涨停的持仓股进行特别关照。如果次日尾盘无法继续封死涨停,果断获利了结,有效防止了天地板和游资收割。
浏览104
评论0
收藏0
用户头像sh_**772oqg
2026-06-18 发布
概述 在搭建外汇实盘策略、行情监控工具与离线回测框架时,动态增减货币对是高频工程需求。若订阅更新逻辑设计不完善,极易产生行情断档、冗余 Tick 堆积、指标计算延迟抬升等问题,直接干扰交易信号输出,同时造成回测样本失真。本文结合多轮实盘调试与回测校验经验,梳理动态订阅场景下的数据同步痛点,提供分层解耦、增量更新的标准化实现思路,配套可直接集成至量化项目的 Python 代码。 一、量化体系下的动态订阅应用场景 量化开发中存在两类必须动态调整观测标的典型场景: 交互式行情观测系统:根据波动率、流动性人工筛选货币对,短时间内频繁调整订阅清单,多用于盘中机会扫描、多品种对比研究; 自动化轮动策略引擎:模型依据预设阈值自动切换标的池,批量轮换观测品种,适合多因子轮动、跨品种套利类策略。 多数开发者初期会采用「断开连接、全量重订阅」的简易实现,该方式仅适用于离线静态测试,无法满足实盘与高精度回测要求。重连间隙会形成数据空白区间,丢失关键盘口价差;频繁建连销毁还会拉高带宽消耗,甚至触发接口访问限流。 量化工程层面的核心约束:维持单一持久 WebSocket 通道、切换过程无数据缺失、降低无效数据流、控制客户端队列负载,保障实盘信号与回测数据集的完整性。 二、订阅切换引发数据异常的底层成因 外汇实时行情 API 采用「单传输链路 + 多标的主题」架构,服务端仅依据客户端指令推送数据,不会自动做订阅变更优化。未做状态管控时,三类问题会持续影响量化数据质量: 全量重置订阅逻辑:每次清空全部标的再批量订阅,切换窗口期无任何 Tick 输入,K 线重构、滑点统计、回测样本全部出现缺失; 仅新增不注销过期标的:长期累积无用品种数据流,本地消息队列持续膨胀,拖慢指标迭代与模型推理速度; 短周期连续下发订阅指令:频繁增减标的打乱服务端推送时序,产生大量重复、滞后的冗余行情,增加数据清洗开销。 通过日志回放与回测复现可定位问题根源:未隔离「当前有效标的集合」与「目标观测标的集合」,缺少集合差集运算、变更防抖缓冲两层基础处理逻辑。 三、适配量化系统的分层优化架构 3.1 双层解耦模块设计 将行情链路拆分为独立的连接管理层、订阅状态管理层,二者互不耦合,从底层消除切换带来的数据流抖动: 连接管理层:仅负责 WebSocket 心跳保活、异常断线自动重连,无论标的池如何调整,传输通道持续保持连接,避免数据断连; 订阅状态管理层:完成新旧标的集合对比、增减指令拆分,所有订阅变更仅在本模块执行,不改动底层传输链路。 3.2 基于集合差集的增量订阅更新 摒弃数组全覆盖的粗暴写法,使用 Set 结构存储当前生效、目标观测两组标的,通过集合运算区分两类操作: 待新增标的 = 目标集合 − 当前生效集合 待注销标的 = 当前生效集合 − 目标集合 分开发送订阅、注销请求,而非一次性重置全部标的,既消除切换空白窗口,也避免长期堆积无效行情数据。在行情采集与回测数据预处理项目中,我采用 AllTick API 作为数据源,统一规范的请求报文结构,可直接代入差集计算结果下发,降低对接调试成本。 3.3 200ms 防抖缓冲合并短时变更 人工筛选、模型自动轮动均会造成短时间内多次调整标的清单。设置 200ms 缓冲窗口,窗口内全部变更统一合并运算,仅执行一次订阅更新,减少接口请求频次,稳定服务端推送节奏。 3.4 本地队列滞后数据过滤机制 下发注销指令后,服务端会短暂推送延迟 Tick。在数据入计算模块前增加过滤逻辑,剔除已注销货币对的滞后行情,避免脏数据干扰技术指标、量化模型的运算结果。 工程设计核心思路 处理动态订阅应采用「状态集合管控思维」,而非逐次处理单次订阅 / 注销指令。持续维护一份准确的有效标的集合,基于差值做增量更新,代码可维护性更强,便于回测复现、线上故障排查。整套优化的核心目标,并非单纯实现标的切换功能,而是保障数据流在变更过程中完整连续,维持实盘与回测数据的一致性。 四、量化项目可直接集成代码示例 import json import websocket from typing import Set # 当前生效订阅货币对 current_symbols: Set = {"EURUSD", "GBPUSD"} # 切换后的目标观测标的池 target_symbols: Set = {"EURUSD", "USDJPY", "AUDUSD"} # 集合差集计算增减清单 add_list = list(target_symbols - current_symbols) remove_list = list(current_symbols - target_symbols) def refresh_subscription(ws_conn): global current_symbols # 下发新增订阅请求 if add_list: sub_cmd = json.dumps({"action": "subscribe", "params": add_list}) ws_conn.send(sub_cmd) # 下发注销订阅请求 if remove_list: unsub_cmd = json.dumps({"action": "unsubscribe", "params": remove_list}) ws_conn.send(unsub_cmd) # 同步本地有效标的状态 current_symbols = target_symbols.copy() 五、落地适配说明 这套分层增量订阅架构轻量化、无额外算力开销,可适配本地回测采集程序、云部署自动化策略、多品种监控面板等各类量化场景。通过持久连接、变更合并、滞后数据过滤三层优化,解决数据断层、冗余流量、高频请求三类影响数据可信度的核心问题,统一实盘与回测的行情采集逻辑,减少因数据处理差异带来的策略偏差。
浏览42
评论0
收藏0
用户头像sh_****559rtx
2026-06-18 发布
做港股量化,信噪比是决定策略成败的关键之一。我在构建实盘信号系统时,发现直接从WebSocket接入的原始成交数据里,混入了大量的非主动交易,如果不加甄别,因子计算和回测结果都会严重偏离。这里我就结合自己的实战经验,聊聊如何利用成交元数据,把自动对盘和碎股从真实成交中剥离出来。 量化场景下的痛点 量化模型对数据的纯净度要求很高。比如计算主动买入量、资金流向指标时,如果掺入了系统撮合产生的自动对盘,就会虚增交易活跃度,导致假信号。而碎股因为是零散交易,不反映主流资金意图,同样属于噪声。最直接的问题是:数据源通常不会直接给这些成交打上醒目的“噪声”标签,需要我们构建一套自动标记逻辑。手动处理不仅慢,而且无法应用于实盘级别的毫秒级决策。 关键判别字段 从WebSocket推送看,一笔成交记录核心字段如下: 字段 含义 time 成交时间 price 成交价格 volume 成交量 trade_type 类型标识(常不可靠) match_id 撮合编号(若有) 实践中我提炼了三条量化规则: 成交量规则:港股整手多为100股,volume模100非零或小于整手的,判定为碎股。 时间密集规则:对同一标的,如果在极短的时间窗口内出现多笔整手成交,且买卖方向高度对称,那大概率是系统自动对盘。 对手方规则:部分API会暴露买卖经纪商或账号信息。如果买方和卖方同时指向系统专用代码(例如“SYS”),直接归类为自动对盘。 实盘处理逻辑 我使用AllTick等提供的港股WebSocket数据,通过在线方式实现实时打标签。每笔成交推送到达时,立即按上述规则分类,并写入带有标签的时序队列,供下游因子计算和信号生成模块使用。代码示例如下: from websocket import create_connection import json # 这里填你的 AllTick API Token API_TOKEN = '你的API_TOKEN' ws_url = f"wss://ws.alltick.co/stock?token={API_TOKEN}" ws = create_connection(ws_url) # 订阅港股 00700.HK 的成交数据 subscribe_msg = { "action": "subscribe", "symbol": "00700.HK", "type": "transaction" } ws.send(json.dumps(subscribe_msg)) def check_auto_match(tick): # 假设系统自动对盘的成交方为 "SYS" return tick.get('buyer') == 'SYS' and tick.get('seller') == 'SYS' while True: data = ws.recv() tick = json.loads(data) volume = tick.get('volume', 0) if volume < 100: tick['tag'] = '碎股' elif check_auto_match(tick): tick['tag'] = '自动对盘' else: tick['tag'] = '普通成交' print(tick['time'], tick['price'], tick['volume'], tick['tag']) 这个简单的处理逻辑,能让我在实盘中持续输出带标签的成交流,为后续策略提供高质量输入。 对分析工作的提升 有了清晰标签后,我的量化框架只用“普通成交”计算资金流向、量比和主动买卖差等指标,回测的夏普比率明显更稳健。同时,我能监测到自动对盘发生的频率,一旦系统对盘异常增多,可能预示市场深度不足,可作为风控因子之一。碎股的独立统计则帮助我评估零散投资者的行为,进一步丰富多因子体系。总之,从源头把数据洗干净,量化之路会顺畅很多。
浏览43
评论0
收藏0
用户头像sh_****447dvu
2026-06-18 发布
一、研究背景 量化策略的有效性高度依赖订单簿深度数据的时序完整性与长期一致性。在行情基建落地阶段,两类底层数据问题会持续干扰因子测算、回测拟合与实盘信号输出: 盘口渐进漂移:轮询或简易 WebSocket 方案长时间运行后,本地缓存盘口与市场真实流动性产生累积偏差,套利、做市、盘口因子信号失真,回测结论无法复现实盘收益; 重连数据断层:增减监控标的时重建连接,批量调仓、高波动阶段会触发集中重连,服务端序列号重置、本地缓存清空,时序链条断裂,破坏数据集连续性。 以上问题属于行情存储架构缺陷,而非策略逻辑问题。本文分享一套单长连接动态订阅 + 序列号时序校验的增量更新方案,从底层规避数据偏差,配套可直接用于策略开发的 Python 实现,整套规范参考标准化实时行情 API 设计。 二、传统行情接入方案量化层面缺陷 2.1 REST 定时全量快照轮询 采样颗粒度粗,丢失轮询间隔内短时流动性变化,高频因子采样失真; 无增量推送,每次全量覆写、重排序,CPU 开销高,多标的并行监控资源压力大; 高频请求易触发接口限流,长线运行偏差不可逆,回测与实盘数据基准割裂。 2.2 切换标的即重建 WebSocket 连接重建重置 seq 序列号,清空本地深度缓存,时序断裂; 批量切换标的引发重连风暴,加剧数据丢失; 时序断层导致动态调仓逻辑无法在回测中完整复现。 三、三类接入方案量化价值对比 接入方案 核心量化缺陷 本文方案优势 REST 全量轮询 时序精度低、长期漂移、限流风险、高 CPU 占用 仅推送变动价位增量数据,完整保留短时盘口变化,适配高频因子采集 传统 WS 重连订阅 调仓触发重连、时序断裂、缓存清空、回测实盘背离 单长连接动态增删标的,序列号连续无中断,保障时序完整 多 WS 并行连接 心跳、缓存、重连逻辑冗余,内存带宽消耗高,扩容受限 单链路统一管理多标的,架构轻量化,支持数十标的稳定并行采样 四、量化级订单簿深度核心架构 4.1 双层字典轻量化内存存储 行情仅推送变动档位,采用增量更新规则: size > 0:新增 / 更新价位挂单量 size = 0:删除无效价位 存储结构: plaintext {code: {"bids": {}, "asks": {}, "last_seq": sequence_number}} 采用延迟排序机制:写入阶段仅增删数据,仅在因子计算、回测采样时执行排序,降低高频 Tick 下的硬件负载。 4.2 统一指令动态订阅机制 依托cmd_id=22004指令,通过 sub/unsub 实现标的热加载、热移除,全程无需断开连接: sub:新增标的,自动分配独立缓存,多标的数据物理隔离; unsub:移除闲置标的,释放内存带宽资源。 适配量化动态轮动、分批调仓的运行场景,无时序中断。 4.3 seq 序列号连续性校验(防漂移核心) 每个标的独立维护last_seq记录最新序列; 仅当新数据包seq == last_seq + 1才执行盘口更新; 检测到跳号、断序自动清空缓存,等待全量快照重新对齐。 从根源消除长线运行下的隐性盘口漂移,保证回测与实盘时序标准统一。 五、量化场景标准化配置参考 量化场景 原有数据问题 配置参数 校验标准 程序初始化批量订阅 重复拉取快照、缓存初始化混乱 cmd_id=22004、action=sub、标的数组 多标的独立缓存生成,序列从零连续递增 实盘运行新增标的 重连清空历史盘口,时序断裂 cmd_id=22004、action=sub、单标的 存量标的数据完整保留,新增标的独立时序 闲置标的取消监控 冗余数据流占用资源,干扰因子采样 cmd_id=22004、action=unsub 对应标的数据流终止,资源释放 重复发起订阅请求 冗余覆写造成盘口数据抖动 本地集合前置去重 无重复推送,盘口数据平稳 空数组无效订阅请求 无效请求消耗网络资源 前置数组非空校验 空参数请求直接拦截,链路稳态运行 六、实盘高频数据故障与兜底方案 海量 Tick 堆积、数据滞后 极端行情数据包密集,消费速度跟不上写入速度。通过独立协程队列解耦消息接收与盘口更新;本地仅保留前 50 档价位,控制内存上限,保证采样实时性。 网络假存活,行情静止无更新 网络抖动不触发断开回调,但数据流停滞。设置 10 秒心跳探活,连续 3 个周期无有效数据自动重连、清空缓存、同步快照校准盘口。 频繁切换订阅产生幽灵订阅 短时间连续 sub/unsub 造成本地订阅状态与服务端推送不一致。订阅操作加线程锁串行执行;数据包前置校验标的订阅状态,无效数据直接丢弃。 标的代码格式错误,静默丢失行情 代码书写错误无报错,但无任何深度数据返回。配置合法标的白名单,订阅前格式校验,异常输出告警日志,便于快速排查数据集缺失问题。 七、方案适配场景与能力边界 适配场景 盘口高频因子、套利、做市策略实盘数据底座搭建; 多标的动态轮动调仓类策略 7×24 小时无人值守运行; 高精度行情数据集采集、回测数据集清洗对齐。 不支持能力 多 WebSocket 连接间本地缓存同步; 依托实时流式接口回溯历史深度 Tick; cmd_id=22004以外自定义私有订阅指令扩展。 八、完整可落地 Python 源码 import websocket import json import threading # 实时行情WebSocket接入地址 WS_CRYPTO_URL = "wss://quote.alltick.co/quote-b-ws-api?token=YOUR_TOKEN" # 全局订阅集合 + 多标的独立深度存储 subscriptions = set() order_book_depth_storage = {} # {code: {"bids": {}, "asks": {}, "last_seq": 0}} def send_sub_cmd(ws, action: str, code_list: list): """统一订阅/取消订阅指令,适配动态调仓""" if not code_list: return cmd_payload = { "cmd_id": 22004, "action": action, "code": code_list } ws.send(json.dumps(cmd_payload)) # 同步本地存储状态 if action == "sub": for code in code_list: subscriptions.add(code) if code not in order_book_depth_storage: order_book_depth_storage[code] = {"bids": {}, "asks": {}, "last_seq": 0} elif action == "unsub": for code in code_list: subscriptions.discard(code) def update_depth_storage(side_map: dict, price: float, size: float): """深度增量更新逻辑""" if size <= 0: side_map.pop(price, None) else: side_map[price] = size def on_open(ws): """连接初始化,批量订阅核心标的""" init_codes = ["BTCUSDT", "ETHUSDT"] send_sub_cmd(ws, "sub", init_codes) print("行情连接建立,初始订阅标的:", init_codes) def on_message(ws, message): """行情解析、时序校验、盘口更新主逻辑""" if not message: return try: data = json.loads(message) if data.get("type") != "orderbook_diff": return code = data.get("code") seq = data.get("seq") side = data.get("side") price = float(data.get("price", 0)) size = float(data.get("size", 0)) if code not in subscriptions: return cache = order_book_depth_storage[code] last_seq = cache["last_seq"] # 序列断裂重置缓存 if last_seq != 0 and seq != last_seq + 1: cache["bids"].clear() cache["asks"].clear() cache["last_seq"] = 0 print(f"{code} 时序断裂,重置深度缓存") return target_map = cache["bids"] if side == "bid" else cache["asks"] update_depth_storage(target_map, price, size) cache["last_seq"] = seq except Exception as e: print("行情解析异常:", str(e)) def on_error(ws, error): print("WebSocket连接异常:", error) def on_close(ws, close_code, close_msg): print("连接断开,清空全部缓存") subscriptions.clear() order_book_depth_storage.clear() if __name__ == "__main__": ws_app = websocket.WebSocketApp( WS_CRYPTO_URL, on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close ) # 心跳保活配置 ws_app.run_forever(ping_interval=10, ping_timeout=5) 九、实盘部署优化建议 全程采用长连接动态增减标的,禁止频繁重建 WebSocket,守住时序数据连续性; 每 30 分钟调用全量快照接口校准缓存,抵消长线运行微量累积偏差,缩小回测实盘误差; 排序逻辑后置至因子读取阶段,降低高频行情 CPU 占用; 日志重点记录 seq 断裂、心跳超时、非法标的三类异常,便于数据问题复盘追溯; 各标的深度数据独立字典隔离,避免多策略并行时数据交叉污染; 如需持久化行情数据集,采用异步定时快照落盘,不阻塞实时更新链路。
浏览48
评论0
收藏0
用户头像sh_*219t3e
2026-06-18 发布
亲测最好用的AI编写量化策略工具,可以让 AI 直接写各个平台的策略代码,直接生成可运行的策略代码,代码质量远高于直接使用 DeepSeek、Trae 等平台。 大家可以直接用描述策略,然后一键生成可运行的完整策略代码,也可以把它当做一个API 查询工具。 🚀️ AI Supermind工具平台:https://iris.findtruman.io/ai/tool/ai-quantitative-trading/?invite_code=SWJX1ARK
浏览88
评论1
收藏0