企业微信

tushare retry 使用的基础方法

tushare 的接口调用依赖于网络环境,在获取股票、期货数据时可能遇到连接超时、服务器限流或临时故障。直接抛出异常会中断策略执行,因此需要引入重试机制。tushare 官方并未内置 retry 功能,开发者需要自行实现。常见做法是使用 Python 的 retry 库或 tenacity 库,也可以编写简单的循环逻辑。

retry 库为例,安装命令为 pip install retry。在调用 tushare 接口的函数上添加 @retry 装饰器,可以指定重试次数、延迟时间和异常类型。


import tushare as ts

from retry import retry

pro = ts.pro_api('your_token')

@retry(tries=3, delay=2, backoff=2, exceptions=(Exception,))

def get_stock_daily(ts_code, start_date, end_date):

    return pro.daily(ts_code=ts_code, start_date=start_date, end_date=end_date)

df = get_stock_daily('000001.SZ', '20240101', '20240131')

print(df)

该装饰器在函数抛出异常时自动重试,tries 控制总尝试次数,delay 为首次重试等待秒数,backoff 为每次重试的延迟倍数。exceptions 指定捕获的异常类型,通常可设为 Exception 以覆盖网络错误和 API 返回的错误码。

处理 tushare 特有的限流与错误码

tushare 对免费用户有每分钟调用次数限制,超出后返回错误信息或抛出异常。直接使用通用重试可能加剧限流。需要识别 tushare 返回的特定错误,调整重试策略。tushare 的 pro_api 接口在限流时通常抛出 Exception,异常信息包含“抱歉,您每分钟最多访问该接口”等文字。可以编写自定义判断函数,在异常信息匹配限流关键词时延长等待时间。

tushare retry 使用该怎样正确设置重试机制


import time

import tushare as ts

from retry import retry

pro = ts.pro_api('your_token')

def is_rate_limit_error(exception):

    msg = str(exception)

    return '每分钟最多访问' in msg or 'hour' in msg or '频率' in msg

@retry(tries=5, delay=10, backoff=3, exceptions=(Exception,))

def get_futures_daily(ts_code, trade_date):

    try:

        return pro.fut_daily(ts_code=ts_code, trade_date=trade_date)

    except Exception as e:

        if is_rate_limit_error(e):

            time.sleep(60)

        raise e

fut_df = get_futures_daily('CU2401.SHF', '20240115')

print(fut_df)

在函数内部先捕获异常,若为限流错误则强制休眠 60 秒,再重新抛出异常触发装饰器重试。这种方式比单纯增加延迟更有效,因为限流窗口通常为 60 秒。

针对股票和期货数据获取的定制重试

股票数据接口dailydaily_basicmoneyflow 等,期货数据接口如 fut_dailyfut_holdingfut_wsr 等,调用频率和错误模式相似。可以封装一个通用重试函数,接受接口名称和参数,内部动态调用。


import time

import tushare as ts

from retry import retry

pro = ts.pro_api('your_token')

def call_tushare_with_retry(api_name, max_retries=4, base_delay=5, **kwargs):

    """

    通用重试调用 tushare 接口

    api_name: 接口名称,如 'daily', 'fut_daily'

    max_retries: 最大重试次数

    base_delay: 基础延迟秒数

    kwargs: 接口参数

    """

    for attempt in range(max_retries):

        try:

            func = getattr(pro, api_name)

            return func(**kwargs)

        except Exception as e:

            msg = str(e)

            if '每分钟最多访问' in msg or '频率' in msg:

                wait = 60

            elif 'timeout' in msg.lower() or 'connection' in msg.lower():

                wait = base_delay * (2 ** attempt)

            else:

                wait = base_delay

            if attempt == max_retries - 1:

                raise e

            time.sleep(wait)

    return None

stock_data = call_tushare_with_retry('daily', ts_code='600000.SH', start_date='20240101', end_date='20240131')

futures_data = call_tushare_with_retry('fut_daily', ts_code='AU2406.SHF', trade_date='20240120')

该函数根据异常信息区分限流与网络超时,限流固定等待 60 秒,网络错误采用指数退避。max_retries 控制总尝试次数,避免无限重试。getattr(pro, api_name) 动态获取接口方法,适用于股票和期货各类数据接口。

使用 tenacity 实现更灵活的重试

tenacity 库功能更丰富,支持重试条件、停止条件、等待策略和自定义回调。安装 pip install tenacity


import tushare as ts

from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type

pro = ts.pro_api('your_token')

