回测数据去哪里找?

回测需要用到:比例法(涨跌幅复权法),通俗的例子解释一下,同样的,用例子解释下,为什么不能用加减法复权,推荐一些能用 pytho 获取历史数据的 比例法 数据源

好的,我们来用通俗易懂的例子解释一下“比例法(涨跌幅复权法)”以及为什么不能用“加减法复权”,并为您推荐一些获取 Python 历史数据的来源。

核心概念:为什么需要复权?

在投资的世界里,股票的价格并不仅仅因为买卖而变动。上市公司的一些行为,比如分红、送股、配股,都会直接影响股价,但这些变动并不反映公司真实的价值增长或下跌。

想象一下,你持有的股票昨天收盘价是 100 元。今天公司决定每股派发 5 元现金红利,这个过程叫做“除息”。派发红利后,公司的总价值减少了,所以交易所会把股价下调 5 元,开盘价变成 95 元。

如果你直接用 95 元和昨天的 100 元来计算涨跌幅,会得出 -5% 的结论。但这显然是错的,因为你的账户里多了 5 元现金,你的总资产并没有损失。

复权(Reinvestment/Adjustment) 的目的,就是将这些非市场交易因素(如分红、送股)造成的股价“缺口”填补上,还原股票价格的真实走势,让你能够准确地计算收益率和进行策略回测。


比例法(涨跌幅复权法):通俗例子解释

核心思想: 比例法假设你收到的所有分红或送股,都会在收到它们的那一刻,立刻以当时的股价重新买入该股票。它关注的是 “总资产的增长比例”

例子:

假设你在 第一天100 元 的价格买了 1 股“神奇公司”的股票。你的总资产是 100 元

第二天,市场没变化,但公司宣布进行“除息”,每股派发现金红利 2 元

  • 除息后,股价会自动从 100 元下调到 98 元
  • 此时,你的持仓变成了:1 股股票(价值 98 元)+ 2 元现金。
  • 你的总资产仍然是 98 + 2 = 100 元,没有变化。

第三天,市场上涨,神奇公司的股价从 98 元上涨到了 102.9 元

  • 涨幅是多少?是 (102.9 - 98) / 98 = 5%
  • 你的总资产现在价值多少?
    • 如果你没有把红利再投资:1 股股票(102.9 元)+ 2 元现金 = 104.9 元
    • 如果我们用比例法来计算一个“复权后”的价格,我们会假设那 2 元现金在除息日(第二天)就以 98 元的价格重新买入了股票。但为了简化计算,比例法直接在昨天的价格基础上乘以今天的涨跌幅。

比例法的计算逻辑:

它认为,第二天的总资产(100元)和第一天的总资产(100元)相比,增长率是 0%。第三天的总资产相较于第二天,增长了 5%。

所以,它会这样构建一个连续的、复权后的价格序列:

  • 第一天复权价: 100 元
  • 第二天复权价: 由于总资产没变,它会把昨天的收盘价“修正”一下,以反映今天的真实情况。修正方法是 昨天的复权价 * (1 + 今天的真实涨跌幅)。但除息日当天,真实涨跌幅为 0(因为总资产没变),所以复权价不变,或者说会进行一个技术调整,我们直接看第三天。
  • 第三天复权价: 第一天的复权价 * (1 + 0%) * (1 + 5%) 是不准确的。正确的逻辑是,它会把除息前的价格作为基准,然后进行“打折”。

我们换个更清晰的前复权角度来理解:

  • 第三天的收盘价是 102.9 元。(基准)
  • 第二天的收盘价是 98 元
  • 第一天的收盘价是 100 元,但因为第二天发生了除息(股价从 100 变成 98,相当于打了 98/100 = 0.98 的折扣),所以我们要把第一天的价格也按这个比例打折,来和后面的价格对齐。
    • 修正后的第一天价格 = 102.9 / (1 + 5%) / (100/98) … 这个计算很复杂。

最简单的理解方式(涨跌幅复权法):

比例法的核心是保证任何两天的复权价格之间的涨跌幅,等于你在这段时间内(并将所有分红再投资)所获得的总收益率

  • 从第一天收盘到第三天收盘,你的真实总收益率是 (104.9 - 100) / 100 = 4.9%。(这里假设你没再投资)
  • 如果分红立刻再投资,第三天你的总资产会是 100 * (1 + 5%) = 105 元(因为你所有的100元都在股票里享受了5%的增长)。
  • 那么,复权价格序列算出来的涨跌幅就应该是 5%。
    • 第三天复权价 / 第一天复权价 - 1 = 5%

结论: 比例法(涨跌幅复权法)通过调整历史价格,使得任何一段时期内的价格涨跌幅都精确对应了“分红再投资”策略下的总回报率。这是进行量化回测最准确、最标准的方法。


为什么不能用“加减法复权”?

