Skip to content

Commit

Permalink
Merge branch 'dev' into pandas-future-proofing
Browse files Browse the repository at this point in the history
  • Loading branch information
JuliaLWang8 authored Dec 7, 2023
2 parents e988afc + 1d3ef4f commit bec30a0
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 102 deletions.
71 changes: 15 additions & 56 deletions tests/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,7 @@ 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)

Expand Down Expand Up @@ -209,56 +206,16 @@ def test_goodTicker_withProxy(self):


# Below will fail because not ported to Yahoo API
dat = yf.Ticker(tkr, session=self.session, proxy=self.proxy)

# 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 Expand Up @@ -746,13 +703,15 @@ def test_bad_freq_value_raises_exception(self):
# data_cached = self.ticker.sustainability
# self.assertIs(data, data_cached, "data not cached")

# def test_recommendations(self):
# data = self.ticker.recommendations
# self.assertIsInstance(data, pd.DataFrame, "data has wrong type")
# self.assertFalse(data.empty, "data is empty")
def test_recommendations(self):
data = self.ticker.recommendations
data_summary = self.ticker.recommendations_summary
self.assertTrue(data.equals(data_summary))
self.assertIsInstance(data, pd.DataFrame, "data has wrong type")
self.assertFalse(data.empty, "data is empty")

# data_cached = self.ticker.recommendations
# self.assertIs(data, data_cached, "data not cached")
data_cached = self.ticker.recommendations
self.assertIs(data, data_cached, "data not cached")

# def test_recommendations_summary(self):
# data = self.ticker.recommendations_summary
Expand Down
59 changes: 31 additions & 28 deletions yfinance/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,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 @@ -132,6 +133,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 @@ -1638,7 +1640,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
c = cache.get_tz_cache()
Expand All @@ -1662,9 +1665,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 @@ -1695,44 +1698,48 @@ def _fetch_ticker_tz(self, proxy, timeout):
return None

def get_recommendations(self, proxy=None, as_dict=False):
self._quote.proxy = proxy
"""
Returns a DataFrame with the recommendations
Columns: period strongBuy buy hold sell strongSell
"""
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 @@ -1747,49 +1754,45 @@ 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
data = self._quote.recommendations
if as_dict:
return data.to_dict()
return data
return self.get_recommendations(proxy=proxy, as_dict=as_dict)

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 @@ -1808,7 +1811,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 @@ -1833,7 +1836,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 @@ -1866,7 +1869,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 @@ -1896,7 +1899,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 @@ -1946,7 +1949,7 @@ def get_actions(self, proxy=None):
return []

def get_shares(self, proxy=None, as_dict=False):
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 @@ -2020,7 +2023,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 @@ -2141,7 +2144,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
36 changes: 36 additions & 0 deletions yfinance/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,39 @@
"OtherCashReceiptsfromOperatingActivities", "ReceiptsfromGovernmentGrants", "ReceiptsfromCustomers"]}

price_colnames = ['Open', 'High', 'Low', 'Close', 'Adj Close']

quote_summary_valid_modules = (
"summaryProfile", # contains general information about the company
"summaryDetail", # prices + volume + market cap + etc
"assetProfile", # summaryProfile + company officers
"fundProfile",
"price", # current prices
"quoteType", # quoteType
"esgScores", # Environmental, social, and governance (ESG) scores, sustainability and ethical performance of companies
"incomeStatementHistory",
"incomeStatementHistoryQuarterly",
"balanceSheetHistory",
"balanceSheetHistoryQuarterly",
"cashFlowStatementHistory",
"cashFlowStatementHistoryQuarterly",
"defaultKeyStatistics", # KPIs (PE, enterprise value, EPS, EBITA, and more)
"financialData", # Financial KPIs (revenue, gross margins, operating cash flow, free cash flow, and more)
"calendarEvents", # future earnings date
"secFilings", # SEC filings, such as 10K and 10Q reports
"upgradeDowngradeHistory", # upgrades and downgrades that analysts have given a company's stock
"institutionOwnership", # institutional ownership, holders and shares outstanding
"fundOwnership", # mutual fund ownership, holders and shares outstanding
"majorDirectHolders",
"majorHoldersBreakdown",
"insiderTransactions", # insider transactions, such as the number of shares bought and sold by company executives
"insiderHolders", # insider holders, such as the number of shares held by company executives
"netSharePurchaseActivity", # net share purchase activity, such as the number of shares bought and sold by company executives
"earnings", # earnings history
"earningsHistory",
"earningsTrend", # earnings trend
"industryTrend",
"indexTrend",
"sectorTrend",
"recommendationTrend",
"futuresChain",
)
Loading

0 comments on commit bec30a0

Please sign in to comment.