@retry(

    stop=stop_after_attempt(5),

    wait=wait_exponential(multiplier=2, min=4, max=60),

    retry=retry_if_exception_type(Exception),

    reraise=True

)

def get_stock_basic(list_status='L'):

    return pro.stock_basic(list_status=list_status)

df_basic = get_stock_basic()

print(df_basic)

stop_after_attempt(5) 表示最多尝试 5 次,wait_exponential 生成指数退避等待时间,retry_if_exception_type(Exception) 捕获所有异常,reraise=True 在重试耗尽后重新抛出最后一次异常。针对限流,可以在函数内部先休眠再抛出异常,配合 tenacity 的等待策略。


import time

from tenacity import retry, stop_after_attempt, wait_fixed

@retry(stop=stop_after_attempt(6), wait=wait_fixed(10), reraise=True)

def get_futures_holding(ts_code, trade_date):

    try:

        return pro.fut_holding(ts_code=ts_code, trade_date=trade_date)

    except Exception as e:

        if '每分钟最多访问' in str(e):

            time.sleep(60)

        raise e

fut_hold = get_futures_holding('IF2403.CFE', '20240118')

print(fut_hold)

重试机制在量化策略中的实际应用

量化回测或实盘交易中,获取股票和期货的历史数据往往需要批量调用接口。批量循环时,每个品种独立重试可能累积大量时间。可以结合超时控制和并发限制。建议将重试逻辑与数据缓存结合,成功获取的数据写入本地数据库,避免重复请求。


import os

import pandas as pd

import tushare as ts

from tenacity import retry, stop_after_attempt, wait_exponential

pro = ts.pro_api('your_token')

def load_cached_or_fetch(api_name, cache_dir='./cache', **kwargs):

    key = f"{api_name}_{'_'.join(f'{k}={v}' for k,v in kwargs.items())}"

    cache_file = os.path.join(cache_dir, f"{key}.parquet")

    if os.path.exists(cache_file):

        return pd.read_parquet(cache_file)

    @retry(stop=stop_after_attempt(4), wait=wait_exponential(multiplier=2, min=5, max=90), reraise=True)

    def fetch():

        func = getattr(pro, api_name)

        try:

            return func(**kwargs)

        except Exception as e:

            if '每分钟最多访问' in str(e):

                import time

                time.sleep(60)

            raise e

    df = fetch()

    os.makedirs(cache_dir, exist_ok=True)

    df.to_parquet(cache_file)

    return df

# 获取股票日线

stock_daily = load_cached_or_fetch('daily', ts_code='000001.SZ', start_date='20240101', end_date='20240131')

# 获取期货日线

fut_daily = load_cached_or_fetch('fut_daily', ts_code='RB2405.SHF', trade_date='20240125')

缓存层显著减少重试次数,尤其适合多次回测同一批股票或期货合约。注意缓存键应包含所有参数,避免不同参数混淆。

常见陷阱与规避措施

重试次数不宜过多,否则可能被 tushare 记为滥用。一般 3 到 5 次足够。延迟时间不能过短,建议基础延迟 5 秒以上,指数退避最大不超过 120 秒。捕获异常时避免捕获 KeyboardInterruptSystemExit,防止程序无法终止。对于股票停牌、期货合约到期等业务错误,重试无意义,应直接跳过或记录日志。


import logging

logging.basicConfig(level=logging.INFO)

def safe_call(api_name, **kwargs):

    try:

        return call_tushare_with_retry(api_name, max_retries=3, **kwargs)

    except Exception as e:

        logging.error(f"调用 {api_name} 失败,参数 {kwargs},错误 {e}")

        return pd.DataFrame()

# 期货数据批量获取示例

fut_codes = ['CU2401.SHF', 'AL2401.SHF', 'ZN2401.SHF']

for code in fut_codes:

    df = safe_call('fut_daily', ts_code=code, trade_date='20240110')

    if not df.empty:

        print(f"{code} 获取成功,行数 {len(df)}")

safe_call 在重试耗尽后返回空 DataFrame,不中断批量任务。日志记录失败参数便于后续排查。股票数据批量获取同理,使用 dailydaily_basic 接口。

总结 tushare retry 使用的关键配置

正确使用 retry 需要结合 tushare 限流规则。推荐组合:tenacityretry 库 + 指数退避 + 限流特殊等待 + 本地缓存。对于高频批量任务,优先实现缓存,再设置最多 3 次重试,每次延迟 5 秒起步。股票和期货数据接口均适用以上模式。避免在循环中无延迟直接重试,否则会快速耗尽配额。合理配置后,数据获取成功率显著提升,策略回测和实盘信号生成更加稳定。