【深度学习量化交易19】行情数据获取方式比测(1)——基于miniQMT的量化交易回测系统开发实记

news2025/4/25 16:16:51
我是Mr.看海,我在尝试用信号处理的知识积累和思考方式做量化交易,应用深度学习和AI实现股票自动交易,目的是实现财务自由~
目前我正在开发基于miniQMT的量化交易系统——看海量化交易系统。

经常使用MiniQMT的朋友都知道,xtquant的行情模块为我们提供了多种数据获取方式,比较常用的就是:

  • 单股订阅 subscribe_quote
  • 订阅全推行情 subscribe_whole_quote
  • 获取全推数据 get_full_tick

在选择具体方法之前,有几个问题不得不弄清楚:

  1. tick数据分别是多久更新一次?(是不是都是3秒?)
  2. 使用不同的模式,数据延迟分别是多少?
  3. K线数据获取有何需要注意之处?
  4. 这三种方式,在订阅和数据返回方面有和异同?
  5. 对于运行tick触发、K线触发、自定义时间触发策略,分别用哪种方法最好?(关于这几种触发方式的设计,在之前的文章里有讲过)

实践是检验真理的唯一标准,对此我做了以下几组实验:

一、验证tick数据更新频率

1.1 单股订阅 subscribe_quote

通过下边代码,我订阅了10只沪深股票,并实时打印。

# 测试单股订阅subscribe_quote
from xtquant import xtdata
import time
import datetime

# 1.定义回调函数
def on_data(datas):
    """数据更新回调函数"""
    # 获取当前时间(精确到毫秒)
    current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
    print(f"\n当前时间: {current_time}")
    
    # datas格式为 { stock_code : [data1, data2, ...] }
    code_list = list(datas.keys())
    
    # 遍历所有股票代码及其数据
    for stock_code in datas:
        print(f"\n股票: {stock_code}")
        for data in datas[stock_code]:
            if 'time' in data:
                # 将数值时间转换为可读时间(假设time是整数时间戳,单位是秒)
                time_value = data['time']
                readable_time = ""
                
                # 根据time的格式进行转换
                if isinstance(time_value, int):
                    if time_value > 10000000000:  # 毫秒级时间戳
                        readable_time = datetime.datetime.fromtimestamp(time_value/1000).strftime('%Y-%m-%d %H:%M:%S')
                    else:  # 秒级时间戳
                        readable_time = datetime.datetime.fromtimestamp(time_value).strftime('%Y-%m-%d %H:%M:%S')
                elif isinstance(time_value, str):
                    # 如果是字符串格式,则直接打印
                    readable_time = time_value
                
                print(f"时间戳: {time_value}, 可读时间: {readable_time}")
            
            # 打印完整数据
            print(data)
    '''
    # 在回调中获取完整K线数据
    klines = xtdata.get_market_data_ex(
        field_list=["time", "open", "high", "low", "close", "volume"],
        stock_list=code_list,
        start_time="20241213",
        period="1m"
    )
    print("\n完整K线数据:")
    print(klines)
    '''
# 2.订阅10只股票数据
stock_codes = [
    "000001.SZ",  # 平安银行
    "000002.SZ",  # 万科A
    "000063.SZ",  # 中兴通讯
    "000333.SZ",  # 美的集团
    "000651.SZ",  # 格力电器
    "000858.SZ",  # 五粮液
    "600036.SH",  # 招商银行
    "600519.SH",  # 贵州茅台
    "601318.SH",  # 中国平安
    "601988.SH"   # 中国银行
]

# 循环订阅每只股票
for stock_code in stock_codes:
    xtdata.subscribe_quote(
        stock_code=stock_code,
        period="tick",            # 日K线
        count=1,                # 获取当天所有数据
        callback=on_data        # 设置回调函数
    )
    print(f"已订阅: {stock_code}")

# 3.保持程序运行
print("开始接收实时数据...")
try:
    xtdata.run()
except KeyboardInterrupt:
    print("程序结束")

分析其打印数据,能得到几点结论:

(1)时间戳可能会“早于”系统时间。

例如下边这段数据,在系统时间为11:14:38.898时,就获取到了时间戳为11:14:39的数据。这可能是由于系统时间不准,也可能是服务器发来的数据标记的时间就是超前的。

不过只要和回测所用数据标准一致就行。

当前时间: 2025-03-21 11:14:38.898

