我目前正在寻找一种方法来加载来自雅虎金融的多年股价历史记录。我将拥有 100 多个股票代码,我将下载从 1985 年到当前日期的数据。我希望将开盘价、最高价、最低价、收盘价、调整收盘价、成交量加载到单个数据框( Pandas )中,并将数据框的名称命名为当前代码。
我的问题是我的变量 ticker 不起作用,即使它起作用了,我该如何存储这些数据?
import csv
import pandas as pd
import pandas_datareader.data as web
import datetime
#This represents the start and end date for the data
start = datetime.datetime(1985, 1, 1)
end = datetime.datetime(2016, 1, 27)
ticker = ['aapl','tvix','ugaz']
i= 0
while i < len(ticker):
f = web.DataReader(ticker, 'yahoo', start, end)
print(f)
i+=1
我希望能够永久存储所有这些数据,例如,如果我今天为 100 个股票代码加载 30 年的价格历史记录,那么明天我只需要附加一天的数据,而不是全部 30 年。此外,数据框似乎是组织数据的最有效方式,但我不太确定,但我想进行机器学习和数据分析。
请您参考如下方法:
如果在 yahoo 上可用,您可以使用 pandas_datareader 模块下载您想要的数据。您可以pip install它或以您喜欢的任何其他方式安装它。
以下是获取一小部分交易品种数据的示例脚本:
from pandas_datareader import data as dreader
symbols = ['GOOG', 'AAPL', 'MMM', 'ACN', 'A', 'ADP']
pnls = {i:dreader.DataReader(i,'yahoo','1985-01-01','2016-09-01') for i in symbols}
这会将数据保存在 python 字典中,允许您使用 .get 方法访问数据。
例如,如果你想获取GOOG的数据,你可以这样做:
print(pnls.get('GOOG').head())
这得到以下内容:
Open High Low Close Volume \
Date
2004-08-19 100.000168 104.060182 95.960165 100.340176 44871300
2004-08-20 101.010175 109.080187 100.500174 108.310183 22942800
2004-08-23 110.750191 113.480193 109.050183 109.400185 18342800
2004-08-24 111.240189 111.600192 103.570177 104.870176 15319700
2004-08-25 104.960181 108.000187 103.880180 106.000184 9232100
Adj Close
Date
2004-08-19 50.119968
2004-08-20 54.100990
2004-08-23 54.645447
2004-08-24 52.382705
2004-08-25 52.947145
请记住,如果给定的代码在某个时间间隔内没有数据,则返回的数据将省略那些年或天(显然)。
编辑:
您的脚本的主要问题(以及许多其他问题)是您多次进行相同的调用(len(ticker) 次)并且一遍又一遍地返回相同的输出。这是因为 DataReader() 函数在提供 list 时,将出去并为该 list 中的每个元素获取 data.frame >。所以,当你写:
i = 0
while i < len(ticker):
f = web.DataReader(ticker, 'yahoo', start, end)
print(f)
i+=1
你基本上是在说:使用 i = 0,我希望你继续调用 web.DataReader(ticker, 'yahoo', start, end) 并且获取相同的数据,然后打印它直到(通过递增)i 的值达到我的代码列表的长度。您可以使用 f = web.DataReader(ticker, 'yahoo', start, end) 得到同样的结果。但即便如此,您也不知道哪个 data.frame 对应哪个代码。
此外,我发现另一件非常令人震惊的事情是,当您处理 100 多个代码时,您想要命名返回的每个 data.frame。为什么在God's Green Earth 上您想要在您的命名空间中拥有 100 多个名称?您可以非常轻松地将所有这些名称集中到一个 dictionary 中(就像我上面推荐的那样),并通过使用 .get() 并提供行情收报机。
回顾:1) 不需要while-loop。 2) 如果您只是将整个代码列表提供给 DataReader() 函数,您将无法知道哪个 data.frame 对应哪个代码。 3) 您不想命名 100 多个数据帧。
建议:通过使用字典(行情代码是键,返回的数据将是值)和一个列表推导式循环来简化整个事情代码并获取他们的数据。我怀疑这可以使您的脚本更易于阅读并且更短。
编辑 2:
这是为满足运行一次作业然后每天使用最新可用价格增加数据的愿望提供解决方案的尝试。这不是唯一的方法,但我认为这是一个好方法。首先,您需要编写一个脚本来获取从 1985 年到昨天的所有代码数据。该脚本将需要在交易时间后(或深夜)运行以捕获最新价格。这可能与我上面的脚本非常相似。您唯一需要添加的是几行代码,以将您计算机上的数据保存在当前工作目录中。应执行以下操作:
from pandas_datareader import data as dreader
symbols = ['GOOG', 'AAPL', 'MMM', 'ACN', 'A', 'ADP']
pnls = {i:dreader.DataReader(i,'yahoo','1985-01-01','2016-09-01') for i in symbols}
for df_name in pnls:
pnls.get(df_name).to_csv("{}_data.csv".format(df_name), index=True, header=True)
然后,您可以编写另一个脚本,它只获取今天相同代码的数据。它也需要在晚上(午夜之前)运行,以便它可以捕获今天的数据。
from datetime import datetime
from pandas_datareader import data as dreader
from pandas_datareader._utils import RemoteDataError
symbols = ['GOOG', 'AAPL', 'MMM', 'ACN', 'A', 'ADP']
try:
pnls = {i:dreader.DataReader(i,'yahoo',datetime.today(),datetime.today()) for i in symbols}
except RemoteDataError:
pnls = None
if pnls is not None:
for df_name in pnls:
with open("{}_data.csv".format(df_name),"a") as outfile:
pnls.get(df_name).to_csv(outfile,header=False)
else:
print("No data available yet. Please run later.")
第二个脚本应该将最新价格附加到之前使用第一个脚本保存的每个数据文件中。
请注意,我假设 Yahoo(或任何其他数据源)将在您所在的任何地方收市后立即提供当天的价格。
希望对您有所帮助。