核心思想: 加减法复权试图通过简单的加法,把分红的金额直接加回到除息前的股价上。

例子(沿用上文):

  • 第一天收盘价:100 元
  • 第二天除息 2 元,收盘价:98 元
  • 第三天上涨 5%,收盘价:102.9 元

加减法的错误逻辑:

它会认为,第二天的 98 元是因为少了 2 元分红,所以要把这 2 元“加回去”。

  • 它计算出的第二天“复权价” = 98 + 2 = 100 元。
  • 它计算出的第三天“复权价” = 102.9 + 2 = 104.9 元。

现在,我们用这个“复权价”序列来计算第三天的涨跌幅:

  • 涨幅 = (104.9 - 100) / 100 = 4.9%

问题出在哪里?

这个 4.9% 的涨幅是错误的!我们前面分析过,股价的实际涨幅是 (102.9 - 98) / 98 = 5%。加减法得出的 4.9% 低估了股票真实的增长能力。

为什么会低估? 因为加减法没有考虑到“复利”效应。比例法假设你的 2 元分红也以 5% 的速度在增长,而加减法粗暴地认为这 2 元永远就是 2 元,没有参与到后续的投资增值中。随着时间的推移和分红次数的增加,这种误差会越来越大,导致你的回测结果严重失真,尤其是对于那些高分红的股票。

一句话总结: 加减法破坏了价格序列的“增长率”信息,导致收益率计算错误;比例法保留了真实的“收益率”,是回测的正确选择。


Python 获取历史数据的“比例法”数据源推荐

在实践中,我们通常不需要自己去计算复权。专业的数据提供商会直接提供已经计算好的复权价格。你只需要在调用 API 时选择正确的价格类型即可。通常,这被称为“Adjusted Price”(调整后价格)。

以下是一些广受好评且能通过 Python 获取复权后历史数据的数据源:

  1. yfinance (雅虎财经)

    • 优点: 完全免费,使用简单,是个人开发者和初学者的首选。它提供的数据默认就是经过比例法复权(前复权)的。
    • 缺点: 数据可能存在清洗不干净或偶尔延迟的问题,对于非常严谨的商业策略,可能需要更专业的数据源。
    • Python 使用示例:
      import yfinance as yf
      
      # 下载台积电(2330.TW)的历史数据
      # auto_adjust=True 是关键,它会自动获取复权后的价格
      tsmc = yf.download('2330.TW', start='2023-01-01', end='2024-01-01', auto_adjust=True)
      
      # tsne.Close 列就是经过比例法(涨跌幅复权法)计算的前复权收盘价
      print(tsmc['Close'].head())
      
  2. TuShare

    • 优点: 国内非常流行的财经数据接口,提供丰富的 A 股、港股、美股等数据。数据质量较高,有积分制度,但基础数据免费。提供了明确的复权因子和复权后行情接口。
    • 缺点: 需要注册获取 token,部分高级数据或高频率调用需要积分。
    • Python 使用示例(需要先注册获取 token):
      import tushare as ts
      
      # 设置你的 token
      ts.set_token('YOUR_TOKEN_HERE')
      pro = ts.pro_api()
      
      # 获取贵州茅台(600519.SH)的日线行情,adj='qfq'代表前复权
      # 'hfq' 代表后复权,两者都属于比例法
      df = pro.daily(ts_code='600519.SH', start_date='20230101', end_date='20240101', adj='qfq')
      
      print(df.head())
      
  3. baostock

    • 优点: 免费、开源的中国 A 股证券数据平台。数据比较稳定和准确,也提供了复权选项。
    • 缺点: 主要覆盖 A 股市场。
    • Python 使用示例:
      import baostock as bs
      
      # 登录系统
      lg = bs.login()
      
      # 获取历史K线数据
      # adjustflag="2" 为前复权, "1" 为后复权
      rs = bs.query_history_k_data_plus("sh.600000",
          "date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST",
          start_date='2023-01-01', end_date='2024-01-01',
          frequency="d", adjustflag="2")
      
      data_list = []
      while (rs.error_code == '0') & rs.next():
          data_list.append(rs.get_row_data())
      
      import pandas as pd
      df = pd.DataFrame(data_list, columns=rs.fields)
      
      print(df.head())
      
      # 登出系统
      bs.logout()
      
  4. 商业级数据源 (Quandl/FactSet, Refinitiv, Bloomberg)

    • 优点: 数据质量最高、覆盖面最广、更新最及时,提供专业的 API 和技术支持。
    • 缺点: 价格昂贵,主要面向金融机构和企业用户。

给初学者的建议:yfinanceTuShare 开始。它们完全能满足学习、研究和个人项目回测的需求,并且能让你很好地理解和应用“比例法”复权数据。在调用时,请务必选择“Adjusted”或“复权”选项。

金融IT程序员的瞎折腾、日常生活的碎碎念
使用 Hugo 构建
主题 StackJimmy 设计