股票: 000858.SZ
时间戳: 1742526879000, 可读时间: 2025-03-21 11:14:39
{'time': 1742526879000, 'lastPrice': 135.31, 'open': 135.7, 'high': 137.5, 'low': 135.14000000000001, 'lastClose': 135.99, 'amount': 1318754346.0, 'volume': 96871, 'pvolume': 0, 'stockStatus': 3, 'openInt': 13, 'transactionNum': 37317, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [135.3, 135.33, 135.34, 135.36, 135.37], 'bidPrice': [135.27, 135.26, 135.23, 135.22, 135.21], 'askVol': [9, 6, 5, 2, 5], 'bidVol': [6, 7, 8, 307, 61], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}

(2)收到的数据每次是一帧,对于同一只股票,获取到数据的时间(秒)可能不是3的倍数。

尽管很多数据的时间戳,秒级都是0、3、6,但是也会有一些是2,5,8等等。

当前时间: 2025-03-21 11:22:02.445

股票: 601318.SH
时间戳: 1742527322000, 可读时间: 2025-03-21 11:22:02
{'time': 1742527322000, 'lastPrice': 52.08, 'open': 52.4, 'high': 52.660000000000004, 'low': 52.02, 'lastClose': 52.49, 'amount': 2057214912.0, 'volume': 392893, 'pvolume': 0, 'stockStatus': 3, 'openInt': 13, 'transactionNum': 63022, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [52.08, 52.09, 52.1, 52.11, 52.120000000000005], 'bidPrice': [52.07, 52.06, 52.050000000000004, 52.04, 52.03], 'askVol': [24, 173, 111, 61, 153], 'bidVol': [44, 176, 336, 218, 784], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}  

(3)订阅量提升后,可能会阻塞程序。

当订阅数量达到300后,程序处理可能会阻塞,其后果需要验证【1】。

1.2 订阅全推行情 subscribe_whole_quote

通过下边的代码,我订阅了全部沪市股票,并实时打印。

# 测试全推数据
from xtquant import xtdata
import time
import datetime

def on_market_data(data):
    """全市场数据回调"""
    # 显示当前时间
    current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
    print(f"\n当前时间: {current_time}")
    # 只打印股票数量和股票的数据
    stock_count = len(data)
    print(f"收到{stock_count}只股票的数据")
    
    if data:  # 如果有数据
        # 获取最多10只股票的数据
        stock_list = list(data.keys())[:]
        print(f"显示前{len(stock_list)}只股票的数据:")
        
        for i, stock_code in enumerate(stock_list, 1):
            stock_data = data[stock_code]
            # 转换时间戳为可读时间
            timestamp_ms = stock_data['time']
            readable_time = datetime.datetime.fromtimestamp(timestamp_ms/1000).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
            print(f"\n{i}. 股票 {stock_code} 的数据时间: {readable_time}")
            print(f"数据详情:")
            print(stock_data)
# 订阅沪深两市的tick数据
seq = xtdata.subscribe_whole_quote(
    code_list=['SH'],  # 上海市场
    callback=on_market_data
)
# 运行程序
print("开始接收数据...")
try:
    xtdata.run()
except KeyboardInterrupt:
    xtdata.unsubscribe_quote(seq)
    print("程序结束")

得到的回调数据不是沪市股票数据同时发来,而是“一堆一堆”地,通常“一堆”数据中有几十只股票。

当前时间: 2025-03-20 13:52:28.895
收到56只股票的数据

对于其中的单只股票,又呈现以下几种现象:

(1)结论1:tick以不严格等于3s的时间间隔获取

