Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
000cb70bcb | ||
|
|
c8d9d06e75 | ||
|
|
a5e07a0375 | ||
|
|
a0a12bcf4c | ||
|
|
c49cf626bb | ||
|
|
fa6f3fc537 | ||
|
|
34dfe944d9 | ||
|
|
9619839bf5 | ||
|
|
90e00a71ca | ||
|
|
f525ee2f5e | ||
|
|
ef12c8b600 | ||
|
|
42e6d0894e | ||
|
|
de1c3c091b | ||
|
|
c6c0fa3347 | ||
|
|
75c823a72c | ||
|
|
f1ad8f0061 | ||
|
|
b27cc0cf40 | ||
|
|
1d7f8139d6 | ||
|
|
01ef1bb813 | ||
|
|
1db6be75b8 | ||
|
|
7902ec8667 | ||
|
|
ff42a3ac87 | ||
|
|
51f2c7301d | ||
|
|
632a16670a |
5
.github/ISSUE_TEMPLATE/bug_report.md
vendored
5
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -14,4 +14,7 @@ Before posting an issue - please upgrade to the latest version and confirm the i
|
||||
Upgrade using:
|
||||
`$ pip install yfinance --upgrade --no-cache-dir`
|
||||
|
||||
Bug still there? Delete this content and submit your bug report here...
|
||||
Bug still there? Delete this content and submit your bug report here and provide the following, as best you can:
|
||||
|
||||
- Simple code that reproduces your problem
|
||||
- The error message
|
||||
|
||||
@@ -1,9 +1,33 @@
|
||||
Change Log
|
||||
===========
|
||||
|
||||
0.1.83
|
||||
------
|
||||
- Reduce spam-effect of tz-fetch
|
||||
|
||||
0.1.81
|
||||
------
|
||||
- Fix unhandled tz-cache exception #1107
|
||||
|
||||
0.1.80
|
||||
------
|
||||
- Fix `download(ignore_tz=True)` for single ticker #1097
|
||||
- Fix rare case of error "Cannot infer DST time" #1100
|
||||
|
||||
0.1.79
|
||||
------
|
||||
- Fix when Yahoo returns price=NaNs on dividend day
|
||||
|
||||
0.1.78
|
||||
------
|
||||
- Fix download() when different timezones #1085
|
||||
|
||||
0.1.77
|
||||
------
|
||||
- Fix user experience bug #1078
|
||||
|
||||
0.1.75
|
||||
------
|
||||
|
||||
- Fixed datetime-related issues: #1048
|
||||
- Add 'keepna' argument #1032
|
||||
- Speedup Ticker() creation #1042
|
||||
|
||||
19
README.md
19
README.md
@@ -48,8 +48,6 @@ Yahoo! finance API is intended for personal use only.**
|
||||
|
||||
The `Ticker` module, which allows you to access ticker data in a more Pythonic way:
|
||||
|
||||
Note: yahoo finance datetimes are received as UTC.
|
||||
|
||||
```python
|
||||
import yfinance as yf
|
||||
|
||||
@@ -187,6 +185,11 @@ data = yf.download( # or pdr.get_data_yahoo(...
|
||||
# (optional, default is '1d')
|
||||
interval = "1m",
|
||||
|
||||
# Whether to ignore timezone when aligning ticker data from
|
||||
# different timezones. Default is True. False may be useful for
|
||||
# minute/hourly data.
|
||||
ignore_tz = False,
|
||||
|
||||
# group by ticker (to access via data['SPY'])
|
||||
# (optional, default is 'column')
|
||||
group_by = 'ticker',
|
||||
@@ -209,6 +212,18 @@ data = yf.download( # or pdr.get_data_yahoo(...
|
||||
)
|
||||
```
|
||||
|
||||
### Timezone cache store
|
||||
|
||||
When fetching price data, all dates are localized to stock exchange timezone.
|
||||
But timezone retrieval is relatively slow, so yfinance attemps to cache them
|
||||
in your users cache folder.
|
||||
You can direct cache to use a different location with `set_tz_cache_location()`:
|
||||
```python
|
||||
import yfinance as yf
|
||||
yf.set_tz_cache_location("custom/cache/location")
|
||||
...
|
||||
```
|
||||
|
||||
### Managing Multi-Level Columns
|
||||
|
||||
The following answer on Stack Overflow is for [How to deal with
|
||||
|
||||
@@ -23,6 +23,7 @@ from . import version
|
||||
from .ticker import Ticker
|
||||
from .tickers import Tickers
|
||||
from .multi import download
|
||||
from .utils import set_tz_cache_location
|
||||
|
||||
__version__ = version.version
|
||||
__author__ = "Ran Aroussi"
|
||||
@@ -42,4 +43,4 @@ def pdr_override():
|
||||
pass
|
||||
|
||||
|
||||
__all__ = ['download', 'Ticker', 'Tickers', 'pdr_override']
|
||||
__all__ = ['download', 'Ticker', 'Tickers', 'pdr_override', 'set_tz_cache_location']
|
||||
|
||||
@@ -151,7 +151,7 @@ class TickerBase():
|
||||
if start or period is None or period.lower() == "max":
|
||||
# Check can get TZ. Fail => probably delisted
|
||||
try:
|
||||
tz = self._get_ticker_tz()
|
||||
tz = self._get_ticker_tz(debug_mode, proxy, timeout)
|
||||
except KeyError as e:
|
||||
if "exchangeTimezoneName" in str(e):
|
||||
shared._DFS[self.ticker] = utils.empty_df()
|
||||
@@ -293,9 +293,6 @@ class TickerBase():
|
||||
"chart"]["result"][0]["meta"]["priceHint"])
|
||||
quotes['Volume'] = quotes['Volume'].fillna(0).astype(_np.int64)
|
||||
|
||||
if not keepna:
|
||||
quotes.dropna(inplace=True)
|
||||
|
||||
# actions
|
||||
dividends, splits = utils.parse_actions(data["chart"]["result"][0])
|
||||
|
||||
@@ -316,35 +313,83 @@ class TickerBase():
|
||||
elif params["interval"] == "1h":
|
||||
pass
|
||||
else:
|
||||
df.index = _pd.to_datetime(df.index.date).tz_localize(tz_exchange)
|
||||
# If a midnight is during DST transition hour when clocks roll back,
|
||||
# meaning clock hits midnight twice, then use the 2nd (ambiguous=True)
|
||||
df.index = _pd.to_datetime(df.index.date).tz_localize(tz_exchange, ambiguous=True)
|
||||
df.index.name = "Date"
|
||||
|
||||
# duplicates and missing rows cleanup
|
||||
df.dropna(how='all', inplace=True)
|
||||
df = df[~df.index.duplicated(keep='first')]
|
||||
|
||||
self._history = df.copy()
|
||||
|
||||
if not actions:
|
||||
df.drop(columns=["Dividends", "Stock Splits"], inplace=True)
|
||||
df = df.drop(columns=["Dividends", "Stock Splits"])
|
||||
if not keepna:
|
||||
mask_nan_or_zero = (df.isna()|(df==0)).all(axis=1)
|
||||
df = df.drop(mask_nan_or_zero.index[mask_nan_or_zero])
|
||||
|
||||
return df
|
||||
|
||||
# ------------------------
|
||||
|
||||
def _get_ticker_tz(self):
|
||||
def _get_ticker_tz(self, debug_mode, proxy, timeout):
|
||||
if not self._tz is None:
|
||||
return self._tz
|
||||
|
||||
tkr_tz = utils.cache_lookup_tkr_tz(self.ticker)
|
||||
if tkr_tz is None:
|
||||
tkr_tz = self.info["exchangeTimezoneName"]
|
||||
# info fetch is relatively slow so cache timezone
|
||||
utils.cache_store_tkr_tz(self.ticker, tkr_tz)
|
||||
tkr_tz = self._fetch_ticker_tz(debug_mode, proxy, timeout)
|
||||
|
||||
try:
|
||||
utils.cache_store_tkr_tz(self.ticker, tkr_tz)
|
||||
except PermissionError:
|
||||
# System probably read-only, so cannot cache
|
||||
pass
|
||||
|
||||
self._tz = tkr_tz
|
||||
return tkr_tz
|
||||
|
||||
|
||||
def _fetch_ticker_tz(self, debug_mode, proxy, timeout):
|
||||
# Query Yahoo for basic price data just to get returned timezone
|
||||
|
||||
params = {"range":"1d", "interval":"1d"}
|
||||
|
||||
# setup proxy in requests format
|
||||
if proxy is not None:
|
||||
if isinstance(proxy, dict) and "https" in proxy:
|
||||
proxy = proxy["https"]
|
||||
proxy = {"https": proxy}
|
||||
|
||||
# Getting data from json
|
||||
url = "{}/v8/finance/chart/{}".format(self._base_url, self.ticker)
|
||||
|
||||
session = self.session or _requests
|
||||
try:
|
||||
data = session.get(url=url, params=params, proxies=proxy, headers=utils.user_agent_headers, timeout=timeout)
|
||||
data = data.json()
|
||||
except Exception as e:
|
||||
if debug_mode:
|
||||
print("Failed to get ticker '{}' reason: {}".format(self.ticker, e))
|
||||
return None
|
||||
else:
|
||||
error = data.get('chart', {}).get('error', None)
|
||||
if error:
|
||||
# explicit error from yahoo API
|
||||
if debug_mode:
|
||||
print("Got error from yahoo api for ticker {}, Error: {}".format(self.ticker, error))
|
||||
else:
|
||||
try:
|
||||
return data["chart"]["result"][0]["meta"]["exchangeTimezoneName"]
|
||||
except Exception as err:
|
||||
if debug_mode:
|
||||
print("Could not get exchangeTimezoneName for ticker '{}' reason: {}".format(self.ticker, err))
|
||||
print("Got response: ")
|
||||
print("-------------")
|
||||
print(" {}".format(data))
|
||||
print("-------------")
|
||||
return None
|
||||
|
||||
|
||||
def _get_info(self, proxy=None):
|
||||
# setup proxy in requests format
|
||||
if proxy is not None:
|
||||
|
||||
@@ -29,7 +29,7 @@ from . import Ticker, utils
|
||||
from . import shared
|
||||
|
||||
|
||||
def download(tickers, start=None, end=None, actions=False, threads=True,
|
||||
def download(tickers, start=None, end=None, actions=False, threads=True, ignore_tz=True,
|
||||
group_by='column', auto_adjust=False, back_adjust=False, keepna=False,
|
||||
progress=True, period="max", show_errors=True, interval="1d", prepost=False,
|
||||
proxy=None, rounding=False, timeout=None, **kwargs):
|
||||
@@ -63,6 +63,9 @@ def download(tickers, start=None, end=None, actions=False, threads=True,
|
||||
Download dividend + stock splits data. Default is False
|
||||
threads: bool / int
|
||||
How many threads to use for mass downloading. Default is True
|
||||
ignore_tz: bool
|
||||
When combining from different timezones, ignore that part of datetime.
|
||||
Default is True
|
||||
proxy: str
|
||||
Optional. Proxy server URL scheme. Default is None
|
||||
rounding: bool
|
||||
@@ -136,16 +139,21 @@ def download(tickers, start=None, end=None, actions=False, threads=True,
|
||||
print("\n".join(['- %s: %s' %
|
||||
v for v in list(shared._ERRORS.items())]))
|
||||
|
||||
if ignore_tz:
|
||||
for tkr in shared._DFS.keys():
|
||||
if (shared._DFS[tkr] is not None) and (shared._DFS[tkr].shape[0]>0):
|
||||
shared._DFS[tkr].index = shared._DFS[tkr].index.tz_localize(None)
|
||||
|
||||
if len(tickers) == 1:
|
||||
ticker = tickers[0]
|
||||
return shared._DFS[shared._ISINS.get(ticker, ticker)]
|
||||
|
||||
try:
|
||||
data = _pd.concat(shared._DFS.values(), axis=1,
|
||||
data = _pd.concat(shared._DFS.values(), axis=1, sort=True,
|
||||
keys=shared._DFS.keys())
|
||||
except Exception:
|
||||
_realign_dfs()
|
||||
data = _pd.concat(shared._DFS.values(), axis=1,
|
||||
data = _pd.concat(shared._DFS.values(), axis=1, sort=True,
|
||||
keys=shared._DFS.keys())
|
||||
|
||||
# switch names back to isins if applicable
|
||||
|
||||
@@ -316,8 +316,17 @@ class ProgressBar:
|
||||
|
||||
|
||||
# Simple file cache of ticker->timezone:
|
||||
_cache_dp = None
|
||||
def get_cache_dirpath():
|
||||
return _os.path.join(_ad.user_cache_dir(), "py-yfinance")
|
||||
if _cache_dp is None:
|
||||
dp = _os.path.join(_ad.user_cache_dir(), "py-yfinance")
|
||||
else:
|
||||
dp = _os.path.join(_cache_dp, "py-yfinance")
|
||||
return dp
|
||||
def set_tz_cache_location(dp):
|
||||
global _cache_dp
|
||||
_cache_dp = dp
|
||||
|
||||
def cache_lookup_tkr_tz(tkr):
|
||||
fp = _os.path.join(get_cache_dirpath(), "tkr-tz.csv")
|
||||
if not _os.path.isfile(fp):
|
||||
|
||||
@@ -1 +1 @@
|
||||
version = "0.1.75"
|
||||
version = "0.1.83"
|
||||
|
||||
Reference in New Issue
Block a user