Skip to content

Commit

Permalink
Merge pull request #1716 from ranaroussi/dev
Browse files Browse the repository at this point in the history
sync dev -> main
  • Loading branch information
ValueRaider authored Oct 4, 2023
2 parents 5b1605b + 7da64b6 commit f6beadf
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 238 deletions.
2 changes: 1 addition & 1 deletion meta.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% set name = "yfinance" %}
{% set version = "0.2.30" %}
{% set version = "0.2.31b1" %}

package:
name: "{{ name|lower }}"
Expand Down
73 changes: 0 additions & 73 deletions test_yfinance.py

This file was deleted.

243 changes: 115 additions & 128 deletions tests/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,54 @@
"""
import pandas as pd
import numpy as np

from .context import yfinance as yf
from .context import session_gbl
from yfinance.exceptions import YFNotImplementedError


import unittest
import requests_cache

from typing import Union, Any

ticker_attributes = (
("major_holders", pd.DataFrame),
("institutional_holders", pd.DataFrame),
("mutualfund_holders", pd.DataFrame),
("splits", pd.Series),
("actions", pd.DataFrame),
("shares", pd.DataFrame),
("info", dict),
("calendar", pd.DataFrame),
("recommendations", Union[pd.DataFrame, dict]),
("earnings", pd.DataFrame),
("quarterly_earnings", pd.DataFrame),
("recommendations_summary", Union[pd.DataFrame, dict]),
("quarterly_cashflow", pd.DataFrame),
("cashflow", pd.DataFrame),
("quarterly_balance_sheet", pd.DataFrame),
("balance_sheet", pd.DataFrame),
("quarterly_income_stmt", pd.DataFrame),
("income_stmt", pd.DataFrame),
("analyst_price_target", pd.DataFrame),
("revenue_forecasts", pd.DataFrame),
("sustainability", pd.DataFrame),
("options", tuple),
("news", Any),
("earnings_trend", pd.DataFrame),
("earnings_dates", pd.DataFrame),
("earnings_forecasts", pd.DataFrame),
)

def assert_attribute_type(testClass: unittest.TestCase, instance, attribute_name, expected_type):
try:
attribute = getattr(instance, attribute_name)
if attribute is not None and expected_type is not Any:
testClass.assertEqual(type(attribute), expected_type)
except Exception:
testClass.assertRaises(
YFNotImplementedError, lambda: getattr(instance, attribute_name)
)

class TestTicker(unittest.TestCase):
session = None
Expand Down Expand Up @@ -61,39 +101,9 @@ def test_badTicker(self):
for k in dat.fast_info:
dat.fast_info[k]

dat.isin
dat.major_holders
dat.institutional_holders
dat.mutualfund_holders
dat.dividends
dat.splits
dat.actions
dat.get_shares_full()
dat.options
dat.news
dat.earnings_dates

dat.income_stmt
dat.quarterly_income_stmt
dat.balance_sheet
dat.quarterly_balance_sheet
dat.cashflow
dat.quarterly_cashflow

# These haven't been ported Yahoo API
# dat.shares
# dat.info
# dat.calendar
# dat.recommendations
# dat.earnings
# dat.quarterly_earnings
# dat.recommendations_summary
# dat.analyst_price_target
# dat.revenue_forecasts
# dat.sustainability
# dat.earnings_trend
# dat.earnings_forecasts

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

def test_goodTicker(self):
# that yfinance works when full api is called on same instance of ticker

Expand All @@ -113,61 +123,20 @@ def test_goodTicker(self):
for k in dat.fast_info:
dat.fast_info[k]

dat.isin
dat.major_holders
dat.institutional_holders
dat.mutualfund_holders
dat.dividends
dat.splits
dat.actions
dat.get_shares_full()
dat.options
dat.news
dat.earnings_dates

dat.income_stmt
dat.quarterly_income_stmt
dat.balance_sheet
dat.quarterly_balance_sheet
dat.cashflow
dat.quarterly_cashflow

# These require decryption which is broken:
# dat.shares
# dat.info
# dat.calendar
# dat.recommendations
# dat.earnings
# dat.quarterly_earnings
# dat.recommendations_summary
# dat.analyst_price_target
# dat.revenue_forecasts
# dat.sustainability
# dat.earnings_trend
# dat.earnings_forecasts

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, debug_mode=False, raise_errors=False)
dat._get_ticker_tz(proxy=self.proxy, timeout=5, debug_mode=False, raise_errors=False)
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.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_major_holders(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)
Expand All @@ -184,38 +153,6 @@ def test_goodTicker_withProxy(self):
self.assertIsNotNone(v)
self.assertTrue(len(v) > 0)

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_income_stmt(proxy=self.proxy)
self.assertIsNotNone(v)
self.assertFalse(v.empty)
Expand Down Expand Up @@ -244,10 +181,6 @@ def test_goodTicker_withProxy(self):
self.assertIsNotNone(v)
self.assertFalse(v.empty)

v = dat.get_shares(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)
Expand All @@ -264,11 +197,60 @@ def test_goodTicker_withProxy(self):
self.assertIsNotNone(v)
self.assertFalse(v.empty)

# TODO: enable after merge
# dat.get_history_metadata(proxy=self.proxy)
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)


class TestTickerHistory(unittest.TestCase):
session = None
Expand Down Expand Up @@ -312,16 +294,21 @@ def test_no_expensive_calls_introduced(self):
As doing other type of scraping calls than "query2.finance.yahoo.com/v8/finance/chart" to yahoo website
will quickly trigger spam-block when doing bulk download of history data.
"""
session = requests_cache.CachedSession(backend='memory')
ticker = yf.Ticker("GOOGL", session=session)
ticker.history("1y")
actual_urls_called = tuple([r.url for r in session.cache.filter()])
session.close()
symbol = "GOOGL"
range = "1y"
with requests_cache.CachedSession(backend="memory") as session:
ticker = yf.Ticker(symbol, session=session)
ticker.history(range)
actual_urls_called = tuple([r.url for r in session.cache.filter()])

expected_urls = (
'https://query2.finance.yahoo.com/v8/finance/chart/GOOGL?events=div,splits,capitalGains&includePrePost=False&interval=1d&range=1y',
f"https://query2.finance.yahoo.com/v8/finance/chart/{symbol}?events=div%2Csplits%2CcapitalGains&includePrePost=False&interval=1d&range={range}",
)
self.assertEqual(
expected_urls,
actual_urls_called,
"Different than expected url used to fetch history."
)
self.assertEqual(expected_urls, actual_urls_called, "Different than expected url used to fetch history.")

def test_dividends(self):
data = self.ticker.dividends
self.assertIsInstance(data, pd.Series, "data has wrong type")
Expand Down
Loading

0 comments on commit f6beadf

Please sign in to comment.