股票 600132.SH 的数据时间: 2025-03-20 13:52:04.000
数据详情:
{'time': 1742449924000, 'lastPrice': 58.42, 'open': 60.0, 'high': 60.0, 'low': 58.410000000000004, 'lastClose': 59.7, 'amount': 215877600.0, 'volume': 36620, 'pvolume': 3661980, 'stockStatus': 0, 'openInt': 13, 'transactionNum': 0, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [58.45, 0.0, 0.0, 0.0, 0.0], 'bidPrice': [58.42, 0.0, 0.0, 0.0, 0.0], 'askVol': [49, 0, 0, 0, 0], 'bidVol': [58, 0, 0, 0, 0], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}
股票 600132.SH 的数据时间: 2025-03-20 13:52:07.000
数据详情:
{'time': 1742449927000, 'lastPrice': 58.45, 'open': 60.0, 'high': 60.0, 'low': 58.410000000000004, 'lastClose': 59.7, 'amount': 215895100.0, 'volume': 36623, 'pvolume': 3662280, 'stockStatus': 0, 'openInt': 13, 'transactionNum': 0, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [58.45, 0.0, 0.0, 0.0, 0.0], 'bidPrice': [58.43, 0.0, 0.0, 0.0, 0.0], 'askVol': [47, 0, 0, 0, 0], 'bidVol': [3, 0, 0, 0, 0], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}
股票 600132.SH 的数据时间: 2025-03-20 13:52:10.000
数据详情:
{'time': 1742449930000, 'lastPrice': 58.42, 'open': 60.0, 'high': 60.0, 'low': 58.410000000000004, 'lastClose': 59.7, 'amount': 216082100.0, 'volume': 36655, 'pvolume': 3665480, 'stockStatus': 0, 'openInt': 13, 'transactionNum': 0, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [58.44, 0.0, 0.0, 0.0, 0.0], 'bidPrice': [58.43, 0.0, 0.0, 0.0, 0.0], 'askVol': [3, 0, 0, 0, 0], 'bidVol': [1, 0, 0, 0, 0], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}
22. 股票 600132.SH 的数据时间: 2025-03-20 13:52:14.000
数据详情:
{'time': 1742449934000, 'lastPrice': 58.42, 'open': 60.0, 'high': 60.0, 'low': 58.410000000000004, 'lastClose': 59.7, 'amount': 216123000.0, 'volume': 36662, 'pvolume': 3666180, 'stockStatus': 0, 'openInt': 13, 'transactionNum': 0, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [58.44, 0.0, 0.0, 0.0, 0.0], 'bidPrice': [58.42, 0.0, 0.0, 0.0, 0.0], 'askVol': [2, 0, 0, 0, 0], 'bidVol': [25, 0, 0, 0, 0], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}
13. 股票 600132.SH 的数据时间: 2025-03-20 13:52:16.000
数据详情:
{'time': 1742449936000, 'lastPrice': 58.44, 'open': 60.0, 'high': 60.0, 'low': 58.410000000000004, 'lastClose': 59.7, 'amount': 216187200.0, 'volume': 36673, 'pvolume': 3667280, 'stockStatus': 0, 'openInt': 13, 'transactionNum': 0, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [58.44, 0.0, 0.0, 0.0, 0.0], 'bidPrice': [58.42, 0.0, 0.0, 0.0, 0.0], 'askVol': [9, 0, 0, 0, 0], 'bidVol': [15, 0, 0, 0, 0], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}

比如上边这个例子,时间戳的秒级分别为4、7、10、14、16,时间间隔出现了2、3、4秒这几种情况。经验证,后期下载下来的数据的时间戳与此一致。

(2)结论2:可能会出现“漏拍”

12. 股票 600177.SH 的数据时间: 2025-03-20 13:52:14.000
数据详情:
{'time': 1742449934000, 'lastPrice': 8.07, 'open': 8.120000000000001, 'high': 8.13, 'low': 8.07, 'lastClose': 8.11, 'amount': 145295300.0, 'volume': 179710, 'pvolume': 17970989, 'stockStatus': 0, 'openInt': 13, 'transactionNum': 0, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [8.08, 0.0, 0.0, 0.0, 0.0], 'bidPrice': [8.07, 0.0, 0.0, 0.0, 0.0], 'askVol': [1816, 0, 0, 0, 0], 'bidVol': [9792, 0, 0, 0, 0], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}
14. 股票 600177.SH 的数据时间: 2025-03-20 13:52:17.000
数据详情:
{'time': 1742449937000, 'lastPrice': 8.08, 'open': 8.120000000000001, 'high': 8.13, 'low': 8.07, 'lastClose': 8.11, 'amount': 145303400.0, 'volume': 179720, 'pvolume': 17971989, 'stockStatus': 0, 'openInt': 13, 'transactionNum': 0, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [8.08, 0.0, 0.0, 0.0, 0.0], 'bidPrice': [8.07, 0.0, 0.0, 0.0, 0.0], 'askVol': [1829, 0, 0, 0, 0], 'bidVol': [9809, 0, 0, 0, 0], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}
16. 股票 600177.SH 的数据时间: 2025-03-20 13:52:23.000
数据详情:
{'time': 1742449943000, 'lastPrice': 8.07, 'open': 8.120000000000001, 'high': 8.13, 'low': 8.07, 'lastClose': 8.11, 'amount': 145304200.0, 'volume': 179721, 'pvolume': 17972089, 'stockStatus': 0, 'openInt': 13, 'transactionNum': 0, 'lastSettlementPrice': 0.0, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [8.08, 0.0, 0.0, 0.0, 0.0], 'bidPrice': [8.07, 0.0, 0.0, 0.0, 0.0], 'askVol': [1829, 0, 0, 0, 0], 'bidVol': [9808, 0, 0, 0, 0], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}

