【问题标题】:wrong scale in yahoo finance python雅虎金融python中的错误比例
【发布时间】:2021-04-28 20:09:57
【问题描述】:

我正在尝试使用 yahoo Finance 下载一些共同基金和 ETF 的历史价格。我认为雅虎财务中存在一个混淆价格比例的错误(我不认为这是一个分裂问题。请参见下面的图片)。

无论如何,这里有一个 MWE 来重现问题

import yfinance as yf
import pandas as pd 
from pandas_datareader import data as pdr
yf.pdr_override()

tickers = ["0P0001FE43.L", "0P00014IJX.L", "SGLN.L"]

start_date = "2019-01-01" 
today      = "2021-04-27"

def getData(ticker):
        #print (ticker)
        data = pdr.get_data_yahoo(ticker, start=start_date, end=today)
        data["yahoo_ticker"] = ticker
        files.append(data)

files=[]
for tik in tickers:
    getData(tik)

df = pd.concat(files)
df = df[ [ "Adj Close", "yahoo_ticker"]]

仔细观察调整后的价格会发现:

我想不出任何系统的方法来纠正这个问题,所以希望能得到任何帮助。

【问题讨论】:

    标签: python yahoo-finance


    【解决方案1】:

    我发现了另一个我认为应该比我的其他答案更强大的解决方案。这并不是针对整个历史记录,而是针对永远不会“自然”发生的50 倍或更多的单日跳跃

    import yfinance as yf
    import pandas as pd
    from pandas_datareader import data as pdr
    yf.pdr_override()
    
    tickers = ["0P0001FE43.L", "0P00014IJX.L", "SGLN.L"]
    
    start_date = "2019-01-01"
    today      = "2021-04-27"
    
    def getData(ticker):
        data = pdr.get_data_yahoo(ticker, start=start_date, end=today)
        data["yahoo_ticker"] = ticker
        # fix faulty yahoo data that jumps 100x
        jumps_up   = data['Adj Close'] / data['Adj Close'].shift() >  50
        jumps_down = data['Adj Close'] / data['Adj Close'].shift() < .02
        correction_factor = 100.**(jumps_down.cumsum() - jumps_up.cumsum())
        data['Adj Close'] *= correction_factor
        print(f"Fixed {sum(correction_factor != 1)}/{len(data)} for ticker {ticker}"
              f" (min: {data['Adj Close'].min()}, max: {data['Adj Close'].max()})")
        return data
    
    df = pd.concat([getData(tik) for tik in tickers])
    df = df[["Adj Close", "yahoo_ticker"]]
    print(df)
    
    Fixed 5/587 for ticker 0P0001FE43.L (min: 97.52300262451172, max: 174.1580047607422)
    Fixed 1/587 for ticker 0P00014IJX.L (min: 169.8939971923828, max: 376.5379943847656)
    Fixed 288/586 for ticker SGLN.L (min: 2195.0, max: 3388.9999389648438)
    

    【讨论】:

    • 它工作,加上其他有问题的股票代码。因此,该方法看起来相当稳健。
    【解决方案2】:

    我只快速检查了 SGLN.L 雅虎的财务页面 并且数据对齐。我不是市场专家,所以我不能说这里发生了什么,但数据似乎匹配。此外,在此期间,音量上升/下降变得更加不稳定,因此可能与此有关。

    【讨论】:

    【解决方案3】:

    为了捕捉和修复一天事件,我通常会检查非常大的一天差距。像这样比较每个关闭与前一个和下一个关闭的东西,应该可以解决 1/100 或 1*100 问题,但没有什么能阻止您设置另一个阈值或一次使用多个阈值。当历史序列中的差距是由于管理不善造成的拆分时,多重比较可以避免更正。

    代码

    fixed = [l[0]]
    
    i = 1
    
    while i < len(l) -1:
            
        p = l[i] / l[i-1]
        n = l[i+1] / l[i]
    
        if p < 0.1 and n >= 100:
            fixed.append(l[i] * 100)      
        elif p >= 100 and n < 0.1:
            fixed.append(round(l[i] / 100, 5))
        else:
            fixed.append(l[i])
        
        i += 1
                
    # Last value
            
    p =  fixed[-1] / l[-1]
    
    if p >= 100:
        fixed.append(l[i] * 100)      
    elif p < 0.1:
        fixed.append(round(l[i] / 100, 5))
    else:
        fixed.append(l[i])
    

    输出

    l = [171.062, 1.71945, 172.901, 172.184]
    [171.062, 171.945, 172.901, 172.184]
    
    l = [1.71062, 1.71945, 172.901, 1.72184]
    [1.71062, 1.71945, 1.72901, 1.72184]
    

    虽然这可行,但如果您可以下载所有(调整后的)OHLC 字段以获取安全性(我使用 Bloomberg Professional 作为数据提供者,我不知道 Yahoo 是否支持它),您应该始终将它们相互比较,而不是仅将收盘价与上一个和下一个进行比较。这将是一种更稳健的方法,同时您还可以检查 O 和 C 是否在 H - L 范围内以及其他更常见但微妙的错误。

    【讨论】:

      【解决方案4】:

      一种方法是简单地发现几乎 100 倍的差异,遗憾的是股票可能会波动很大,因此这可能并不总是有效:

      import yfinance as yf
      import pandas as pd
      from pandas_datareader import data as pdr
      yf.pdr_override()
      
      tickers = ["0P0001FE43.L", "0P00014IJX.L", "SGLN.L"]
      
      start_date = "2019-01-01"
      today      = "2021-04-27"
      
      def getData(ticker):
          data = pdr.get_data_yahoo(ticker, start=start_date, end=today)
          data["yahoo_ticker"] = ticker
          # fix data where it's more than 40 times the min
          mask = data['Adj Close'] < 40 * (data['Adj Close'].min())
          data['Adj Close'] = data['Adj Close'] * (1 + 99 * mask)
          print(f'Fixed {sum(mask)}/{len(mask)} datapoints for ticker {ticker}')
          return data
      
      df = pd.concat([getData(tik) for tik in tickers])
      df = df[["Adj Close", "yahoo_ticker"]]
      print(df)
      
      Fixed 5/587 datapoints for ticker 0P0001FE43.L
      Fixed 1/587 datapoints for ticker 0P00014IJX.L
      Fixed 288/586 datapoints for ticker SGLN.L
      

      【讨论】:

        【解决方案5】:

        根据Yahoo Finance,它实际上是数据集中的错误,而不是包中的错误。

        对于影响几天的事件,我建议用 NaN 替换错误行,然后使用 pandas.DataFrame.interpolate()

        faulty = df['Adj Close'].le(df['Adj Close'].shift()*0.1)
        df.at[faulty[faulty].index, :] = np.nan
        df['Adj Close'] = df['Adj Close'].interpolate()
        

        【讨论】:

        • 您应该仅在缺少数据而不是小数点错误时进行插值。您应该修复小数点错误。如果您插入以填充 N/A,您还应该记得添加一个标志以避免在整个市场关闭或股票因任何原因没有交易时进行交易。您的回测将向您展示交易,而实际上这将是“无法”。
        • 好点@nico9T。如果是小数点错误,则确定错误10^x 然后按10^(-x) 缩放错误数据是有意义的。感谢您的反馈。
        猜你喜欢
        • 1970-01-01
        • 2017-10-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多