🚀 AI 一键生成 qmt 策略代码
立即体验

QMT xtdata 获取指数行情时 volume (成交量) 整数溢出怎么办?

qmt | 发布时间: 2026/6/2
以下内容由 EasyQuant 生成。

问题描述

xtdata获取指数数据market_data的volume值可能存在整数溢出问题

import pandas as pd
from tqdm import tqdm
from xtquant import xtdata
import time

STOCK_LIST = xtdata.get_stock_list_in_sector('沪深A股')
INDEX_LIST = xtdata.get_stock_list_in_sector('沪深指数')
ETF_LIST = xtdata.get_stock_list_in_sector('沪深ETF')

ALL_CODE = INDEX_LIST

# 按装订区域中的绿色按钮以运行脚本。
if __name__ == '__main__':

start = time.time()
# xtdata.download_history_data2数据量大时会超时
for code in tqdm(ALL_CODE):
xtdata.download_history_data(code,'1d')

df_d = xtdata.get_market_data_ex([],stock_list=ALL_CODE)
df_l = [df.assign(stock_code=code,name = xtdata.get_instrument_detail(stock_code=code)['InstrumentName']) for code,df in df_d.items()]
df = pd.concat(df_l,axis=0).dropna()

print(f'Elapsed time: {time.time()-start}')

解决方案

在使用 QMT 的 xtquant.xtdata 获取 A 股指数(如上证指数、深证成指等)的历史行情时,确实经常会遇到 volume(成交量)字段出现负数或异常小的值。这通常是由于**整数溢出(Integer Overflow)**引起的。

为什么会发生整数溢出?

A 股主要指数的日成交量非常巨大。例如,上证指数的日成交量经常在几十亿手(或百亿股)级别。如果底层 C++ 接口或 Pandas 转换时使用了 32 位有符号整数(int32),其最大能表示的值为 2,147,483,647。当真实成交量超过这个数值时,就会发生溢出,导致最高位符号位被改变,从而在 Python 中显示为负数。

解决方案

方案一:通过代码手动修复溢出值

如果底层数据是以 32 位无符号整数传输,但在某处被错误解析为 32 位有符号整数,你可以通过加上 $2^{32}$ (即 4294967296) 来还原真实的成交量。在合并 DataFrame 后,可以加上这样一步处理:

import pandas as pd
import numpy as np

# 假设 df 是你合并后的 DataFrame
# 修复 volume 溢出问题 (将负数转换回真实的无符号整数值)
df['volume'] = np.where(df['volume'] < 0, df['volume'] + 4294967296, df['volume'])

# 确保数据类型为 float64 或 int64 以容纳大数值
df['volume'] = df['volume'].astype('float64')

方案二:使用 amount (成交额) 替代

在很多量化分析场景中,对于指数而言,成交额 (amount) 往往比成交量 (volume) 更具参考价值,且 amount 字段底层通常使用双精度浮点数 (double / float64) 存储,不会发生溢出问题。如果你的策略允许,建议直接使用 amount 字段。

方案三:更新 xtquant 版本

迅投官方在不断迭代 xtquant 库,部分新版本可能已经将底层的数据结构升级为 64 位整数 (int64long long) 来彻底解决大盘指数成交量溢出的问题。建议通过 pip 检查并更新到最新版本的 xtquant

pip install --upgrade xtquant

优化后的完整代码示例

结合你的代码,优化后的安全版本如下:

import pandas as pd
import numpy as np
from tqdm import tqdm
from xtquant import xtdata
import time

# 获取指数列表
INDEX_LIST = xtdata.get_stock_list_in_sector('沪深指数')
ALL_CODE = INDEX_LIST

if __name__ == '__main__':
    start = time.time()
    
    # 1. 下载历史数据
    print("开始下载历史数据...")
    for code in tqdm(ALL_CODE):
        xtdata.download_history_data(code, '1d')

    # 2. 获取数据
    print("开始获取并处理数据...")
    df_d = xtdata.get_market_data_ex([], stock_list=ALL_CODE, period='1d')
    
    df_l = []
    for code, df in df_d.items():
        if not df.empty:
            # 获取合约名称
            detail = xtdata.get_instrument_detail(stock_code=code)
            name = detail['InstrumentName'] if detail else '未知'
            
            # 赋值新列
            df = df.assign(stock_code=code, name=name)
            df_l.append(df)

    if df_l:
        # 3. 合并数据
        final_df = pd.concat(df_l, axis=0).dropna()
        
        # 4. 修复 volume 整数溢出问题
        # 将负数加上 2^32,并转换为 float64 防止再次溢出
        final_df['volume'] = np.where(
            final_df['volume'] < 0, 
            final_df['volume'] + 4294967296, 
            final_df['volume']
        )
        final_df['volume'] = final_df['volume'].astype('float64')
        
        print(final_df[['stock_code', 'name', 'close', 'volume', 'amount']].tail())
    else:
        print("未获取到有效数据")

    print(f'Elapsed time: {time.time()-start:.2f} seconds')

通过上述 np.where 的处理,可以有效修正因 32 位有符号整数限制导致的指数成交量负数问题。