上边的例子可以看出,13:52:17到13:52:23之间,漏掉了“一拍”。这可能是由于这“一拍”没有成交量引起的。

为了验证是否是此原因,我下载了当前的tick数据,这几秒的数据为:

2025-03-20,13:52:14,8.07,8.12,8.13,8.07,8.11,145295288.0,179710,0,0,13,0.0,"[8.08, 8.09, 8.1, 8.11, 8.12]","[8.07, 8.06, 8.05, 8.04, 8.03]","[1816, 3285, 2861, 3111, 3116]","[9792, 12223, 9316, 3182, 5398]"
2025-03-20,13:52:17,8.08,8.12,8.13,8.07,8.11,145303368.0,179720,0,0,13,0.0,"[8.08, 8.09, 8.1, 8.11, 8.12]","[8.07, 8.06, 8.05, 8.04, 8.03]","[1829, 3264, 2861, 3111, 3116]","[9809, 12223, 9316, 3182, 5398]"
2025-03-20,13:52:20,8.08,8.12,8.13,8.07,8.11,145303368.0,179720,0,0,13,0.0,"[8.08, 8.09, 8.1, 8.11, 8.12]","[8.07, 8.06, 8.05, 8.04, 8.03]","[1829, 3264, 2861, 3111, 3116]","[9809, 12223, 9286, 3182, 5398]"
2025-03-20,13:52:23,8.07,8.12,8.13,8.07,8.11,145304175.0,179721,0,0,13,0.0,"[8.08, 8.09, 8.1, 8.11, 8.12]","[8.07, 8.06, 8.05, 8.04, 8.03]","[1829, 3264, 2861, 3111, 3116]","[9808, 12223, 9285, 3182, 5398]"

可见13:52:20的数据和上一个tick的数据完全相同,全推作为增量补充的手段,就会不再推送这一帧数据。

1.3 获取全推数据 get_full_tick

全推数据的测试程序是这样的:

# fulltick行情获取,测试数据更新频率和所谓增量补充数据的概念
from xtquant import xtdata
import time
import datetime

# 循环获取沪深两市的最新行情快照
try:
    while True:
        # 记录当前时间
        start_time = time.time()
        current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        
        # 获取沪深两市的最新行情快照
        snapshot = xtdata.get_full_tick(["SH"])
        
        # 记录获取快照后的时间
        snapshot_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        
        # 计算耗时
        end_time = time.time()
        elapsed_time = (end_time - start_time) * 1000  # 转换为毫秒
        
        # 打印时间和耗时
        print(f"\n当前时间: {current_time}")
        print(f"获取快照后时间: {snapshot_time}")
        print(f"执行get_full_tick耗时: {elapsed_time:.2f}毫秒")
        
        # 打印股票数据
        print(f"当前市场共{len(snapshot)}只股票")
        if snapshot:
            # 展示前3只股票的数据
            stock_list = list(snapshot.keys())[:3]
            for i, stock_code in enumerate(stock_list, 1):
                print(f"\n{i}. 股票{stock_code}的tick数据:")
                print(snapshot[stock_code])
        
        # 等待0.05秒再次执行
        #time.sleep(0.05)
except KeyboardInterrupt:
    print("\n程序已终止")

同样订阅了沪市的全部股票,经验证同样基本是3秒刷新一次。不过这个函数得到的全截面横扫,不会有“跳帧”的情况。

如果在一个tick的3秒钟内不断地获取全推数据,其中会有很多帧数据都是重复的。

二、验证tick数据延迟

这个延迟包含两个层面,一是获取某一秒时间戳的tick数据时,此时的时间延迟多少;二是时间戳标注的数据相对于真实的数据延迟是多少。

对于第二个问题,属于迅投数据本身的质量问题,暂时无法验证。

对于第一个问题,则可以进行对比。同样使用上述的程序,能得到下边的结果:

2.1 单股订阅 subscribe_quote

单股订阅的延迟来自于订阅数量较大时,数据会逐一触发回调。就当前测试程序订阅的10只股票来看,时间戳的时间和系统时间相差均在正负零点几毫秒的误差范围内。

