Add dividend calendar from nasdaq (#1189)

* Add dividend calendar from nasdaq

* tests + hugo

* missed controller test

* gst file

* Add timeout idea and better print message

* fix divcal

Co-authored-by: DidierRLopes <dro.lopes@campus.fct.unl.pt>
This commit is contained in:
jmaslek
2022-01-15 16:58:00 -05:00
committed by GitHub
parent a3255b96a0
commit 5499dad5c7
15 changed files with 1585 additions and 1302 deletions

View File

@@ -54,6 +54,7 @@ class DiscoveryController(BaseController):
"rtearn",
"cnews",
"rtat",
"divcal",
]
arkord_sortby_choices = [
@@ -94,6 +95,16 @@ class DiscoveryController(BaseController):
"Technology",
]
]
dividend_columns = [
"Name",
"Symbol",
"Ex-Dividend Date",
"Payment Date",
"Record Date",
"Dividend",
"Indicated Annual Dividend",
"Announcement Date",
]
def __init__(self, queue: List[str] = None):
"""Constructor"""
@@ -109,6 +120,8 @@ class DiscoveryController(BaseController):
choices["arkord"]["--fund"] = {c: None for c in self.arkord_fund_choices}
choices["cnews"]["-t"] = {c: None for c in self.cnews_type_choices}
choices["cnews"]["--type"] = {c: None for c in self.cnews_type_choices}
choices["divcal"]["-s"] = {c: None for c in self.dividend_columns}
choices["divcal"]["--sort"] = {c: None for c in self.dividend_columns}
self.completer = NestedCompleter.from_nested_dict(choices)
@@ -141,10 +154,63 @@ class DiscoveryController(BaseController):
[src][Pennystockflow.com][/src]
hotpenny today's hot penny stocks
[src][NASDAQ Data Link (Formerly Quandl)][/src]
rtat top 10 retail traded stocks per day[/cmds]
rtat top 10 retail traded stocks per day
divcal dividend calendar for selected date[/cmds]
"""
console.print(text=help_text, menu="Stocks - Discovery")
# TODO Add flag for adding last price to the following table
def call_divcal(self, other_args: List[str]):
"""Process divcal command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="divcal",
description="""Get dividend calendar for selected date""",
)
parser.add_argument(
"-d",
"--date",
default=datetime.now(),
type=valid_date,
dest="date",
help="Date to get format for",
)
parser.add_argument(
"-s",
"--sort",
default=["Dividend"],
nargs="+",
type=str,
help="Column to sort by",
dest="sort",
)
parser.add_argument(
"-a",
"--ascend",
default=False,
action="store_true",
help="Flag to sort in ascending order",
dest="ascend",
)
if other_args and "-" not in other_args[0][0]:
other_args.insert(0, "-d")
ns_parser = parse_known_args_and_warn(
parser, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED, limit=10
)
if ns_parser:
sort_col = " ".join(ns_parser.sort)
if sort_col not in self.dividend_columns:
console.print(f"{sort_col} not a valid selection for sorting.\n")
return
nasdaq_view.display_dividend_calendar(
ns_parser.date.strftime("%Y-%m-%d"),
sort_col=sort_col,
ascending=ns_parser.ascend,
limit=ns_parser.limit,
export=ns_parser.export,
)
def call_rtearn(self, other_args: List[str]):
"""Process rtearn command"""
parser = argparse.ArgumentParser(

View File

@@ -4,6 +4,7 @@ __docformat__ = "numpy"
import pandas as pd
import requests
import gamestonk_terminal.config_terminal as cfg
from gamestonk_terminal.helper_funcs import get_user_agent
def get_retail_tickers() -> pd.DataFrame:
@@ -23,3 +24,35 @@ def get_retail_tickers() -> pd.DataFrame:
df = pd.DataFrame(r.json()["datatable"]["data"])
df.columns = ["Date", "Ticker", "Activity", "Sentiment"]
return df
def get_dividend_cal(date: str) -> pd.DataFrame:
"""Gets dividend calendar for given date. Date represents Ex-Dividend Date
Parameters
----------
date: datetime
Date to get for in format YYYY-MM-DD
Returns
-------
pd.DataFrame:
Dataframe of dividend calendar
"""
ag = get_user_agent()
# Nasdaq API doesn't like this user agent, thus we always get other than this particular one
while (
ag
== "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:82.1) Gecko/20100101 Firefox/82.1"
):
ag = get_user_agent()
try:
r = requests.get(
f"https://api.nasdaq.com/api/calendar/dividends?date={date}",
headers={"User-Agent": ag},
)
if r.status_code == 200:
return pd.DataFrame(r.json()["data"]["calendar"]["rows"])
except requests.exceptions.ReadTimeout:
return pd.DataFrame()
return pd.DataFrame()

View File

@@ -6,7 +6,7 @@ import os
from colorama import Style
from tabulate import tabulate
from gamestonk_terminal.helper_funcs import export_data
from gamestonk_terminal.helper_funcs import export_data, rich_table_from_df
from gamestonk_terminal.stocks.discovery import nasdaq_model
import gamestonk_terminal.feature_flags as gtff
from gamestonk_terminal.rich_config import console
@@ -40,3 +40,59 @@ def display_top_retail(n_days: int = 3, export: str = ""):
console.print("")
export_data(export, os.path.dirname(os.path.abspath(__file__)), "rtat", retails)
def display_dividend_calendar(
date: str,
sort_col: str = "Dividend",
ascending: bool = False,
limit: int = 10,
export: str = "",
):
"""Display NASDAQ dividend calendar
Parameters
----------
date: str
Date to get dividend calendar for
sort_col: str
Column to sort data for
ascending: bool
Flag to sort in ascending order
limit: int
Number of results to show
export: str
Format to export data
"""
div_map = {
"symbol": "Symbol",
"companyName": "Name",
"dividend_Ex_Date": "Ex-Dividend Date",
"payment_Date": "Payment Date",
"record_Date": "Record Date",
"dividend_Rate": "Dividend",
"indicated_Annual_Dividend": "Annual Dividend",
"announcement_Date": "Announcement Date",
}
calendar = nasdaq_model.get_dividend_cal(date)
if calendar.empty:
console.print(
"No data found. Check that the date provided is a market day. If it is then try this function"
" again as the request may have not gone through.\n"
)
return
calendar = calendar.drop(columns=["announcement_Date"])
calendar.columns = calendar.columns.map(div_map)
calendar = calendar.sort_values(by=sort_col, ascending=ascending)
if gtff.USE_TABULATE_DF:
console.print(
rich_table_from_df(
calendar.head(limit),
headers=list(calendar.columns),
title=f"[bold]Dividend Calendar for {date}[/bold]",
)
)
else:
console.print(calendar.head(limit).to_string())
console.print("")
export_data(export, os.path.dirname(os.path.abspath(__file__)), "divcal", calendar)

View File

@@ -29,4 +29,5 @@ hotpenny
rtat
reset
r
divcal -l 2
exit

View File

@@ -0,0 +1,72 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://api.nasdaq.com/api/calendar/dividends?date=MOCK_DATE
response:
body:
string: !!binary |
H4sIAAAAAAAAAL2XXW/aMBSG/0qUi12R1Dbjo9whPqZIpaXA1ItpQm7sUkuJjRynAyH+e08CoaGU
ZIMpEgLnvM5J3ufYOWFjM2qo3dnYPg24ZFQn41dOGddRMozW4bMK7I493Q1qtq/CJZXrexpyCKc/
NZuJN8Hg/PlgNe9TkyiDldPfR600VLOXdB1yabIZ491hpmruK80ycZIeZdoh/2SnZplBEpIJH6Js
3pUypsH8oHVsL9OsnWblzqNSqlj6PH9H3Vxsd+kt3Jf6Ayh+bT4576lXLq1v1tRwYGX1AhVx5gzA
7cNyqbSJpTBraxhLVrM86btwyQPM4cPwa2gI32B8QxAhp7hAqx+0Y1jJaSSTPrFCLmq3CjFhF9fx
10AgK24miTGQKCFwJ0KRoO7HmhqhpDXW/IVrDSEKVICBCvkZIHf9cYVAcL1RCIS4pPEfgEx5wH3z
LxjG0yrXRTmGRvP2egwzunK67I1KQxcA4QPHlPuxFkbw6IjBrFspg5Kt0a63rkcwGXiztPrn10Ie
weS+2t3QLGHQJN+vZ+DJF00jo2PfxDq3AfLGf84qXf+NsvWPcON644+QNWkF+2pPOA32jeFk/08e
vUr7Qknd0SVlHwodGWumY/juDYaZ7XxTHKRl/uiGMK3KsuPismP33HJP8qJd3mLfI/DpiyW8cPwd
gVG1BFCzmAByW+1LEHjScN0XC2FocNrcvH6vd5FJ0rzEZElzw27B4kbnFveTkJI/04UCdwwqraF5
nTp9+vFQoVFcvI2hmOS808be6W940TUi5PCMToxu7FDI/TSCMHbQrUPIDKFO+oHbCOnqoBPiYOKQ
1oe+hXQhjyLo+HZHxkEAdAw1cfqfQvcUgzBBqGY/J+PR8UzG33igllwfxbfbd9rj0wetDAAA
headers:
Cache-Control:
- max-age=0, no-cache, no-store
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Length:
- '681'
Content-Type:
- application/json; charset=utf-8
Date:
- Sat, 15 Jan 2022 03:52:28 GMT
Expires:
- Sat, 15 Jan 2022 03:52:28 GMT
Pragma:
- no-cache
Server:
- Kestrel
Set-Cookie:
- ak_bmsc=2D77018EC2D10C1225CD33DA80EC7583~000000000000000000000000000000~YAAQxmV0aDOw2DJ+AQAA4HvdWw5/KqfepPjz4RuC3UllD198t32mcBWGOPVW5RgBp0FMFf0Hq7BTNS6oEX0TyfdDBG1hf4bIx42zyKKwrcQTDuoVT3WLKxubBU4YG/u4bQZ1AjBp+VaBnXK5+eCvc6MPkxga30kXyPCmmv8tcT9QeGtjjDqm+I3MED1hiuiiFi8f76vFhRaa2nk66iXGgMNUT2wAnTfn/k7aDSKp5GqExbZKLvVkWMyc/ola8rmbs6C62L8IX4XOAgGZbMygc9tf82TU83YIvnHOs+piIRDABLVYtqpJ3XV/BliV+hYsB9yPpr3He8dgL/U6AN1FpunwsejTJBFQGbPcx+yHzBvipR4lrTlyEtoVgUFS;
Domain=.nasdaq.com; Path=/; Expires=Sat, 15 Jan 2022 05:52:28 GMT; Max-Age=7200;
HttpOnly
Strict-Transport-Security:
- max-age=86400
Vary:
- Accept-Encoding
X-EdgeConnect-MidMile-RTT:
- '20'
- '30'
X-EdgeConnect-Origin-MEX-Latency:
- '39'
- '39'
gid:
- '0132'
lang:
- en
rid:
- 54e94667-dec5-48fa-ae07-c55a4143f8d4
srctype:
- default
status:
code: 200
message: OK
version: 1

View File

@@ -33,3 +33,14 @@ def test_get_ipo_calendar_400(mocker):
retail_tickers = nasdaq_model.get_retail_tickers()
assert retail_tickers.empty
@pytest.mark.vcr(record_mode="none")
def test_dividend_fails(mocker):
mock_response = requests.Response()
mock_response.status_code = 400
mocker.patch(target="requests.get", new=mocker.Mock(return_value=mock_response))
retail_tickers = nasdaq_model.get_dividend_cal("2021-01-01")
assert retail_tickers.empty

View File

@@ -10,9 +10,8 @@ from gamestonk_terminal.stocks.discovery import nasdaq_view
@pytest.fixture(scope="module")
def vcr_config():
return {
"filter_query_parameters": [
("api_key", "MOCK_API"),
]
"filter_headers": [("User-Agent", None)],
"filter_query_parameters": [("api_key", "MOCK_API"), ("date", "MOCK_DATE")],
}
@@ -26,3 +25,12 @@ def test_display_top_retail(mocker, use_tab):
)
nasdaq_view.display_top_retail(n_days=3, export="")
@pytest.mark.default_cassette("test_display_dividend_calendar")
@pytest.mark.vcr
@pytest.mark.record_stdout
def test_display_dividend_calendar(mocker):
mocker.patch.object(target=nasdaq_view.gtff, attribute="USE_TABULATE_DF", new=False)
nasdaq_view.display_dividend_calendar(date="2022-01-11", limit=2)

