Skip to content

Commit

Permalink
Merge remote-tracking branch 'yfinance/dev' into bugfix/data-types-2
Browse files Browse the repository at this point in the history
# Conflicts:
#	yfinance/base.py
  • Loading branch information
mreiche committed Oct 21, 2023
2 parents ba977a1 + 7432d29 commit ba3c1b5
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 152 deletions.
128 changes: 7 additions & 121 deletions tests/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,132 +142,18 @@ def test_goodTicker(self):
for attribute_name, attribute_type in ticker_attributes:
assert_attribute_type(self, dat, attribute_name, attribute_type)

#TODO:: Refactor with `assert_attribute` once proxy is accepted as a parameter of `Ticker`
def test_goodTicker_withProxy(self):
# that yfinance works when full api is called on same instance of ticker

tkr = "IBM"
dat = yf.Ticker(tkr, session=self.session)

dat._fetch_ticker_tz(proxy=self.proxy, timeout=5)
dat._get_ticker_tz(proxy=self.proxy, timeout=5)
dat.history(period="1wk", proxy=self.proxy)

v = dat.get_major_holders(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_institutional_holders(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_mutualfund_holders(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_info(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertTrue(len(v) > 0)

v = dat.get_income_stmt(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_incomestmt(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_financials(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_balance_sheet(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_balancesheet(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_cash_flow(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_cashflow(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_shares_full(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_isin(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertTrue(v != "")

v = dat.get_news(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertTrue(len(v) > 0)
dat = yf.Ticker(tkr, session=self.session, proxy=self.proxy)

v = dat.get_earnings_dates(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)

dat.get_history_metadata(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertTrue(len(v) > 0)

# Below will fail because not ported to Yahoo API

# v = dat.stats(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertTrue(len(v) > 0)

# v = dat.get_recommendations(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_calendar(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_sustainability(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_recommendations_summary(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_analyst_price_target(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_rev_forecast(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_earnings_forecast(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_trend_details(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_earnings_trend(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_earnings(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)

# v = dat.get_shares(proxy=self.proxy)
# self.assertIsNotNone(v)
# self.assertFalse(v.empty)
dat._fetch_ticker_tz(timeout=5)
dat._get_ticker_tz(timeout=5)
dat.history(period="1wk")

for attribute_name, attribute_type in ticker_attributes:
assert_attribute_type(self, dat, attribute_name, attribute_type)


class TestTickerHistory(unittest.TestCase):
session = None

Expand Down
51 changes: 27 additions & 24 deletions yfinance/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@


class TickerBase:
def __init__(self, ticker, session=None):
def __init__(self, ticker, session=None, proxy=None):
self.ticker = ticker.upper()
self.proxy = proxy
self.session = session
self._history = None
self._history_metadata = None
Expand Down Expand Up @@ -135,6 +136,7 @@ def history(self, period="1mo", interval="1d",
If True, then raise errors as Exceptions instead of logging.
"""
logger = utils.get_yf_logger()
proxy = proxy or self.proxy

if debug is not None:
if debug:
Expand Down Expand Up @@ -1641,7 +1643,8 @@ def map_signals_to_ranges(f, f_up, f_down):

return df2

def _get_ticker_tz(self, proxy, timeout):
def _get_ticker_tz(self,timeout, proxy=None):
proxy = proxy or self.proxy
if self._tz is not None:
return self._tz
cache = utils.get_tz_cache()
Expand All @@ -1665,9 +1668,9 @@ def _get_ticker_tz(self, proxy, timeout):
return tz

@utils.log_indent_decorator
def _fetch_ticker_tz(self, proxy, timeout):
def _fetch_ticker_tz(self, timeout, proxy=None):
# Query Yahoo for fast price data just to get returned timezone

proxy = proxy or self.proxy
logger = utils.get_yf_logger()

params = {"range": "1d", "interval": "1d"}
Expand Down Expand Up @@ -1698,44 +1701,44 @@ def _fetch_ticker_tz(self, proxy, timeout):
return None

def get_recommendations(self, proxy=None, as_dict=False):
self._quote.proxy = proxy
self._quote.proxy = proxy or self.proxy
data = self._quote.recommendations
if as_dict:
return data.to_dict()
return data

def get_calendar(self, proxy=None, as_dict=False):
self._quote.proxy = proxy
self._quote.proxy = proxy or self.proxy
data = self._quote.calendar
if as_dict:
return data.to_dict()
return data

def get_major_holders(self, proxy=None, as_dict=False):
self._holders.proxy = proxy
self._holders.proxy = proxy or self.proxy
data = self._holders.major
if as_dict:
return data.to_dict()
return data

def get_institutional_holders(self, proxy=None, as_dict=False):
self._holders.proxy = proxy
self._holders.proxy = proxy or self.proxy
data = self._holders.institutional
if data is not None:
if as_dict:
return data.to_dict()
return data

def get_mutualfund_holders(self, proxy=None, as_dict=False):
self._holders.proxy = proxy
self._holders.proxy = proxy or self.proxy
data = self._holders.mutualfund
if data is not None:
if as_dict:
return data.to_dict()
return data

def get_info(self, proxy=None) -> dict:
self._quote.proxy = proxy
self._quote.proxy = proxy or self.proxy
data = self._quote.info
return data

Expand All @@ -1750,49 +1753,49 @@ def basic_info(self):
return self.fast_info

def get_sustainability(self, proxy=None, as_dict=False):
self._quote.proxy = proxy
self._quote.proxy = proxy or self.proxy
data = self._quote.sustainability
if as_dict:
return data.to_dict()
return data

def get_recommendations_summary(self, proxy=None, as_dict=False):
self._quote.proxy = proxy
self._quote.proxy = proxy or self.proxy
data = self._quote.recommendations
if as_dict:
return data.to_dict()
return data

def get_analyst_price_target(self, proxy=None, as_dict=False):
self._analysis.proxy = proxy
self._analysis.proxy = proxy or self.proxy
data = self._analysis.analyst_price_target
if as_dict:
return data.to_dict()
return data

def get_rev_forecast(self, proxy=None, as_dict=False):
self._analysis.proxy = proxy
self._analysis.proxy = proxy or self.proxy
data = self._analysis.rev_est
if as_dict:
return data.to_dict()
return data

def get_earnings_forecast(self, proxy=None, as_dict=False):
self._analysis.proxy = proxy
self._analysis.proxy = proxy or self.proxy
data = self._analysis.eps_est
if as_dict:
return data.to_dict()
return data

def get_trend_details(self, proxy=None, as_dict=False):
self._analysis.proxy = proxy
self._analysis.proxy = proxy or self.proxy
data = self._analysis.analyst_trend_details
if as_dict:
return data.to_dict()
return data

def get_earnings_trend(self, proxy=None, as_dict=False):
self._analysis.proxy = proxy
self._analysis.proxy = proxy or self.proxy
data = self._analysis.earnings_trend
if as_dict:
return data.to_dict()
Expand All @@ -1811,7 +1814,7 @@ def get_earnings(self, proxy=None, as_dict=False, freq="yearly"):
Optional. Proxy server URL scheme
Default is None
"""
self._fundamentals.proxy = proxy
self._fundamentals.proxy = proxy or self.proxy
data = self._fundamentals.earnings[freq]
if as_dict:
dict_data = data.to_dict()
Expand All @@ -1836,7 +1839,7 @@ def get_income_stmt(self, proxy=None, as_dict=False, pretty=False, freq="yearly"
Optional. Proxy server URL scheme
Default is None
"""
self._fundamentals.proxy = proxy
self._fundamentals.proxy = proxy or self.proxy

data = self._fundamentals.financials.get_income_time_series(freq=freq, proxy=proxy)

Expand Down Expand Up @@ -1869,7 +1872,7 @@ def get_balance_sheet(self, proxy=None, as_dict=False, pretty=False, freq="yearl
Optional. Proxy server URL scheme
Default is None
"""
self._fundamentals.proxy = proxy
self._fundamentals.proxy = proxy or self.proxy

data = self._fundamentals.financials.get_balance_sheet_time_series(freq=freq, proxy=proxy)

Expand Down Expand Up @@ -1899,7 +1902,7 @@ def get_cash_flow(self, proxy=None, as_dict=False, pretty=False, freq="yearly")
Optional. Proxy server URL scheme
Default is None
"""
self._fundamentals.proxy = proxy
self._fundamentals.proxy = proxy or self.proxy

data = self._fundamentals.financials.get_cash_flow_time_series(freq=freq, proxy=proxy)

Expand Down Expand Up @@ -1949,7 +1952,7 @@ def get_actions(self, proxy=None) -> pd.DataFrame:
return pd.DataFrame()

def get_shares(self, proxy=None, as_dict=False) -> Union[pd.DataFrame, dict]:
self._fundamentals.proxy = proxy
self._fundamentals.proxy = proxy or self.proxy
data = self._fundamentals.shares
if as_dict:
return data.to_dict()
Expand Down Expand Up @@ -2023,7 +2026,7 @@ def get_isin(self, proxy=None) -> Optional[str]:

q = ticker

self._quote.proxy = proxy
self._quote.proxy = proxy or self.proxy
if self._quote.info is None:
# Don't print error message cause self._quote.info will print one
return None
Expand Down Expand Up @@ -2144,7 +2147,7 @@ def get_earnings_dates(self, limit=12, proxy=None) -> Optional[pd.DataFrame]:
dates[cn] = dates[cn] + ' ' + tzinfo["AM/PM"]
dates[cn] = pd.to_datetime(dates[cn], format="%b %d, %Y, %I %p")
# - instead of attempting decoding of ambiguous timezone abbreviation, just use 'info':
self._quote.proxy = proxy
self._quote.proxy = proxy or self.proxy
tz = self._get_ticker_tz(proxy=proxy, timeout=30)
dates[cn] = dates[cn].dt.tz_localize(tz)

Expand Down
14 changes: 7 additions & 7 deletions yfinance/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@


class Ticker(TickerBase):
def __init__(self, ticker, session=None):
super(Ticker, self).__init__(ticker, session=session)
def __init__(self, ticker, session=None, proxy=None):
super(Ticker, self).__init__(ticker, session=session, proxy=proxy)
self._expirations = {}
self._underlying = {}

def __repr__(self):
return f'yfinance.Ticker object <{self.ticker}>'

def _download_options(self, date=None, proxy=None):
def _download_options(self, date=None):
if date is None:
url = f"{self._base_url}/v7/finance/options/{self.ticker}"
else:
url = f"{self._base_url}/v7/finance/options/{self.ticker}?date={date}"

r = self._data.get(url=url, proxy=proxy).json()
r = self._data.get(url=url, proxy=self.proxy).json()
if len(r.get('optionChain', {}).get('result', [])) > 0:
for exp in r['optionChain']['result'][0]['expirationDates']:
self._expirations[_datetime.datetime.utcfromtimestamp(
Expand Down Expand Up @@ -80,9 +80,9 @@ def _options2df(self, opt, tz=None):
data['lastTradeDate'] = data['lastTradeDate'].dt.tz_convert(tz)
return data

def option_chain(self, date=None, proxy=None, tz=None):
def option_chain(self, date=None, tz=None):
if date is None:
options = self._download_options(proxy=proxy)
options = self._download_options()
else:
if not self._expirations:
self._download_options()
Expand All @@ -91,7 +91,7 @@ def option_chain(self, date=None, proxy=None, tz=None):
f"Expiration `{date}` cannot be found. "
f"Available expirations are: [{', '.join(self._expirations)}]")
date = self._expirations[date]
options = self._download_options(date, proxy=proxy)
options = self._download_options(date)

return _namedtuple('Options', ['calls', 'puts', 'underlying'])(**{
"calls": self._options2df(options['calls'], tz=tz),
Expand Down

0 comments on commit ba3c1b5

Please sign in to comment.