2.2 订阅全推行情 subscribe_whole_quote

大体来说延迟不算太大,时间戳的时间和系统时间相差均在正负零点几毫秒的误差范围内。

2.3 获取全推数据 get_full_tick

对于全部7879只股票,获取到的耗时大概为250毫秒。

三、K线数据获取有何需要注意之处?

3.1 单股订阅 subscribe_quote

经过测试,获取K线数据时(比如1m数据),也是每3秒进入一次回调。

不过经过实测,有两点需要注意:

(1)K线数据内的数据,指的是该周期计算起始点到当前时间点的统计值。

举个例子,下边这两帧信号是一分钟中的最后两帧和下一秒信号的第一帧,例如其中的volume和amount是随着时间的推移增加的,当达到一分钟的最后一帧时,即为该分钟最终的K线数据。下一秒volume和amount重新开始计数,对于其他的参数也是如此。

不过帧数据的时间戳都是精确到分,而不是秒,这点需要注意。

当前时间: 2025-03-20 14:54:55.741

股票: 600036.SH
时间戳: 1742453700000, 可读时间: 2025-03-20 14:55:00
{'time': 1742453700000, 'open': 45.22, 'high': 45.24, 'low': 45.19, 'close': 45.21, 'volume': 2571, 'amount': 11626401.0, 'settlementPrice': 0.0, 'openInterest': 13, 'dr': 1.0, 'totaldr': 5.2226309371267226, 'preClose': 6.9523421295223e-310, 'suspendFlag': 0}

当前时间: 2025-03-20 14:54:58.708

股票: 600036.SH
时间戳: 1742453700000, 可读时间: 2025-03-20 14:55:00
{'time': 1742453700000, 'open': 45.22, 'high': 45.24, 'low': 45.19, 'close': 45.230000000000004, 'volume': 2860, 'amount': 12933130.0, 'settlementPrice': 0.0, 'openInterest': 13, 'dr': 1.0, 'totaldr': 5.2226309371267226, 'preClose': 6.9523421295223e-310, 'suspendFlag': 0}

 股票: 600036.SH
时间戳: 1742453760000, 可读时间: 2025-03-20 14:56:00
{'time': 1742453760000, 'open': 45.230000000000004, 'high': 45.230000000000004, 'low': 45.230000000000004, 'close': 45.230000000000004, 'volume': 157, 'amount': 710015.0, 'settlementPrice': 0.0, 'openInterest': 13, 'dr': 1.0, 'totaldr': 5.2226309371267226, 'preClose': 6.9523421295223e-310, 'suspendFlag': 0}

(2)K线最后一帧数据代表了该周期下K线数据的最终值

标题即是结论,我在盘后下载的数据中对比了。

需要注意的是,一分钟的最后一帧大致在57秒后到达,接收完10组数据大概用了1.8秒。这其中可能打印占用了一定时间,不过在订阅数达到了普通端口权限上线(300只)时,数据接收本身耗时有多长,是需要继续探究的问题【1】,因为过长的接受周期,可能会导致程序阻塞。

3.2 订阅全推行情 subscribe_whole_quote、获取全推数据 get_full_tick

这两个方法均只能获取tick数据。

四、这三种方式,在订阅和数据返回方面有和异同?

4.1 单股订阅 subscribe_quote

所谓单股订阅,自然每次只能订阅一只股票了,为了实现多只股票的订阅,需要使用循环来达到目的。

由于每只股票数据都要单独触发一次回调函数,该过程变得有些低效。对于少量股票订阅该效率尚可,股票数量多了后,可能会带来不能接受的低效。(此处需验证【1】)

4.2 订阅全推行情 subscribe_whole_quote

批量订阅,“成堆”返回数据,数据获取既高效又及时,在大批量数据订阅时的不二选择。

4.3 获取全推数据 get_full_tick

其实数据获取的延迟尚可接受,但是相对于订阅全推行情,总还是难免有滞后。可以在实时性要求不高的场景下作为补充手段,可精确控制查询频率,避免推送机制可能带来的数据洪峰。

五、对于运行tick触发、K线触发、自定义时间触发策略,分别用哪种方法最好?

5.1 tick触发

最佳方法:订阅全推行情 subscribe_whole_quote

次选方法:单股订阅subscribe_quote

也就是两种方式可兼具,根据订阅的股票数量和策略场景自由选择。其实所谓“订阅全推行情”,并不是一定要把沪深的股票全部订阅,是可以指定要订阅的股票代码的。

