【问题标题】:Downloading mutliple stocks at once from yahoo finance python从 yahoo Finance python 一次下载多只股票
【发布时间】:2018-09-17 04:55:48
【问题描述】:

我对使用 pandas 数据阅读器的 yahoo Finance 的功能有疑问。我已经使用了几个月的股票代码列表并在以下行中执行它:

import pandas_datareader as pdr
import datetime

stocks = ["stock1","stock2",....]
start = datetime.datetime(2012,5,31)
end = datetime.datetime(2018,3,1)

f = pdr.DataReader(stocks, 'yahoo',start,end)

从昨天开始,我收到错误“IndexError: list index out of range”,仅当我尝试获取多只股票时才会出现。

最近几天有什么变化需要我考虑吗?或者您有更好的解决方案来解决我的问题?

【问题讨论】:

    标签: python python-3.x yahoo-finance pandas-datareader


    【解决方案1】:

    于 2021 年 1 月 19 日更新

    tickers = ['msft', 'aapl', 'twtr', 'intc', 'tsm', 'goog', 'amzn', 'fb', 'nvda']
    df = pdr.DataReader(tickers, data_source='yahoo', start='2017-01-01', end='2020-09-28')
    

    原答案

    如果您阅读 Pandas DataReader 的 documentation,他们会立即对多个数据源 API 进行折旧,其中之一是 Yahoo!财务。

    v0.6.0(2018 年 1 月 24 日)

    立即弃用 Yahoo!Google OptionsQuotesEDGAR。 这些 API 背后的端点发生了根本性的变化,并且 现有的读者需要完全重写。对于大多数 Yahoo! 数据端点已被删除。 PDR 想恢复这些 功能和拉取请求是受欢迎的。

    这可能是导致您收到IndexError(或任何其他通常不存在的错误)的罪魁祸首。


    但是,还有另一个 Python 包,其目标是修复对 Yahoo! 的支持。 Pandas DataReader 的财务,您可以在此处找到该软件包:

    https://pypi.python.org/pypi/fix-yahoo-finance

    根据他们的文档:

    Yahoo! finance 已停用其历史数据 API,导致许多依赖它的程序停止工作。

    fix-yahoo-finance 通过从 Yahoo! 抓取数据来临时解决问题。使用和返回 Pandas 融资pandas_datareader 格式相同的 DataFrame/Panel get_data_yahoo().

    基本上是“劫持”pandas_datareader.data.get_data_yahoo() 方法,fix-yahoo-finance的植入很容易,只需要 将fix_yahoo_finance 导入到您的代码中。

    您只需要添加以下内容:

    from pandas_datareader import data as pdr
    import fix_yahoo_finance as yf
    
    yf.pdr_override() 
    
    stocks = ["stock1","stock2", ...]
    start = datetime.datetime(2012,5,31)
    end = datetime.datetime(2018,3,1)
    
    f = pdr.get_data_yahoo(stocks, start=start, end=end)
    

    甚至不需要 Pandas DataReader:

    import fix_yahoo_finance as yf
    
    stocks = ["stock1","stock2", ...]
    start = datetime.datetime(2012,5,31)
    end = datetime.datetime(2018,3,1)
    data = yf.download(stocks, start=start, end=end)
    

    【讨论】:

    • 是否可以更改返回数据的时间范围/频率/间隔?我需要 90m 的收盘价。
    【解决方案2】:

    您可以使用带有 pandas 的新 Python YahooFinancials 模块来执行此操作。 YahooFinancials 构建良好,通过散列每个 Yahoo Finance Web 页面中存在的数据存储对象来获取数据,因此它速度很快,并且不依赖于旧的已停产的 API,也不依赖像爬虫那样的 Web 驱动程序。数据以 JSON 格式返回,您可以通过传入股票/指数代码列表来初始化 YahooFinancials 类,从而一次提取任意数量的股票。

    $ pip install yahoofinancials

    用法示例:

    from yahoofinancials import YahooFinancials
    import pandas as pd
    
    # Select Tickers and stock history dates
    ticker = 'AAPL'
    ticker2 = 'MSFT'
    ticker3 = 'INTC'
    index = '^NDX'
    freq = 'daily'
    start_date = '2012-10-01'
    end_date = '2017-10-01'
    
    
    # Function to clean data extracts
    def clean_stock_data(stock_data_list):
        new_list = []
        for rec in stock_data_list:
            if 'type' not in rec.keys():
                new_list.append(rec)
        return new_list
    
    # Construct yahoo financials objects for data extraction
    aapl_financials = YahooFinancials(ticker)
    mfst_financials = YahooFinancials(ticker2)
    intl_financials = YahooFinancials(ticker3)
    index_financials = YahooFinancials(index)
    
    # Clean returned stock history data and remove dividend events from price history
    daily_aapl_data = clean_stock_data(aapl_financials
                                         .get_historical_stock_data(start_date, end_date, freq)[ticker]['prices'])
    daily_msft_data = clean_stock_data(mfst_financials
                                         .get_historical_stock_data(start_date, end_date, freq)[ticker2]['prices'])
    daily_intl_data = clean_stock_data(intl_financials
                                         .get_historical_stock_data(start_date, end_date, freq)[ticker3]['prices'])
    daily_index_data = index_financials.get_historical_stock_data(start_date, end_date, freq)[index]['prices']
    stock_hist_data_list = [{'NDX': daily_index_data}, {'AAPL': daily_aapl_data}, {'MSFT': daily_msft_data},
                            {'INTL': daily_intl_data}]
    
    
    # Function to construct data frame based on a stock and it's market index
    def build_data_frame(data_list1, data_list2, data_list3, data_list4):
        data_dict = {}
        i = 0
        for list_item in data_list2:
            if 'type' not in list_item.keys():
                data_dict.update({list_item['formatted_date']: {'NDX': data_list1[i]['close'], 'AAPL': list_item['close'],
                                                                'MSFT': data_list3[i]['close'],
                                                                'INTL': data_list4[i]['close']}})
                i += 1
        tseries = pd.to_datetime(list(data_dict.keys()))
        df = pd.DataFrame(data=list(data_dict.values()), index=tseries,
                          columns=['NDX', 'AAPL', 'MSFT', 'INTL']).sort_index()
        return df
    

    一次多个股票数据示例(返回每个股票代码的 JSON 对象列表):

    from yahoofinancials import YahooFinancials
    
    tech_stocks = ['AAPL', 'MSFT', 'INTC']
    bank_stocks = ['WFC', 'BAC', 'C']
    
    yahoo_financials_tech = YahooFinancials(tech_stocks)
    yahoo_financials_banks = YahooFinancials(bank_stocks)
    
    tech_cash_flow_data_an = yahoo_financials_tech.get_financial_stmts('annual', 'cash')
    bank_cash_flow_data_an = yahoo_financials_banks.get_financial_stmts('annual', 'cash')
    
    banks_net_ebit = yahoo_financials_banks.get_ebit()
    tech_stock_price_data = tech_cash_flow_data.get_stock_price_data()
    daily_bank_stock_prices = yahoo_financials_banks.get_historical_stock_data('2008-09-15', '2017-09-15', 'daily')
    

    JSON 输出示例:

    代码:

    yahoo_financials = YahooFinancials('WFC')
    print(yahoo_financials.get_historical_stock_data("2017-09-10", "2017-10-10", "monthly"))
    

    JSON 返回:

    {
        "WFC": {
            "prices": [
                {
                    "volume": 260271600,
                    "formatted_date": "2017-09-30",
                    "high": 55.77000045776367,
                    "adjclose": 54.91999816894531,
                    "low": 52.84000015258789,
                    "date": 1506830400,
                    "close": 54.91999816894531,
                    "open": 55.15999984741211
                }
            ],
            "eventsData": [],
            "firstTradeDate": {
                "date": 76233600,
                "formatted_date": "1972-06-01"
            },
            "isPending": false,
            "timeZone": {
                "gmtOffset": -14400
            },
            "id": "1mo15050196001507611600"
        }
    }
    

    【讨论】:

    • 只是想知道:使用“网络驱动程序”有什么问题? (我什至不确定“网络驱动程序”的定义是什么)。因为您的模块正在抓取网页,所以它需要一种下载这些网页的方法。
    • 另外你应该补充一点,如果你开始使用这个模块,你要么希望它被维护,要么准备好在需要时维护它。事实上,雅虎金融可以随时更改其网页结构,这可能需要修改模块抓取代码。
    • 同意。如果需要的话,我已经准备好维护代码至少供我个人使用。它真的很好地放在一起。维护者已经解决了一些问题并关闭了它们,因此他不会出现缺席。雅虎财经在关闭 API 时似乎部署了大规模的新网络应用程序。最重要的是,这些字段似乎直接来自数据库。我似乎不会很快更改字段名称,并且前端更改不会影响模块,除非他们更改他们正在使用的 Web 应用程序框架。 DB 通常只在主要版本中更改。
    • Web 驱动程序也不错,不要误会我的意思。我喜欢硒+幻影。但是,您报废的渲染 GUI 组件通常比数据存储变量更容易更改,并且重命名的数据库字段(非常罕见)的名称更改解决方案通常更容易实现,然后编写新代码以与之交互并报废应用程序。此外,根据我的经验,此解决方案比从网络抓取工具获取数据要快。尤其是当它是数据时,您只能通过 Web 驱动程序通过分页按钮来报废。我怀疑这个模块在大约 3 年内只需要小幅修复就可以了
    【解决方案3】:

    yahoo_finance 已无法使用,因为 Yahoo 已更改格式,fix_yahoo_finance 足以下载数据。但是要解析,您需要其他库,这是一个简单的工作示例:

    
    import numpy as np #python library for scientific computing
    import pandas as pd #python library for data manipulation and analysis
    import matplotlib.pyplot as plt #python library for charting
    import fix_yahoo_finance as yf #python library to scrape data from yahoo finance
    from pandas_datareader import data as pdr #extract data from internet sources into pandas data frame
    
    yf.pdr_override()
    
    data = pdr.get_data_yahoo(‘^DJI’, start=”2006–01–01")
    data2 = pdr.get_data_yahoo(“MSFT”, start=”2006–01–01")
    data3 = pdr.get_data_yahoo(“AAPL”, start=”2006–01–01")
    data4 = pdr.get_data_yahoo(“BB.TO”, start=”2006–01–01")
    
    ax = (data[‘Close’] / data[‘Close’].iloc[0] * 100).plot(figsize=(15, 6))
    (data2[‘Close’] / data2[‘Close’].iloc[0] * 100).plot(ax=ax, figsize=(15,6))
    (data3[‘Close’] / data3[‘Close’].iloc[0] * 100).plot(ax=ax, figsize=(15,6))
    (data4[‘Close’] / data5[‘Close’].iloc[0] * 100).plot(ax=ax, figsize=(15,6))
    
    plt.legend([‘Dow Jones’, ‘Microsoft’, ‘Apple’, ‘Blackberry’], loc=’upper left’)
    plt.show()
    
    

    代码解释可以访问https://medium.com/@gerrysabar/charting-stocks-price-from-yahoo-finance-using-fix-yahoo-finance-library-6b690cac5447

    【讨论】:

      【解决方案4】:

      试试这个简单的代码

      watchlist=["stock1","stock2".......]
      closing_price=pd.DataFrame()
      symbols=[]
      
      for i in watchlist:
          Result=wb.DataReader(i,start='05-1-20', end='05-20-20',data_source='yahoo')
          closing_price=closing_price.append(Result)        
          symbols.append(i)
          print("Generating Closing price for",i)  
      
      closing_price["SYMBOL"]=symbols
      print("closing_price"
      
      

      【讨论】:

        【解决方案5】:

        这对我有用。

        assets = ['TSLA', 'MSFT', 'FB']
        
        yahoo_financials = YahooFinancials(assets)
        
        data = yahoo_financials.get_historical_price_data(start_date='2019-01-01', 
                                                          end_date='2019-12-31', 
                                                          time_interval='weekly')
        
        prices_df = pd.DataFrame({
            a: {x['formatted_date']: x['adjclose'] for x in data[a]['prices']} for a in assets})
        
        prices_df
        

        结果:

        【讨论】:

          猜你喜欢
          • 2017-01-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-12-30
          • 2019-04-08
          • 2020-09-15
          • 2020-07-08
          相关资源
          最近更新 更多