View File

@@ -26,4 +26,5 @@
hotpenny today's hot penny stocks
[NASDAQ Data Link (Formerly Quandl)]
rtat top 10 retail traded stocks per day
divcal dividend calendar for selected date

View File

@@ -0,0 +1,4 @@
Name Symbol Ex-Dividend Date Payment Date Record Date Dividend Annual Dividend
9 InterDigital, Inc. IDCC 01/11/2022 01/26/2022 01/12/2022 0.35 1.40
10 Winnebago Industries, Inc. WGO 01/11/2022 01/26/2022 01/12/2022 0.18 0.72

View File

@@ -1,39 +1,39 @@
2021-12-07 Top Retail:
2022-01-11 Top Retail:
Ticker Activity Sentiment
TSLA 0.0321 2
TQQQ 0.0160 1
SPY 0.0237 1
QQQ 0.0269 1
NVDA 0.0461 1
MSFT 0.0122 3
LCID 0.0175 -5
INTC 0.0120 -8
AMD 0.0307 1
AAPL 0.0535 0
TSLA 0.0445 2
TQQQ 0.0233 4
SPY 0.0258 3
QQQ 0.0330 2
NVDA 0.0384 1
MSFT 0.0155 4
LCID 0.0146 -4
F 0.0117 3
AMD 0.0447 1
AAPL 0.0400 -1
2021-12-08 Top Retail:
2022-01-12 Top Retail:
Ticker Activity Sentiment
TSLA 0.0303 2
TQQQ 0.0168 3
SPY 0.0192 -1
ROKU 0.0230 0
QQQ 0.0208 1
NVDA 0.0541 1
MSFT 0.0115 4
FB 0.0127 1
AMD 0.0255 2
AAPL 0.0651 0
TSLA 0.0548 2
TQQQ 0.0268 6
SPY 0.0275 4
QQQ 0.0292 4
NVDA 0.0389 2
MSFT 0.0174 4
LCID 0.0121 -3
F 0.0136 3
AMD 0.0423 2
AAPL 0.0394 0
2021-12-09 Top Retail:
2022-01-13 Top Retail:
Ticker Activity Sentiment
TSLA 0.0379 2
TQQQ 0.0203 4
SPY 0.0231 1
ROKU 0.0119 0
QQQ 0.0243 4
NVDA 0.0401 1
LCID 0.0312 -3
FB 0.0114 1
AMD 0.0312 2
AAPL 0.0698 1
TSM 0.0158 7
TSLA 0.0542 2
TQQQ 0.0210 6
SPY 0.0283 5
QQQ 0.0368 4
NVDA 0.0433 1
MSFT 0.0230 6
F 0.0233 0
AMD 0.0383 2
AAPL 0.0347 2