5.2 K线触发

最佳方法:单股订阅subscribe_quote

理由很简单,另外两种方式无法获取K线数据。

不过需要注意的一点是,单股订阅K线数据,需要能够筛选出K线周期最后一帧的数据,这个在算法上需要有所设计。

其实使用全推的方式也可以模拟计算出K线的效果,但是这样做效率既不高,实现又相对复杂,所以就不考虑了。

5.3 自定义时间触发

最佳方法:单股订阅subscribe_quote+get_market_data_ex、获取全推数据 get_full_tick

次选方法:订阅全推行情 subscribe_whole_quote

自定义时间触发和上述两种触发方式有着本质上的区别:tick或者K线触发都是以数据进行驱动的,即数据到位后触发回调;而自定义时间触发时以时间为驱动的,即到某一时刻点之后自动进入回调程序。

所以对于自定义时间触发的方式,需要在回调程序(或者说策略的主程序)中获取数据。此时如果需要获取的是市场横截面的tick数据,直接使用get_full_tick即可;如果要获取的是K线数据(tick数据也可以),可以通过单股订阅(在初始化程序时订阅),然后通过get_market_data_ex读取数据的方式实现。

至于能够使用subscribe_whole_quote订阅全市场行情,然后使用get_market_data_ex读取数据,这个有待验证是否可行【2】。

注:【1】【2】后续会写一篇文章单独测试单股订阅数达到上限时,获取数据的效率表现;以及测试订阅全市场行情,能否使用get_market_data_ex读取数据。

六、其他

还需要讨论的一个问题是,使用上述订阅/数据获取方式,是否能在回测时回测最大程度还原实盘,其中tick触发是相对简单的,只要数据不阻塞,每一个tick能被正确处理就行;K线数据则需要设计一个比较合理的最后一帧的确认逻辑;自定义时间触发存在一个较为难处理的问题,即 get_full_tick这个函数在回测系统中不易模拟,这需要提前下载全盘的tick数据,再封装一个函数调用当前时间戳下的最新tick数据,一来需要调动处理的数据量巨大,另外能够与真实情况下的全推数据完全保持一致,是较难验证和实现的。

七、下一步考虑

后边还有几件事要做,做完后回测系统就可以跟大家见面了:

  • 策略框架标准化定义
  • 策略通用工具箱完善
  • 策略的项目化管理设置
  • 日志管理
  • 回测结果可视化与评估参数优化
  • 与成熟的回测软件(比如QMT)进行相同策略的对比,以验证软件的有效性

因此,目前的回测系统还不满足放出来给大家使用的状态,待测试稳定后,快捷的安装包版本以及全部开源代码都会放出来给读者朋友们使用。

近期我尽量加快软件和文章更新的频率,尽早让朋友们使用上这个软件。

end、开通miniQMT

上述讲到的系统是基于miniQMT,很多券商都可以开通miniQMT,不过门槛各有不同,很多朋友找不到合适的券商和开通渠道。这里我可以联系券商渠道帮忙开通,股票交易费率是万1,开通成功的朋友都可以免费使用上边开发的“看海量化交易系统”。这个系统还在持续开发的过程中,数据下载的功能已经可以使用,回测部分正在加紧开发,大家可以先开通MiniQMT的权限,这样回测部分的功能放出后就能第一时间用上了~

对于想要开通miniQMT、使用上边开发的“看海量化交易系统”的朋友们,请大家关注一下我的公众号“看海的城堡”,在公众号页面下方点击相应标签即可获取。

相关文章

【深度学习量化交易1】一个金融小白尝试量化交易的设想、畅享和遐想

【深度学习量化交易2】财务自由第一步,三个多月的尝试,找到了最合适我的量化交易路径

【深度学习量化交易3】为了轻松免费地下载股票历史数据,我开发完成了可视化的数据下载模块

【深度学习量化交易4】 量化交易历史数据清洗——为后续分析扫清障碍

【深度学习量化交易5】 量化交易历史数据可视化模块

【深度学习量化交易6】优化改造基于miniQMT的量化交易软件,已开放下载~(已完成数据下载、数据清洗、可视化模块)

【深度学习量化交易7】miniQMT快速上手教程案例集——使用xtQuant进行历史数据下载篇

【深度学习量化交易8】miniQMT快速上手教程案例集——使用xtQuant进行获取实时行情数据篇

【深度学习量化交易9】miniQMT快速上手教程案例集——使用xtQuant获取基本面数据篇

