774170ec05
采集层(多源各下): - baostock: 日线全字段全量(baostock_daily_fullmarket) + 15min全市场 + 静态(基础/复权/分红/季频/三表) + 成份股 - akshare: 静态(估值/龙虎榜/大宗/融资融券/北向/指数成分/行业/股本/解禁/业绩预告) - xtdata(miniQMT): build_daily_from_xtdata + daily_update_xtdata 数据补全 P0: - ETF全市场: universe 扩展 沪深A股∪ETF∪基金(7414), dividend_type='front' 前复权 - 历史成份股(治幸存者偏差): index_const_hist_download 深证/国证 adjust_cni 4指数 + 中证1000/2000快照 + 新浪交叉校验 - 退市K线: baostock_delisted_download + import_delisted_to_db(实证 Day1 fetch_all_stocks 已含退市) 灌库: - import_baostock_to_db: daily_baostock_full(5537股/1826万行,18字段)+ bs_index_constituent + bs_adjust_factor - INSERT OR REPLACE 幂等, WAL+busy_timeout, dbbardata 不碰 每日增量 #7(用户决策A: VPS直跑): - daily_update_static: login探针防黑名单graceful skip + LOOKBACK7 + query_stock_basic含退市 + INSERT OR REPLACE + QUERY_COUNT守48000/天 设计文档: spec(13节三层融合) + P0 plan + 数据gap设计
125 lines
4.0 KiB
Python
125 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""mootdx 分钟K线历史深度测试 —— 周一开盘后跑(非交易时段通达信全服务器返空)
|
|
|
|
目的:对比 miniQMT 模拟端 1m/5m/15m 统一只给 ~12 个月(2025-07-16 起),
|
|
看通达信公共行情服务器能给多深的分钟历史。
|
|
|
|
用法:
|
|
venv311/bin/python scripts/data_platform/test_mootdx_depth.py
|
|
结果写 scripts/data_platform/_mootdx_depth_result.txt 并打印。
|
|
|
|
注意:
|
|
- 频率值表(mootdx 0.11.7 实测): 0=5m 1=15m 2=30m 3=60m 4=日 8=1分钟 9=日线
|
|
- bars 返回【不复权】原始价;offset 硬上限 800,更深历史靠 start 分页
|
|
- 非交易时段(收盘后/周末)通达信服务器 quotes+bars 全频率返空,连日线都不给
|
|
"""
|
|
import socket
|
|
import sys
|
|
import datetime
|
|
from mootdx.quotes import Quotes
|
|
|
|
_TDX_SERVERS = [
|
|
('119.97.185.59', 7709), ('124.70.133.119', 7709), ('116.205.183.150', 7709),
|
|
('123.60.73.44', 7709), ('116.205.163.254', 7709), ('121.36.225.169', 7709),
|
|
('123.60.70.228', 7709), ('124.71.9.153', 7709), ('110.41.147.114', 7709),
|
|
('124.71.187.122', 7709),
|
|
]
|
|
|
|
|
|
def _probe(ip, port, timeout=2.0):
|
|
try:
|
|
with socket.create_connection((ip, port), timeout=timeout):
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def _n(x):
|
|
"""统一求长度, 规避空 DataFrame 的 bool 歧义坑"""
|
|
if x is None:
|
|
return 0
|
|
try:
|
|
return len(x)
|
|
except Exception:
|
|
return 0
|
|
|
|
|
|
def find_server(symbol='600519'):
|
|
"""遍历服务器, 返回第一个能返回日线 bars 的(交易日内才有)"""
|
|
for ip, port in _TDX_SERVERS:
|
|
if not _probe(ip, port):
|
|
continue
|
|
try:
|
|
c = Quotes.factory(market='std', server=(ip, port))
|
|
d = c.bars(symbol=symbol, frequency=9, offset=5)
|
|
if _n(d) > 0:
|
|
return ip, c
|
|
except Exception:
|
|
pass
|
|
return None, None
|
|
|
|
|
|
def test_depth(c, symbol, freq, name, max_pages=200):
|
|
"""start 分页翻到底, 找最早/最新 datetime. 200页: 1m≈20月/5m≈8年/15m≈24年"""
|
|
start = 0
|
|
total = 0
|
|
pages = 0
|
|
earliest = None
|
|
latest = None
|
|
while pages < max_pages:
|
|
try:
|
|
df = c.bars(symbol=symbol, frequency=freq, offset=800, start=start)
|
|
except Exception:
|
|
break
|
|
n = _n(df)
|
|
if n == 0:
|
|
break
|
|
total += n
|
|
try:
|
|
ft = str(df.iloc[0]['datetime'])
|
|
lt = str(df.iloc[-1]['datetime'])
|
|
if earliest is None or ft < earliest:
|
|
earliest = ft
|
|
if latest is None or lt > latest:
|
|
latest = lt
|
|
except Exception:
|
|
pass
|
|
if n < 800:
|
|
break
|
|
start += n
|
|
pages += 1
|
|
return name, total, earliest, latest, pages
|
|
|
|
|
|
def main():
|
|
out = ['mootdx 深度测试 @ %s' % datetime.datetime.now()]
|
|
ip, c = find_server()
|
|
if c is None:
|
|
out.append('!!! 没有服务器返回日线数据 —— 非交易时段(周末/收盘后)通达信全服务器返空')
|
|
out.append('!!! 请周一 09:30 开盘后重跑此脚本')
|
|
msg = '\n'.join(out)
|
|
print(msg)
|
|
with open('_mootdx_depth_result.txt', 'w') as f:
|
|
f.write(msg)
|
|
sys.exit(1)
|
|
|
|
out.append('server: %s' % ip)
|
|
out.append('')
|
|
for sym in ['600519']: # 茅台(2001上市, 老股, 测深度上限最佳)
|
|
out.append('=== %s (茅台) ===' % sym)
|
|
for fr, nm in [(8, '1分钟'), (0, '5分钟'), (1, '15分钟')]:
|
|
name, total, earliest, latest, pages = test_depth(c, sym, fr, nm)
|
|
out.append(' %-6s: %7d 根 | 最早=%s | 最新=%s | 翻%d页'
|
|
% (name, total, earliest, latest, pages))
|
|
out.append('')
|
|
out.append('对比: miniQMT 模拟端 1m/5m/15m 统一 ~12 个月(2025-07-16 起)')
|
|
msg = '\n'.join(out)
|
|
print(msg)
|
|
with open('_mootdx_depth_result.txt', 'w') as f:
|
|
f.write(msg)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|