View File

@@ -1,75 +1,75 @@
2021-12-07 Top Retail:
2022-01-11 Top Retail:
╒══════╤════════════╤═════════════╕
│ │ Activity │ Sentiment │
╞══════╪════════════╪═════════════╡
│ TSLA │ 0.0321 │ 2 │
│ TSLA │ 0.0445 │ 2 │
├──────┼────────────┼─────────────┤
│ TQQQ │ 0.016 │ 1 │
│ TQQQ │ 0.0233 │ 4 │
├──────┼────────────┼─────────────┤
│ SPY │ 0.0237 │ 1 │
│ SPY │ 0.0258 │ 3 │
├──────┼────────────┼─────────────┤
│ QQQ │ 0.0269 │ 1 │
│ QQQ │ 0.033 │ 2 │
├──────┼────────────┼─────────────┤
│ NVDA │ 0.0461 │ 1 │
│ NVDA │ 0.0384 │ 1 │
├──────┼────────────┼─────────────┤
│ MSFT │ 0.0122 │ 3 │
│ MSFT │ 0.0155 │ 4 │
├──────┼────────────┼─────────────┤
│ LCID │ 0.0175 │ -5 │
│ LCID │ 0.0146 │ -4 │
├──────┼────────────┼─────────────┤
│ INTC │ 0.012 │ -8 │
│ F │ 0.0117 │ 3 │
├──────┼────────────┼─────────────┤
│ AMD │ 0.0307 │ 1 │
│ AMD │ 0.0447 │ 1 │
├──────┼────────────┼─────────────┤
│ AAPL │ 0.0535 │ 0 │
│ AAPL │ 0.04 │ -1 │
╘══════╧════════════╧═════════════╛
2021-12-08 Top Retail:
2022-01-12 Top Retail:
╒══════╤════════════╤═════════════╕
│ │ Activity │ Sentiment │
╞══════╪════════════╪═════════════╡
│ TSLA │ 0.0303 │ 2 │
│ TSLA │ 0.0548 │ 2 │
├──────┼────────────┼─────────────┤
│ TQQQ │ 0.0168 │ 3 │
│ TQQQ │ 0.0268 │ 6 │
├──────┼────────────┼─────────────┤
│ SPY │ 0.0192 │ -1 │
│ SPY │ 0.0275 │ 4 │
├──────┼────────────┼─────────────┤
│ ROKU │ 0.023 │ 0 │
│ QQQ │ 0.0292 │ 4 │
├──────┼────────────┼─────────────┤
│ QQQ │ 0.0208 │ 1 │
│ NVDA │ 0.0389 │ 2 │
├──────┼────────────┼─────────────┤
│ NVDA │ 0.0541 │ 1 │
│ MSFT │ 0.0174 │ 4 │
├──────┼────────────┼─────────────┤
│ MSFT │ 0.0115 │ 4 │
│ LCID │ 0.0121 │ -3 │
├──────┼────────────┼─────────────┤
│ FB │ 0.0127 │ 1 │
│ F │ 0.0136 │ 3 │
├──────┼────────────┼─────────────┤
│ AMD │ 0.0255 │ 2 │
│ AMD │ 0.0423 │ 2 │
├──────┼────────────┼─────────────┤
│ AAPL │ 0.0651 │ 0 │
│ AAPL │ 0.0394 │ 0 │
╘══════╧════════════╧═════════════╛
2021-12-09 Top Retail:
2022-01-13 Top Retail:
╒══════╤════════════╤═════════════╕
│ │ Activity │ Sentiment │
╞══════╪════════════╪═════════════╡
│ TSLA │ 0.0379 │ 2 │
│ TSM │ 0.0158 │ 7 │
├──────┼────────────┼─────────────┤
│ TQQQ │ 0.0203 │ 4 │
│ TSLA │ 0.0542 │ 2 │
├──────┼────────────┼─────────────┤
│ SPY │ 0.0231 │ 1 │
│ TQQQ │ 0.021 │ 6 │
├──────┼────────────┼─────────────┤
│ ROKU │ 0.0119 │ 0 │
│ SPY │ 0.0283 │ 5 │
├──────┼────────────┼─────────────┤
│ QQQ │ 0.0243 │ 4 │
│ QQQ │ 0.0368 │ 4 │
├──────┼────────────┼─────────────┤
│ NVDA │ 0.0401 │ 1 │
│ NVDA │ 0.0433 │ 1 │
├──────┼────────────┼─────────────┤
│ LCID │ 0.0312 │ -3 │
│ MSFT │ 0.023 │ 6 │
├──────┼────────────┼─────────────┤
│ FB │ 0.0114 │ 1 │
│ F │ 0.0233 │ 0 │
├──────┼────────────┼─────────────┤
│ AMD │ 0.0312 │ 2 │
│ AMD │ 0.0383 │ 2 │
├──────┼────────────┼─────────────┤
│ AAPL │ 0.0698 │ 1 │
│ AAPL │ 0.0347 │ 2 │
╘══════╧════════════╧═════════════╛