【深度学习量化交易10】miniQMT快速上手教程案例集——使用xtQuant获取板块及成分股数据篇

【深度学习量化交易11】miniQMT快速上手教程——使用XtQuant进行实盘交易篇(一万七千字超详细版本)

【深度学习量化交易12】基于miniQMT的量化交易框架总体构建思路——回测、模拟、实盘通吃的系统架构

【深度学习量化交易13】继续优化改造基于miniQMT的量化交易软件,增加补充数据功能,优化免费下载数据模块体验!

【深度学习量化交易14】正式开源!看海量化交易系统——基于miniQMT的量化交易软件

【深度学习量化交易15】基于miniQMT的量化交易回测系统已基本构建完成!AI炒股的框架初步实现

【深度学习量化交易16】韭菜进阶指南:A股交易成本全解析

【深度学习量化交易17】触发机制设置——基于miniQMT的量化交易回测系统开发实记

【深度学习量化交易18】盘前盘后回调机制设计与实现——基于miniQMT的量化交易回测系统开发实记

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2327185.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

23种设计模式-结构型模式-代理

文章目录 简介问题解决方案代码核心设计要点 总结 简介 代理是一种结构型设计模式,让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问,并允许在把请求提交给对象前后进行一些处理。 问题 为什么要控制对于某个对象的访问呢&#xff1f…

Windows C++ 排查死锁

开发出来应用程序突然间卡死不动&#xff0c;如果其中是因为死锁问题卡列该如何排查 下面是一个简单的死锁例子 #include <iostream> #include <thread> #include <mutex>std::mutex a, b;void function_a() {std::lock_guard<std::mutex> _x(a);std:…

ctfshow

1&#xff0c;web517 通过输入两个单引号让查询语句正常&#xff0c;判断是什么注入&#xff0c;使用的是什么字符 然后我们通过order by 判断回显位&#xff0c;进行一个联合查询注入 获取数据库名 ctfshow的sqli-labs和本地搭建最大的不同&#xff0c;就是show的flag不在当前…

【AI论文】什么、如何、何处以及效果如何?大语言模型测试时缩放技术调研

摘要&#xff1a;随着预训练时代对计算&#xff08;数据和参数&#xff09;缩放的热情逐渐减退&#xff0c;测试时缩放&#xff08;Test-Time Scaling, TTS&#xff09;&#xff0c;也被称作“测试时计算”&#xff0c;已成为一个备受瞩目的研究焦点。近期研究表明&#xff0c;…

大模型学习一:deepseek api 调用实战以及参数介绍

一、说明 DeepSeek&#xff08;杭州深度求索人工智能基础技术研究有限公司&#xff09;是一家专注于大语言模型&#xff08;LLM&#xff09;研发的中国创新型科技公司&#xff0c;成立于2023年7月17日&#xff0c;由幻方量化孵化。其核心产品包括开源推理模型DeepSeek-R1、多模…

MYSQL实现获取某个经纬度区域内的数据

1.创建表 2.插入表数据 INSERT INTO tf_sys.tf_location(name, longitude, latitude, location) VALUES (资料名称1, 114.437625, 16.016914, ST_GeomFromText(POINT(114.437625 16.016914))); INSERT INTO tf_sys.tf_location(name, longitude, latitude, location) VALUES (…

《Python实战进阶》No39:模型部署——TensorFlow Serving 与 ONNX

第39集&#xff1a;模型部署——TensorFlow Serving 与 ONNX 摘要 在机器学习项目中&#xff0c;训练好的模型需要被部署到生产环境中才能发挥实际价值。本集聚焦于如何将模型高效地部署到生产环境&#xff0c;涵盖TensorFlow Serving和ONNX两种主流工具的使用方法。我们将从理…

YOLOv11区域检测

TrackZone 使用Ultralytics YOLO11 -Ultralytics YOLO 文档 如何通过Ultralytics YOLO11 在Python 中使用 TrackZone&#xff1f; 只需几行代码&#xff0c;您就可以在特定区域设置对象跟踪&#xff0c;从而轻松将其集成到您的项目中。 import cv2from ultralytics import s…

手工win提权土豆家族一键梭哈

手工提权 就是在没有工具使用的时候进行提权&#xff08;或者是win版本过新导致的exp作者没更新等&#xff09; 优点就是 随选随用 缺点就是非常繁琐&#xff08;建议是先土豆梭哈然后再手工提权&#xff09; 先进行信息收集&#xff08;这边靶机以例子&#xff09; 这个…

在Qt中直接在构建目录下直接运行.exe文件报错问题分析

在Qt中直接在构建目录下直接运行.exe文件报错问题分析 在学习Qt的过程中遇到过一个问题&#xff0c;直接在Qt构建目录下运行生成的.exe文件时会报错。这和MFC有一定的差别&#xff0c;如果MFC是可以直接运行的。 这是怎么回事呢&#xff1f; 在 Qt 中直接运行构建目录下的 .…

头戴式面捕头盔:高精度捕捉真人面部表情,赋能元宇宙多场景应用

随着元宇宙虚拟人与现实场景的不断交融&#xff0c;如何赋予虚拟人更加自然&#xff0c;灵动的表情成为了业内人员共同讨论的话题&#xff0c;尤其是在虚拟人直播&#xff0c;影视动画制作方面。在虚拟人直播间&#xff0c;丰富的面部表情可以赋予虚拟人更加生动的情感表达&…

LLM大模型教程——什么是AI大模型

引言 当GPT-4展现出惊人的上下文理解能力,当Stable Diffusion创造出媲美人类画师的图像作品,当AlphaFold2破解蛋白质折叠密码——这些里程碑事件标志着人工智能发展进入大模型主导的新纪元。本综述将深入解析这一技术革命的核心载体——AI大模型。 一、AI 大模型是什么​ 概…

机器学习(八):K-Means聚类原理与实战

声明&#xff1a;未经允许禁止转载与抄袭。 前言 k k k均值&#xff08; k k k-means&#xff09;聚类算法是一种经典的无监督聚类算法&#xff0c;本文将深入解析其理论原理&#xff0c;并在真是数据集上进行算法实践&#xff0c;话不多说&#xff0c;请看下文。 算法原理 …

【stm32--HAL库DMA+USART+空闲中断不定长收发数据】

串口通信-Hal库实现不定长度收发&#xff0c;DMAUSART DMA串口STM32CUBEMX配置&#xff08;工程创建&#xff09;基础配置时钟配置工程配置 代码编写现象 DMA 在正式配置之前&#xff0c;我们先来一起简单了解一下DMA。DMA&#xff08;Direct Memory Access&#xff0c;直接内…

【SPP】蓝牙串口配置中LM互操作性要求深度解析

在蓝牙协议栈中&#xff0c;链路管理器&#xff08;Link Manager, LM&#xff09;承担着链路建立、安全管理、功耗控制等核心功能。对于串行端口配置文件&#xff08;SPP&#xff09;而言&#xff0c;LM 的互操作性直接影响连接稳定性、数据安全性和设备功耗。本文基于蓝牙核心…

Java迭代器【设计模式之迭代器模式】

目录 一.前言 二.正文 1.我写的类为什么不能使用增强for(迭代器遍历) 2.代码健全性——迭代器常见的两个Exception 1.NoSuchElementException 2.ConcurrentModificationException 三.后言 一.前言 本篇面向对象主要为和我一样的小白&#xff0c;主要是对迭代器模式的浅…

Eclipse IDE

创建新的Java项目和类 在 Eclipse IDE 中创建一个新的 Java 项目和 Java 类的步骤如下&#xff1a; 1. 创建新的 Java 项目 打开 Eclipse IDE。在菜单栏中&#xff0c;点击 File > New > Java Project。在弹出的对话框中&#xff0c;输入项目名称&#xff08;例如&…

计算机视觉算法实战——基于YOLOv8的自动驾驶障碍物实时感知系统

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 引言&#xff1a;自动驾驶感知系统的关键挑战 自动驾驶技术正以前所未有的速度重塑交通出行方式&#xff…

【boost搜索引擎】下

boost搜索引擎 1. 编写搜索引擎模块 Searcher2. 编写 http_server 模块3. 编写前端模块4. 添加日志5. 补充 去掉暂停词6. 项目扩展方向 1. 编写搜索引擎模块 Searcher 这一模块主要提供建立索引&#xff0c;以及收到用户的发起的http请求通过Get方法提交的搜索关键字&#xff…

数据结构优化DP总结

单调栈&#xff1a;Codeforces Round 622 (Div. 2) C2. Skyscrapers (hard version) 简单来讲就是最后需要呈现出一个单峰数组&#xff0c;使得总高度最高。 最开始想到暴力枚举每一个元素都充当最高的“单峰”&#xff0c;但是这里的 n 过大&#xff0c;这样枚举肯定会TLE。 …