Skip to content

Commit 23a3128

Browse files
committed
feat: earning calendar first commit
bringing Calendar class to yfinance, already working, still need to verify some stuff and integrate with rest of yfinance rename to calendars: introduce the idea of multiple calendars refactor: more types of calendar (ipo, splits, etc) added custom class Operand for query building documentation and example reference rename Operand to CalendarQuery input dates support date and str, improved col names, improved cache management, rm useless helper functions, rm col names from docstring added support for timestamps utils._parse_user_dt has default tz=utc
1 parent bc67252 commit 23a3128

File tree

7 files changed

+665
-2
lines changed

7 files changed

+665
-2
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import yfinance as yf
2+
from datetime import datetime, timedelta
3+
4+
# Default init (today + 7 days)
5+
calendar = yf.Calendars()
6+
7+
# Today's events: calendar of 1 day
8+
tomorrow = datetime.now() + timedelta(days=1)
9+
calendar = yf.Calendars(end=tomorrow)
10+
11+
# Default calendar queries - accessing the properties will fetch the data from YF
12+
calendar.earnings_calendar
13+
calendar.ipo_info_calendar
14+
calendar.splits_calendar
15+
calendar.economic_events_calendar
16+
17+
# Manual queries
18+
calendar.get_earnings_calendar()
19+
calendar.get_ipo_info_calendar()
20+
calendar.get_splits_calendar()
21+
calendar.get_economic_events_calendar()
22+
23+
# Earnings calendar custom filters
24+
calendar.get_earnings_calendar(
25+
market_cap=100_000_000, # filter out small-cap
26+
filter_most_active=True, # show only actively traded. Uses: `screen(query="MOST_ACTIVES")`
27+
)
28+
29+
# Example of real use case:
30+
# Get inminent unreported earnings events
31+
today = datetime.now()
32+
is_friday = today.weekday() == 4
33+
day_after_tomorrow = today + timedelta(days=4 if is_friday else 2)
34+
35+
calendar = yf.Calendars(today, day_after_tomorrow)
36+
df = calendar.get_earnings_calendar(limit=100)
37+
38+
unreported_df = df[df["Reported EPS"].isnull()]

doc/source/reference/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ The following are the publicly available classes, and functions exposed by the `
1616
- :attr:`Ticker <yfinance.Ticker>`: Class for accessing single ticker data.
1717
- :attr:`Tickers <yfinance.Tickers>`: Class for handling multiple tickers.
1818
- :attr:`Market <yfinance.Market>`: Class for accessing market summary.
19+
- :attr:`Calendars <yfinance.Calendars>`: Class for accessing calendar events data.
1920
- :attr:`download <yfinance.download>`: Function to download market data for multiple tickers.
2021
- :attr:`Search <yfinance.Search>`: Class for accessing search results.
2122
- :attr:`Lookup <yfinance.Lookup>`: Class for looking up tickers.
@@ -38,6 +39,7 @@ The following are the publicly available classes, and functions exposed by the `
3839
yfinance.ticker_tickers
3940
yfinance.stock
4041
yfinance.market
42+
yfinance.calendars
4143
yfinance.financials
4244
yfinance.analysis
4345
yfinance.market
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=====================
2+
Calendars
3+
=====================
4+
5+
.. currentmodule:: yfinance
6+
7+
8+
Class
9+
------------
10+
The `Calendars` class allows you to get information about upcoming events, for example, earning events.
11+
12+
.. autosummary::
13+
:toctree: api/
14+
15+
Calendars
16+
17+
Sample Code
18+
------------------
19+
20+
.. literalinclude:: examples/calendars.py
21+
:language: python

tests/test_calendars.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from datetime import datetime, timedelta, timezone
2+
import unittest
3+
4+
import pandas as pd
5+
6+
from tests.context import yfinance as yf, session_gbl
7+
8+
9+
class TestCalendars(unittest.TestCase):
10+
def setUp(self):
11+
self.calendars = yf.Calendars(session=session_gbl)
12+
13+
def test_get_earnings_calendar(self):
14+
result = self.calendars.get_earnings_calendar(limit=5)
15+
tickers = self.calendars.earnings_calendar.index.tolist()
16+
17+
self.assertIsInstance(result, pd.DataFrame)
18+
self.assertEqual(len(result), 5)
19+
self.assertIsInstance(tickers, list)
20+
self.assertEqual(len(tickers), len(result))
21+
self.assertEqual(tickers, result.index.tolist())
22+
23+
first_ticker = result.index.tolist()[0]
24+
result_first_ticker = self.calendars.earnings_calendar.loc[first_ticker].name
25+
self.assertEqual(first_ticker, result_first_ticker)
26+
27+
def test_get_earnings_calendar_init_params(self):
28+
result = self.calendars.get_earnings_calendar(limit=5)
29+
self.assertGreaterEqual(result['Event Start Date'].iloc[0], pd.to_datetime(datetime.now(tz=timezone.utc)))
30+
31+
start = datetime.now(tz=timezone.utc) - timedelta(days=7)
32+
result = yf.Calendars(start=start).get_earnings_calendar(limit=5)
33+
self.assertGreaterEqual(result['Event Start Date'].iloc[0], pd.to_datetime(start))
34+
35+
def test_get_ipo_info_calendar(self):
36+
result = self.calendars.get_ipo_info_calendar(limit=5)
37+
38+
self.assertIsInstance(result, pd.DataFrame)
39+
self.assertEqual(len(result), 5)
40+
41+
def test_get_economic_events_calendar(self):
42+
result = self.calendars.get_economic_events_calendar(limit=5)
43+
44+
self.assertIsInstance(result, pd.DataFrame)
45+
self.assertEqual(len(result), 5)
46+
47+
def test_get_splits_calendar(self):
48+
result = self.calendars.get_splits_calendar(limit=5)
49+
50+
self.assertIsInstance(result, pd.DataFrame)
51+
self.assertEqual(len(result), 5)
52+
53+
54+
if __name__ == "__main__":
55+
unittest.main()

yfinance/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from .search import Search
2424
from .lookup import Lookup
2525
from .ticker import Ticker
26+
from .calendars import Calendars
2627
from .tickers import Tickers
2728
from .multi import download
2829
from .live import WebSocket, AsyncWebSocket
@@ -42,7 +43,7 @@
4243
import warnings
4344
warnings.filterwarnings('default', category=DeprecationWarning, module='^yfinance')
4445

45-
__all__ = ['download', 'Market', 'Search', 'Lookup', 'Ticker', 'Tickers', 'enable_debug_mode', 'set_tz_cache_location', 'Sector', 'Industry', 'WebSocket', 'AsyncWebSocket']
46+
__all__ = ['download', 'Market', 'Search', 'Lookup', 'Ticker', 'Tickers', 'enable_debug_mode', 'set_tz_cache_location', 'Sector', 'Industry', 'WebSocket', 'AsyncWebSocket', 'Calendars']
4647
# screener stuff:
4748
__all__ += ['EquityQuery', 'FundQuery', 'screen', 'PREDEFINED_SCREENER_QUERIES']
4849

0 commit comments

Comments
 (0)