View File

@@ -0,0 +1,30 @@
```
usage: divcal [-d DATE] [-s SORT [SORT ...]] [-a] [-h] [--export {csv,json,xlsx}] [-l LIMIT]
```
Get dividend calendar for selected date
```
optional arguments:
-d DATE, --date DATE Date to get format for (default: 2022-01-14 22:50:41.433203)
-s SORT [SORT ...], --sort SORT [SORT ...]
Column to sort by (default: ['Dividend'])
-a, --ascend Flag to sort in ascending order (default: False)
-h, --help show this help message (default: False)
--export {csv,json,xlsx}
Export raw data into csv, json, xlsx (default: )
-l LIMIT, --limit LIMIT
Number of entries to show in data. (default: 10)
```
```
Dividend Calendar for 2022-01-14
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Name ┃ Symbol ┃ Ex-Dividend Date ┃ Payment Date ┃ Record Date ┃ Dividend ┃ Annual Dividend ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ Grupo Aeroportuario del Centro Norte S.A.B. de C.V. │ OMAB │ 01/14/2022 │ 01/26/2022 │ 01/18/2022 │ 7.77 │ 5.57 │
├─────────────────────────────────────────────────────┼────────┼──────────────────┼──────────────┼─────────────┼──────────┼─────────────────┤
│ PNC Financial Services Group, Inc. (The) │ PNC │ 01/14/2022 │ 02/05/2022 │ 01/18/2022 │ 1.25 │ 5.00 │
├─────────────────────────────────────────────────────┼────────┼──────────────────┼──────────────┼─────────────┼──────────┼─────────────────┤
│ Sabine Royalty Trust │ SBR │ 01/14/2022 │ 01/31/2022 │ 01/18/2022 │ 0.88 │ 10.52 │
└─────────────────────────────────────────────────────┴────────┴──────────────────┴──────────────┴─────────────┴──────────┴─────────────────┘
```

View File

@@ -54,6 +54,8 @@ main:
ref: "/stocks/discovery/fds"
- name: rtat
ref: "/stocks/discovery/rtat"
- name: divcal
ref: "/stocks/discovery/divcal"
- name: Sector and Industry Analysis (SIA)
ref: "/stocks/sia"
sub: