mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
[Feature] Add Workspace App To openbb-nasdaq For Company Filings As PDFs (#7135)
* add custom app launcher to openbb-nasdaq * f-string * linters * linters * readme * mypy * grammar police * cleanup test code --------- Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com>
This commit is contained in:
65
openbb_platform/providers/nasdaq/README.md
vendored
65
openbb_platform/providers/nasdaq/README.md
vendored
@@ -10,4 +10,67 @@ To install the extension:
|
||||
pip install openbb-nasdaq
|
||||
```
|
||||
|
||||
Documentation available [here](https://docs.openbb.co/platform/developer_guide/contributing).
|
||||
## Coverage
|
||||
|
||||
The following endpoints are covered by this extension:
|
||||
|
||||
- `obb.economy.calendar`
|
||||
- `obb.equity.calendar.dividend`
|
||||
- `obb.equity.calendar.earnings`
|
||||
- `obb.equity.calendar.ipo`
|
||||
- `obb.equity.search`
|
||||
- `obb.equity.screener`
|
||||
- `obb.equity.fundamental.dividend`
|
||||
- `obb.equity.fundamental.filings`
|
||||
|
||||
Router extensions are required (`openbb-economy` & `openbb-equity`) to populate endpoints, but fetchers can be used independent of the Python and API interfaces.
|
||||
|
||||
```python
|
||||
from openbb_nasdaq import nasdaq_provider
|
||||
|
||||
nasdaq_provider.fetcher_dict
|
||||
```
|
||||
|
||||
```python
|
||||
{'CalendarDividend': openbb_nasdaq.models.calendar_dividend.NasdaqCalendarDividendFetcher,
|
||||
'CalendarEarnings': openbb_nasdaq.models.calendar_earnings.NasdaqCalendarEarningsFetcher,
|
||||
'CalendarIpo': openbb_nasdaq.models.calendar_ipo.NasdaqCalendarIpoFetcher,
|
||||
'CompanyFilings': openbb_nasdaq.models.company_filings.NasdaqCompanyFilingsFetcher,
|
||||
'EconomicCalendar': openbb_nasdaq.models.economic_calendar.NasdaqEconomicCalendarFetcher,
|
||||
'EquitySearch': openbb_nasdaq.models.equity_search.NasdaqEquitySearchFetcher,
|
||||
'EquityScreener': openbb_nasdaq.models.equity_screener.NasdaqEquityScreenerFetcher,
|
||||
'HistoricalDividends': openbb_nasdaq.models.historical_dividends.NasdaqHistoricalDividendsFetcher,
|
||||
'TopRetail': openbb_nasdaq.models.top_retail.NasdaqTopRetailFetcher}
|
||||
```
|
||||
|
||||
## OpenBB Workspace App
|
||||
|
||||
This package includes a standalone Workspace application for viewing market calendars and company filings.
|
||||
|
||||
Launch it from the command line, with the environment active, by entering:
|
||||
|
||||
```sh
|
||||
openbb-api --app openbb_nasdaq.app:app --factory
|
||||
```
|
||||
|
||||
This will start the FastAPI application via Uvicorn and serve the configuration files to Workspace when added as a backend data source.
|
||||
|
||||
To see all the launch arguments, use:
|
||||
|
||||
```sh
|
||||
openbb-api --help
|
||||
```
|
||||
|
||||
The application is served by a factory function, and the FastAPI instance can be utilized by calling the `main` function.
|
||||
|
||||
```python
|
||||
from openbb_nasdaq.app import main
|
||||
|
||||
app = main()
|
||||
```
|
||||
|
||||
## OpenBB Documentation
|
||||
|
||||
OpenBB Platform documentation is available [here](https://docs.openbb.co/platform).
|
||||
|
||||
OpenBB Workspace documentation is available [here](https://docs.openbb.co/workspace).
|
||||
|
||||
727
openbb_platform/providers/nasdaq/openbb_nasdaq/app.py
Normal file
727
openbb_platform/providers/nasdaq/openbb_nasdaq/app.py
Normal file
@@ -0,0 +1,727 @@
|
||||
"""OpenBB Workspace Application.
|
||||
|
||||
This includes widgets and endpoints for fetching and displaying
|
||||
SEC filings, as well as calendars for earnings, dividends, ipos,
|
||||
and global economic events from the public Nasdaq website.
|
||||
|
||||
To use this app, launch it with:
|
||||
|
||||
```bash
|
||||
openbb-api --app openbb_nasdaq.app:main --factory
|
||||
```
|
||||
|
||||
Then navigate to the OpenBB Workspace and add the server as a backend data source.
|
||||
|
||||
Open the server's URL in your browser for more information on connecting to the OpenBB Workspace.
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-statements, too-many-locals, line-too-long
|
||||
|
||||
|
||||
def main():
|
||||
"""Return a FastAPI app instance."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from datetime import datetime
|
||||
from typing import Annotated, Literal, Optional
|
||||
|
||||
from async_lru import alru_cache
|
||||
from fastapi import Depends, FastAPI
|
||||
from openbb_nasdaq.models.calendar_dividend import NasdaqCalendarDividendFetcher
|
||||
from openbb_nasdaq.models.calendar_earnings import NasdaqCalendarEarningsFetcher
|
||||
from openbb_nasdaq.models.calendar_ipo import NasdaqCalendarIpoFetcher
|
||||
from openbb_nasdaq.models.company_filings import NasdaqCompanyFilingsFetcher
|
||||
from openbb_nasdaq.models.economic_calendar import NasdaqEconomicCalendarFetcher
|
||||
from openbb_nasdaq.models.equity_search import NasdaqEquitySearchFetcher
|
||||
from pandas import DataFrame
|
||||
|
||||
listings = DataFrame()
|
||||
|
||||
current_year = int(datetime.now().year)
|
||||
years = sorted(
|
||||
[{"label": str(i), "value": i} for i in range(1994, current_year + 1)],
|
||||
key=lambda x: x["value"], # type: ignore
|
||||
reverse=True,
|
||||
)
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
async def get_listings() -> DataFrame:
|
||||
"""Get the Nasdaq listings."""
|
||||
return listings
|
||||
|
||||
Nasdaqlistings = Annotated[
|
||||
DataFrame,
|
||||
Depends(get_listings),
|
||||
]
|
||||
|
||||
async def startup_event():
|
||||
"""Startup event for the FastAPI app."""
|
||||
nonlocal listings
|
||||
fetcher = NasdaqEquitySearchFetcher()
|
||||
|
||||
directory = await fetcher.fetch_data({}, {})
|
||||
|
||||
listings = DataFrame([d.model_dump() for d in directory]).query( # type: ignore
|
||||
"test_issue == 'N' and etf == 'N'"
|
||||
" and not name.str.contains('%')"
|
||||
" and not name.str.contains('Unit')"
|
||||
" and not name.str.contains('Rights')"
|
||||
" and not name.str.contains('Warrant')"
|
||||
" and not name.str.contains('Preferred')"
|
||||
)
|
||||
|
||||
app.add_event_handler("startup", startup_event)
|
||||
|
||||
@app.get("/get_symbol_choices", include_in_schema=False)
|
||||
async def get_symbol_choices(
|
||||
directory: Nasdaqlistings, # type: ignore
|
||||
symbol: Optional[str] = None,
|
||||
year: Optional[int] = None,
|
||||
form_group: Optional[str] = None,
|
||||
) -> list:
|
||||
"""Get symbol choices for the Nasdaq listings."""
|
||||
|
||||
if symbol and year and form_group:
|
||||
return await get_document_choices(symbol, year, form_group)
|
||||
|
||||
items = directory.set_index("symbol")["name"].to_dict()
|
||||
|
||||
return [
|
||||
{"value": k, "label": k, "extraInfo": {"description": v}}
|
||||
for k, v in items.items()
|
||||
]
|
||||
|
||||
@alru_cache
|
||||
async def get_document_choices(
|
||||
symbol: Optional[str] = None,
|
||||
year: Optional[int] = None,
|
||||
form_group: Literal[
|
||||
"annual",
|
||||
"quarterly",
|
||||
"proxy",
|
||||
"insider",
|
||||
"8k",
|
||||
"registration",
|
||||
"comment",
|
||||
] = "8k",
|
||||
) -> list:
|
||||
"""Get document choices for the given symbol."""
|
||||
fetcher = NasdaqCompanyFilingsFetcher()
|
||||
|
||||
params = {
|
||||
"symbol": symbol,
|
||||
"year": year,
|
||||
"form_group": form_group,
|
||||
}
|
||||
|
||||
items = await fetcher.fetch_data(params, {})
|
||||
docs: list = []
|
||||
|
||||
for item in items:
|
||||
form = item.model_dump() # type: ignore
|
||||
title = f"{form.get('filing_date', '')} - {'8-K' if form_group == '8k' else form_group.title()}"
|
||||
url = form.get("pdf_url")
|
||||
|
||||
if not url:
|
||||
continue
|
||||
docs.append({"label": title, "value": url})
|
||||
|
||||
return docs
|
||||
|
||||
@app.get(
|
||||
"/open_document",
|
||||
openapi_extra={
|
||||
"widget_config": {
|
||||
"type": "multi_file_viewer",
|
||||
"name": "SEC Filings",
|
||||
"description": "View SEC filings by company.",
|
||||
"refetchInterval": False,
|
||||
"widgetId": "nasdaq_company_filings",
|
||||
"params": [
|
||||
{
|
||||
"paramName": "document_url",
|
||||
"label": "Document URL",
|
||||
"description": "Select the document to open.",
|
||||
"type": "endpoint",
|
||||
"optionsEndpoint": "/get_symbol_choices",
|
||||
"optionsParams": {
|
||||
"symbol": "$symbol",
|
||||
"year": "$year",
|
||||
"form_group": "$form_group",
|
||||
},
|
||||
"show": False,
|
||||
"roles": ["fileSelector"],
|
||||
"multiSelect": True,
|
||||
},
|
||||
{
|
||||
"paramName": "symbol",
|
||||
"label": "Symbol",
|
||||
"description": (
|
||||
"Ticker symbol for the company."
|
||||
" Foreign (dual-listed) companies may not be required to file with the SEC."
|
||||
),
|
||||
"type": "endpoint",
|
||||
"value": "AAPL",
|
||||
"optionsEndpoint": "/get_symbol_choices",
|
||||
"style": {"popupWidth": 850},
|
||||
},
|
||||
{
|
||||
"paramName": "year",
|
||||
"label": "Calendar Year",
|
||||
"description": "Calendar year for the filings.",
|
||||
"value": years[0]["value"],
|
||||
"type": "number",
|
||||
"options": years,
|
||||
},
|
||||
{
|
||||
"paramName": "form_group",
|
||||
"label": "Form Group",
|
||||
"description": "Form group for the filings.",
|
||||
"value": "8k",
|
||||
"type": "text",
|
||||
"options": [
|
||||
{"label": "Annual", "value": "annual"},
|
||||
{"label": "Quarterly", "value": "quarterly"},
|
||||
{"label": "Proxy", "value": "proxy"},
|
||||
{"label": "Insider", "value": "insider"},
|
||||
{"label": "8-K", "value": "8k"},
|
||||
{"label": "Registration", "value": "registration"},
|
||||
{"label": "Comment", "value": "comment"},
|
||||
],
|
||||
},
|
||||
],
|
||||
"gridData": {"w": 40, "h": 30},
|
||||
}
|
||||
},
|
||||
)
|
||||
async def open_document(
|
||||
document_url: str,
|
||||
) -> dict:
|
||||
"""Open the selected PDF filing document."""
|
||||
import base64 # noqa
|
||||
from openbb_core.provider.utils.helpers import make_request
|
||||
|
||||
encoded_content: str = ""
|
||||
|
||||
if document_url and document_url.startswith("http"):
|
||||
response = make_request(document_url)
|
||||
response.raise_for_status()
|
||||
encoded_content = base64.b64encode(response.content).decode("utf-8")
|
||||
|
||||
return {
|
||||
"data_format": {
|
||||
"data_type": "pdf",
|
||||
"filename": document_url.split("/")[-1],
|
||||
},
|
||||
"content": encoded_content,
|
||||
}
|
||||
|
||||
@app.get(
|
||||
"/earnings_calendar",
|
||||
openapi_extra={
|
||||
"widget_config": {
|
||||
"name": "Earnings Calendar",
|
||||
"description": "Upcoming, and historical, company earnings releases (US Markets).",
|
||||
"category": "Equity",
|
||||
"subCategory": "Calendar",
|
||||
"type": "table",
|
||||
"searchCategory": "Equity",
|
||||
"widgetId": "nasdaq_earnings_calendar",
|
||||
"refetchInterval": False,
|
||||
"params": [
|
||||
{
|
||||
"label": "Start Date",
|
||||
"description": "Start date of the data.",
|
||||
"type": "date",
|
||||
"value": None,
|
||||
"paramName": "start_date",
|
||||
},
|
||||
{
|
||||
"label": "End Date",
|
||||
"description": "End date of the data.",
|
||||
"type": "date",
|
||||
"value": None,
|
||||
"paramName": "end_date",
|
||||
},
|
||||
],
|
||||
"gridData": {"w": 40, "h": 20},
|
||||
"data": {
|
||||
"table": {
|
||||
"columnsDefs": [
|
||||
{
|
||||
"field": "surprise_percent",
|
||||
"formatterFn": "normalizedPercent",
|
||||
"cellDataType": "number",
|
||||
"renderFn": "greenRed",
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
async def earnings_calendar(
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
) -> list[NasdaqCalendarEarningsFetcher.data_type]:
|
||||
"""Get the earnings calendar."""
|
||||
fetcher = NasdaqCalendarEarningsFetcher()
|
||||
|
||||
params = {
|
||||
"start_date": start_date,
|
||||
"end_date": end_date,
|
||||
}
|
||||
|
||||
return await fetcher.fetch_data(params, {}) # type: ignore
|
||||
|
||||
@app.get(
|
||||
"/dividend_calendar",
|
||||
openapi_extra={
|
||||
"widget_config": {
|
||||
"name": "Dividend Calendar",
|
||||
"description": "Upcoming, and historical, dividend payments (US Markets).",
|
||||
"category": "Equity",
|
||||
"subCategory": "Calendar",
|
||||
"type": "table",
|
||||
"searchCategory": "Equity",
|
||||
"widgetId": "nasdaq_dividends_calendar",
|
||||
"refetchInterval": False,
|
||||
"params": [
|
||||
{
|
||||
"label": "Start Date",
|
||||
"description": "Start date of the data.",
|
||||
"type": "date",
|
||||
"value": None,
|
||||
"paramName": "start_date",
|
||||
},
|
||||
{
|
||||
"label": "End Date",
|
||||
"description": "End date of the data.",
|
||||
"type": "date",
|
||||
"value": None,
|
||||
"paramName": "end_date",
|
||||
},
|
||||
],
|
||||
"gridData": {"w": 40, "h": 20},
|
||||
}
|
||||
},
|
||||
)
|
||||
async def dividend_calendar(
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
) -> list[NasdaqCalendarDividendFetcher.data_type]:
|
||||
"""Get the dividend calendar."""
|
||||
fetcher = NasdaqCalendarDividendFetcher()
|
||||
|
||||
params = {
|
||||
"start_date": start_date,
|
||||
"end_date": end_date,
|
||||
}
|
||||
|
||||
return await fetcher.fetch_data(params, {}) # type: ignore
|
||||
|
||||
@app.get(
|
||||
"/ipo_calendar",
|
||||
openapi_extra={
|
||||
"widget_config": {
|
||||
"name": "IPO Calendar",
|
||||
"description": "IPO announcements and calendar.",
|
||||
"category": "Equity",
|
||||
"subCategory": "Calendar",
|
||||
"type": "table",
|
||||
"searchCategory": "Equity",
|
||||
"widgetId": "nasdaq_ipo_calendar",
|
||||
"refetchInterval": False,
|
||||
"params": [
|
||||
{
|
||||
"label": "Start Date",
|
||||
"description": "Start date of the data, in YYYY-MM-DD format.",
|
||||
"optional": True,
|
||||
"type": "date",
|
||||
"value": None,
|
||||
"show": True,
|
||||
"paramName": "start_date",
|
||||
},
|
||||
{
|
||||
"label": "End Date",
|
||||
"description": "End date of the data, in YYYY-MM-DD format.",
|
||||
"optional": True,
|
||||
"type": "date",
|
||||
"value": None,
|
||||
"show": True,
|
||||
"paramName": "end_date",
|
||||
},
|
||||
{
|
||||
"label": "Status",
|
||||
"description": "Status of the IPO. [upcoming, priced, or withdrawn]",
|
||||
"optional": True,
|
||||
"type": "text",
|
||||
"value": None,
|
||||
"show": True,
|
||||
"options": [
|
||||
{"label": "upcoming", "value": "upcoming"},
|
||||
{"label": "priced", "value": "priced"},
|
||||
{"label": "filed", "value": "filed"},
|
||||
{"label": "withdrawn", "value": "withdrawn"},
|
||||
],
|
||||
"paramName": "status",
|
||||
},
|
||||
{
|
||||
"label": "Is SPO",
|
||||
"description": "If True, returns data for secondary public offerings (SPOs).",
|
||||
"optional": True,
|
||||
"type": "boolean",
|
||||
"value": False,
|
||||
"show": True,
|
||||
"paramName": "is_spo",
|
||||
},
|
||||
],
|
||||
"gridData": {"w": 40, "h": 20},
|
||||
}
|
||||
},
|
||||
)
|
||||
async def ipo_calendar(
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
) -> list[NasdaqCalendarIpoFetcher.data_type]:
|
||||
"""Get the IPO calendar."""
|
||||
fetcher = NasdaqCalendarIpoFetcher()
|
||||
|
||||
params = {
|
||||
"start_date": start_date,
|
||||
"end_date": end_date,
|
||||
}
|
||||
|
||||
return await fetcher.fetch_data(params, {}) # type: ignore
|
||||
|
||||
@app.get(
|
||||
"/economic_calendar",
|
||||
openapi_extra={
|
||||
"widget_config": {
|
||||
"name": "Economic Calendar",
|
||||
"description": "Upcoming, and historical, macroeconomic events.",
|
||||
"category": "Economy",
|
||||
"subCategory": "Calendar",
|
||||
"type": "table",
|
||||
"searchCategory": "Equity",
|
||||
"widgetId": "nasdaq_economic_calendar",
|
||||
"refetchInterval": False,
|
||||
"params": [
|
||||
{
|
||||
"paramName": "country",
|
||||
"options": [
|
||||
{"label": "United States", "value": "united_states"},
|
||||
{"label": "China", "value": "china"},
|
||||
{"label": "Hong Kong", "value": "hong_kong"},
|
||||
{"label": "Japan", "value": "japan"},
|
||||
{"label": "Singapore", "value": "signapore"},
|
||||
{"label": "South Korea", "value": "south_korea"},
|
||||
{"label": "India", "value": "india"},
|
||||
{"label": "Russia", "value": "russia"},
|
||||
{"label": "Euro Zone", "value": "euro_zone"},
|
||||
{"label": "Germany", "value": "germany"},
|
||||
{"label": "United Kingdom", "value": "united_kingdom"},
|
||||
{"label": "France", "value": "france"},
|
||||
{"label": "Spain", "value": "spain"},
|
||||
{"label": "Italy", "value": "italy"},
|
||||
{"label": "Switzerland", "value": "switzerland"},
|
||||
{"label": "Canada", "value": "canada"},
|
||||
{"label": "Australia", "value": "australia"},
|
||||
{"label": "New Zealand", "value": "new_zealand"},
|
||||
{"label": "South Africa", "value": "south_africa"},
|
||||
{"label": "Brazil", "value": "brazil"},
|
||||
],
|
||||
},
|
||||
],
|
||||
"gridData": {"w": 40, "h": 20},
|
||||
"data": {
|
||||
"table": {
|
||||
"showAll": False,
|
||||
"columnsDefs": [
|
||||
{
|
||||
"field": "date",
|
||||
"pinned": "left",
|
||||
"formatterFn": None,
|
||||
"headerName": "Date",
|
||||
"headerTooltip": "The date of the data.",
|
||||
"cellDataType": "date",
|
||||
},
|
||||
{
|
||||
"field": "country",
|
||||
"formatterFn": None,
|
||||
"headerName": "Country",
|
||||
"headerTooltip": "Country of event.",
|
||||
"cellDataType": "text",
|
||||
},
|
||||
{
|
||||
"field": "event",
|
||||
"formatterFn": None,
|
||||
"renderFn": "hoverCard",
|
||||
"renderFnParams": {
|
||||
"hoverCard": {
|
||||
"cellField": "value",
|
||||
"markdown": "{description}",
|
||||
}
|
||||
},
|
||||
"headerName": "Event",
|
||||
"headerTooltip": "Event name.",
|
||||
"cellDataType": "text",
|
||||
},
|
||||
{
|
||||
"field": "consensus",
|
||||
"formatterFn": None,
|
||||
"headerName": "Consensus",
|
||||
"headerTooltip": "Average forecast among a representative group of economists.",
|
||||
"cellDataType": "number",
|
||||
},
|
||||
{
|
||||
"field": "actual",
|
||||
"formatterFn": None,
|
||||
"headerName": "Actual",
|
||||
"headerTooltip": "Latest released value.",
|
||||
"cellDataType": "number",
|
||||
},
|
||||
{
|
||||
"field": "previous",
|
||||
"formatterFn": None,
|
||||
"headerName": "Previous",
|
||||
"headerTooltip": (
|
||||
"Value for the previous period after"
|
||||
+ " the revision (if revision is applicable)."
|
||||
),
|
||||
"cellDataType": "number",
|
||||
},
|
||||
{
|
||||
"field": "revised",
|
||||
"formatterFn": None,
|
||||
"headerName": "Revised",
|
||||
"headerTooltip": "Revised previous value, if applicable.",
|
||||
"cellDataType": "number",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
async def economic_calendar(
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
country: Optional[str] = None,
|
||||
):
|
||||
"""Get the dividend calendar."""
|
||||
fetcher = NasdaqEconomicCalendarFetcher()
|
||||
|
||||
params = {
|
||||
"start_date": start_date,
|
||||
"end_date": end_date,
|
||||
}
|
||||
if country:
|
||||
params["country"] = country
|
||||
|
||||
data: list[NasdaqEconomicCalendarFetcher.data_type] = await fetcher.fetch_data(params, {}) # type: ignore
|
||||
output: list = []
|
||||
|
||||
for row in data:
|
||||
markdown = (
|
||||
f"### **{row.event}**\n\n{row.description}"
|
||||
if row.description
|
||||
else row.event
|
||||
)
|
||||
output.append(
|
||||
{
|
||||
"date": row.date.strftime("%Y-%m-%d"),
|
||||
"country": row.country,
|
||||
"event": {
|
||||
"value": row.event,
|
||||
"description": markdown,
|
||||
},
|
||||
"consensus": row.consensus,
|
||||
"actual": row.actual,
|
||||
"previous": row.previous,
|
||||
"revised": row.revised,
|
||||
}
|
||||
)
|
||||
|
||||
return output
|
||||
|
||||
@app.get(
|
||||
"/apps.json",
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def get_apps() -> dict:
|
||||
return {
|
||||
"name": "Company Filings & Market Calendars",
|
||||
"img": "https://logosandtypes.com/wp-content/uploads/2020/07/nasdaq.svg",
|
||||
"img_dark": "",
|
||||
"img_light": "",
|
||||
"description": (
|
||||
"View company filings and market calendars, downloaded from the public Nasdaq website."
|
||||
" This app is not affiliated with, or authoriazed by, Nasdaq."
|
||||
),
|
||||
"allowCustomization": True,
|
||||
"tabs": {
|
||||
"earnings": {
|
||||
"id": "earnings",
|
||||
"name": "Earnings Calendar & Filings",
|
||||
"layout": [
|
||||
{
|
||||
"i": "nasdaq_earnings_calendar",
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"w": 40,
|
||||
"h": 10,
|
||||
"state": {
|
||||
"chartView": {"enabled": False, "chartType": "line"},
|
||||
"columnState": {
|
||||
"default": {
|
||||
"sort": {
|
||||
"sortModel": [
|
||||
{"colId": "market_cap", "sort": "desc"}
|
||||
]
|
||||
},
|
||||
"columnPinning": {
|
||||
"leftColIds": [
|
||||
"symbol",
|
||||
"name",
|
||||
"period_ending",
|
||||
],
|
||||
"rightColIds": [],
|
||||
},
|
||||
"columnOrder": {
|
||||
"orderedColIds": [
|
||||
"report_date",
|
||||
"reporting_time",
|
||||
"symbol",
|
||||
"name",
|
||||
"market_cap",
|
||||
"eps_previous",
|
||||
"eps_consensus",
|
||||
"num_estimates",
|
||||
"eps_actual",
|
||||
"surprise_percent",
|
||||
"period_ending",
|
||||
"previous_report_date",
|
||||
]
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"i": "nasdaq_company_filings",
|
||||
"x": 0,
|
||||
"y": 12,
|
||||
"w": 40,
|
||||
"h": 30,
|
||||
},
|
||||
],
|
||||
},
|
||||
"dividend-calendar": {
|
||||
"id": "dividend-calendar",
|
||||
"name": "Dividend Calendar",
|
||||
"layout": [
|
||||
{
|
||||
"i": "nasdaq_dividends_calendar",
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"w": 40,
|
||||
"h": 20,
|
||||
"state": {
|
||||
"chartView": {"enabled": False, "chartType": "line"},
|
||||
"columnState": {
|
||||
"default": {
|
||||
"sort": {
|
||||
"sortModel": [
|
||||
{
|
||||
"colId": "ex_dividend_date",
|
||||
"sort": "asc",
|
||||
},
|
||||
{"colId": "amount", "sort": "desc"},
|
||||
{
|
||||
"colId": "annualized_amount",
|
||||
"sort": "desc",
|
||||
},
|
||||
]
|
||||
},
|
||||
"columnPinning": {
|
||||
"leftColIds": ["symbol", "name"],
|
||||
"rightColIds": [],
|
||||
},
|
||||
"columnOrder": {
|
||||
"orderedColIds": [
|
||||
"ex_dividend_date",
|
||||
"symbol",
|
||||
"amount",
|
||||
"name",
|
||||
"record_date",
|
||||
"payment_date",
|
||||
"declaration_date",
|
||||
"annualized_amount",
|
||||
]
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
"ipo-calendar": {
|
||||
"id": "ipo-calendar",
|
||||
"name": "IPO Calendar",
|
||||
"layout": [
|
||||
{
|
||||
"i": "nasdaq_ipo_calendar",
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"w": 40,
|
||||
"h": 21,
|
||||
"state": {
|
||||
"chartView": {"enabled": False, "chartType": "line"},
|
||||
"columnState": {
|
||||
"default": {
|
||||
"columnPinning": {
|
||||
"leftColIds": [
|
||||
"ipo_date",
|
||||
"symbol",
|
||||
"name",
|
||||
],
|
||||
"rightColIds": [],
|
||||
},
|
||||
"columnOrder": {
|
||||
"orderedColIds": [
|
||||
"ipo_date",
|
||||
"symbol",
|
||||
"name",
|
||||
"offer_amount",
|
||||
"share_count",
|
||||
"share_price",
|
||||
"deal_status",
|
||||
"exchange",
|
||||
"id",
|
||||
]
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
"economic-calendar": {
|
||||
"id": "economic-calendar",
|
||||
"name": "Economic Calendar",
|
||||
"layout": [
|
||||
{
|
||||
"i": "nasdaq_economic_calendar",
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"w": 40,
|
||||
"h": 20,
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
"groups": [],
|
||||
}
|
||||
|
||||
return app
|
||||
69
openbb_platform/providers/nasdaq/poetry.lock
generated
vendored
69
openbb_platform/providers/nasdaq/poetry.lock
generated
vendored
@@ -166,6 +166,21 @@ doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)",
|
||||
test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""]
|
||||
trio = ["trio (>=0.26.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "async-lru"
|
||||
version = "2.0.5"
|
||||
description = "Simple LRU cache for asyncio"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943"},
|
||||
{file = "async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing_extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "async-timeout"
|
||||
version = "5.0.1"
|
||||
@@ -370,6 +385,30 @@ files = [
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deepdiff"
|
||||
version = "8.5.0"
|
||||
description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "deepdiff-8.5.0-py3-none-any.whl", hash = "sha256:d4599db637f36a1c285f5fdfc2cd8d38bde8d8be8636b65ab5e425b67c54df26"},
|
||||
{file = "deepdiff-8.5.0.tar.gz", hash = "sha256:a4dd3529fa8d4cd5b9cbb6e3ea9c95997eaa919ba37dac3966c1b8f872dc1cd1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
orderly-set = ">=5.4.1,<6"
|
||||
|
||||
[package.extras]
|
||||
cli = ["click (>=8.1.0,<8.2.0)", "pyyaml (>=6.0.0,<6.1.0)"]
|
||||
coverage = ["coverage (>=7.6.0,<7.7.0)"]
|
||||
dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)", "jsonpickle (>=4.0.0,<4.1.0)", "nox (==2025.5.1)", "numpy (>=2.0,<3.0) ; python_version < \"3.10\"", "numpy (>=2.2.0,<2.3.0) ; python_version >= \"3.10\"", "orjson (>=3.10.0,<3.11.0)", "pandas (>=2.2.0,<2.3.0)", "polars (>=1.21.0,<1.22.0)", "python-dateutil (>=2.9.0,<2.10.0)", "tomli (>=2.2.0,<2.3.0)", "tomli-w (>=1.2.0,<1.3.0)"]
|
||||
docs = ["Sphinx (>=6.2.0,<6.3.0)", "sphinx-sitemap (>=2.6.0,<2.7.0)", "sphinxemoji (>=0.3.0,<0.4.0)"]
|
||||
optimize = ["orjson"]
|
||||
static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)", "pydantic (>=2.10.0,<2.11.0)"]
|
||||
test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "distro"
|
||||
version = "1.9.0"
|
||||
@@ -934,6 +973,34 @@ uuid7 = ">=0.1.0,<0.2.0"
|
||||
uvicorn = ">=0.34.2,<0.35.0"
|
||||
websockets = ">=15.0,<16.0"
|
||||
|
||||
[[package]]
|
||||
name = "openbb-platform-api"
|
||||
version = "1.1.10"
|
||||
description = "OpenBB Platform API: Launch script and widgets builder for the OpenBB Platform API and Workspace Backend Connector."
|
||||
optional = false
|
||||
python-versions = "<3.13,>=3.9.21"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "openbb_platform_api-1.1.10-py3-none-any.whl", hash = "sha256:18da196dac5b2be9e7fc8632eaa495826ae1bcfd3365d319c5c8550219919e2c"},
|
||||
{file = "openbb_platform_api-1.1.10.tar.gz", hash = "sha256:8a0cb7dd9f183587a262965cfaa7b7b4098e9fa112614ebdcb5eb40d35e70c84"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
deepdiff = "*"
|
||||
openbb-core = ">=1.4.7,<2.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "orderly-set"
|
||||
version = "5.4.1"
|
||||
description = "Orderly set"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "orderly_set-5.4.1-py3-none-any.whl", hash = "sha256:b5e21d21680bd9ef456885db800c5cb4f76a03879880c0175e1b077fb166fd83"},
|
||||
{file = "orderly_set-5.4.1.tar.gz", hash = "sha256:a1fb5a4fdc5e234e9e8d8e5c1bbdbc4540f4dfe50d12bf17c8bc5dbf1c9c878d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pandas"
|
||||
version = "2.2.3"
|
||||
@@ -1788,4 +1855,4 @@ type = ["pytest-mypy"]
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.9.21,<3.13"
|
||||
content-hash = "e87dd4d308fbc419916e8f08f30702b1ea7005caf3424a3220cafac9139c31b3"
|
||||
content-hash = "8d6ad6be9cd05a1d7c1ec900e35fafc7551844a836386799eafbb4a2641e185b"
|
||||
|
||||
@@ -9,7 +9,9 @@ packages = [{ include = "openbb_nasdaq" }]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9.21,<3.13"
|
||||
openbb-core = "^1.4.6"
|
||||
openbb-core = "^1.4.7"
|
||||
openbb-platform-api = "^1.1.10"
|
||||
async-lru = "^2.0.5"
|
||||
random-user-agent = "^1.0.1"
|
||||
nasdaq-data-link = "^1.0.4"
|
||||
|
||||
|
||||
188
openbb_platform/providers/nasdaq/tests/record/expected_apps.json
vendored
Normal file
188
openbb_platform/providers/nasdaq/tests/record/expected_apps.json
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
{
|
||||
"name": "Company Filings & Market Calendars",
|
||||
"img": "https://logosandtypes.com/wp-content/uploads/2020/07/nasdaq.svg",
|
||||
"img_dark": "",
|
||||
"img_light": "",
|
||||
"description": "View company filings and market calendars, downloaded from the public Nasdaq website. This app is not affiliated with, or authoriazed by, Nasdaq.",
|
||||
"allowCustomization": true,
|
||||
"tabs": {
|
||||
"earnings": {
|
||||
"id": "earnings",
|
||||
"name": "Earnings Calendar & Filings",
|
||||
"layout": [
|
||||
{
|
||||
"i": "nasdaq_earnings_calendar",
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"w": 40,
|
||||
"h": 10,
|
||||
"state": {
|
||||
"chartView": {
|
||||
"enabled": false,
|
||||
"chartType": "line"
|
||||
},
|
||||
"columnState": {
|
||||
"default": {
|
||||
"sort": {
|
||||
"sortModel": [
|
||||
{
|
||||
"colId": "market_cap",
|
||||
"sort": "desc"
|
||||
}
|
||||
]
|
||||
},
|
||||
"columnPinning": {
|
||||
"leftColIds": [
|
||||
"symbol",
|
||||
"name",
|
||||
"period_ending"
|
||||
],
|
||||
"rightColIds": []
|
||||
},
|
||||
"columnOrder": {
|
||||
"orderedColIds": [
|
||||
"report_date",
|
||||
"reporting_time",
|
||||
"symbol",
|
||||
"name",
|
||||
"market_cap",
|
||||
"eps_previous",
|
||||
"eps_consensus",
|
||||
"num_estimates",
|
||||
"eps_actual",
|
||||
"surprise_percent",
|
||||
"period_ending",
|
||||
"previous_report_date"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"i": "nasdaq_company_filings",
|
||||
"x": 0,
|
||||
"y": 12,
|
||||
"w": 40,
|
||||
"h": 30
|
||||
}
|
||||
]
|
||||
},
|
||||
"dividend-calendar": {
|
||||
"id": "dividend-calendar",
|
||||
"name": "Dividend Calendar",
|
||||
"layout": [
|
||||
{
|
||||
"i": "nasdaq_dividends_calendar",
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"w": 40,
|
||||
"h": 20,
|
||||
"state": {
|
||||
"chartView": {
|
||||
"enabled": false,
|
||||
"chartType": "line"
|
||||
},
|
||||
"columnState": {
|
||||
"default": {
|
||||
"sort": {
|
||||
"sortModel": [
|
||||
{
|
||||
"colId": "ex_dividend_date",
|
||||
"sort": "asc"
|
||||
},
|
||||
{
|
||||
"colId": "amount",
|
||||
"sort": "desc"
|
||||
},
|
||||
{
|
||||
"colId": "annualized_amount",
|
||||
"sort": "desc"
|
||||
}
|
||||
]
|
||||
},
|
||||
"columnPinning": {
|
||||
"leftColIds": [
|
||||
"symbol",
|
||||
"name"
|
||||
],
|
||||
"rightColIds": []
|
||||
},
|
||||
"columnOrder": {
|
||||
"orderedColIds": [
|
||||
"ex_dividend_date",
|
||||
"symbol",
|
||||
"amount",
|
||||
"name",
|
||||
"record_date",
|
||||
"payment_date",
|
||||
"declaration_date",
|
||||
"annualized_amount"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ipo-calendar": {
|
||||
"id": "ipo-calendar",
|
||||
"name": "IPO Calendar",
|
||||
"layout": [
|
||||
{
|
||||
"i": "nasdaq_ipo_calendar",
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"w": 40,
|
||||
"h": 21,
|
||||
"state": {
|
||||
"chartView": {
|
||||
"enabled": false,
|
||||
"chartType": "line"
|
||||
},
|
||||
"columnState": {
|
||||
"default": {
|
||||
"columnPinning": {
|
||||
"leftColIds": [
|
||||
"ipo_date",
|
||||
"symbol",
|
||||
"name"
|
||||
],
|
||||
"rightColIds": []
|
||||
},
|
||||
"columnOrder": {
|
||||
"orderedColIds": [
|
||||
"ipo_date",
|
||||
"symbol",
|
||||
"name",
|
||||
"offer_amount",
|
||||
"share_count",
|
||||
"share_price",
|
||||
"deal_status",
|
||||
"exchange",
|
||||
"id"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"economic-calendar": {
|
||||
"id": "economic-calendar",
|
||||
"name": "Economic Calendar",
|
||||
"layout": [
|
||||
{
|
||||
"i": "nasdaq_economic_calendar",
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"w": 40,
|
||||
"h": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"groups": []
|
||||
}
|
||||
807
openbb_platform/providers/nasdaq/tests/record/expected_widgets.json
vendored
Normal file
807
openbb_platform/providers/nasdaq/tests/record/expected_widgets.json
vendored
Normal file
@@ -0,0 +1,807 @@
|
||||
{
|
||||
"nasdaq_company_filings": {
|
||||
"name": "SEC Filings",
|
||||
"description": "View SEC filings by company.",
|
||||
"category": "Open Document",
|
||||
"type": "multi_file_viewer",
|
||||
"searchCategory": "Open Document",
|
||||
"widgetId": "nasdaq_company_filings",
|
||||
"params": [
|
||||
{
|
||||
"label": "Document URL",
|
||||
"description": "Select the document to open.",
|
||||
"optional": false,
|
||||
"type": "endpoint",
|
||||
"value": null,
|
||||
"show": false,
|
||||
"paramName": "document_url",
|
||||
"optionsEndpoint": "/get_symbol_choices",
|
||||
"optionsParams": {
|
||||
"symbol": "$symbol",
|
||||
"year": "$year",
|
||||
"form_group": "$form_group"
|
||||
},
|
||||
"roles": [
|
||||
"fileSelector"
|
||||
],
|
||||
"multiSelect": true
|
||||
},
|
||||
{
|
||||
"paramName": "symbol",
|
||||
"label": "Symbol",
|
||||
"description": "Ticker symbol for the company. Foreign (dual-listed) companies may not be required to file with the SEC.",
|
||||
"type": "endpoint",
|
||||
"value": "AAPL",
|
||||
"optionsEndpoint": "/get_symbol_choices",
|
||||
"style": {
|
||||
"popupWidth": 850
|
||||
}
|
||||
},
|
||||
{
|
||||
"paramName": "year",
|
||||
"label": "Calendar Year",
|
||||
"description": "Calendar year for the filings.",
|
||||
"value": 2025,
|
||||
"type": "number",
|
||||
"options": [
|
||||
{
|
||||
"label": "2025",
|
||||
"value": 2025
|
||||
},
|
||||
{
|
||||
"label": "2024",
|
||||
"value": 2024
|
||||
},
|
||||
{
|
||||
"label": "2023",
|
||||
"value": 2023
|
||||
},
|
||||
{
|
||||
"label": "2022",
|
||||
"value": 2022
|
||||
},
|
||||
{
|
||||
"label": "2021",
|
||||
"value": 2021
|
||||
},
|
||||
{
|
||||
"label": "2020",
|
||||
"value": 2020
|
||||
},
|
||||
{
|
||||
"label": "2019",
|
||||
"value": 2019
|
||||
},
|
||||
{
|
||||
"label": "2018",
|
||||
"value": 2018
|
||||
},
|
||||
{
|
||||
"label": "2017",
|
||||
"value": 2017
|
||||
},
|
||||
{
|
||||
"label": "2016",
|
||||
"value": 2016
|
||||
},
|
||||
{
|
||||
"label": "2015",
|
||||
"value": 2015
|
||||
},
|
||||
{
|
||||
"label": "2014",
|
||||
"value": 2014
|
||||
},
|
||||
{
|
||||
"label": "2013",
|
||||
"value": 2013
|
||||
},
|
||||
{
|
||||
"label": "2012",
|
||||
"value": 2012
|
||||
},
|
||||
{
|
||||
"label": "2011",
|
||||
"value": 2011
|
||||
},
|
||||
{
|
||||
"label": "2010",
|
||||
"value": 2010
|
||||
},
|
||||
{
|
||||
"label": "2009",
|
||||
"value": 2009
|
||||
},
|
||||
{
|
||||
"label": "2008",
|
||||
"value": 2008
|
||||
},
|
||||
{
|
||||
"label": "2007",
|
||||
"value": 2007
|
||||
},
|
||||
{
|
||||
"label": "2006",
|
||||
"value": 2006
|
||||
},
|
||||
{
|
||||
"label": "2005",
|
||||
"value": 2005
|
||||
},
|
||||
{
|
||||
"label": "2004",
|
||||
"value": 2004
|
||||
},
|
||||
{
|
||||
"label": "2003",
|
||||
"value": 2003
|
||||
},
|
||||
{
|
||||
"label": "2002",
|
||||
"value": 2002
|
||||
},
|
||||
{
|
||||
"label": "2001",
|
||||
"value": 2001
|
||||
},
|
||||
{
|
||||
"label": "2000",
|
||||
"value": 2000
|
||||
},
|
||||
{
|
||||
"label": "1999",
|
||||
"value": 1999
|
||||
},
|
||||
{
|
||||
"label": "1998",
|
||||
"value": 1998
|
||||
},
|
||||
{
|
||||
"label": "1997",
|
||||
"value": 1997
|
||||
},
|
||||
{
|
||||
"label": "1996",
|
||||
"value": 1996
|
||||
},
|
||||
{
|
||||
"label": "1995",
|
||||
"value": 1995
|
||||
},
|
||||
{
|
||||
"label": "1994",
|
||||
"value": 1994
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"paramName": "form_group",
|
||||
"label": "Form Group",
|
||||
"description": "Form group for the filings.",
|
||||
"value": "8k",
|
||||
"type": "text",
|
||||
"options": [
|
||||
{
|
||||
"label": "Annual",
|
||||
"value": "annual"
|
||||
},
|
||||
{
|
||||
"label": "Quarterly",
|
||||
"value": "quarterly"
|
||||
},
|
||||
{
|
||||
"label": "Proxy",
|
||||
"value": "proxy"
|
||||
},
|
||||
{
|
||||
"label": "Insider",
|
||||
"value": "insider"
|
||||
},
|
||||
{
|
||||
"label": "8-K",
|
||||
"value": "8k"
|
||||
},
|
||||
{
|
||||
"label": "Registration",
|
||||
"value": "registration"
|
||||
},
|
||||
{
|
||||
"label": "Comment",
|
||||
"value": "comment"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"endpoint": "open_document",
|
||||
"runButton": false,
|
||||
"gridData": {
|
||||
"w": 40,
|
||||
"h": 30
|
||||
},
|
||||
"data": {
|
||||
"dataKey": "",
|
||||
"table": {
|
||||
"showAll": true
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"Custom"
|
||||
],
|
||||
"refetchInterval": false
|
||||
},
|
||||
"nasdaq_earnings_calendar": {
|
||||
"name": "Earnings Calendar",
|
||||
"description": "Upcoming, and historical, company earnings releases (US Markets).",
|
||||
"category": "Equity",
|
||||
"type": "table",
|
||||
"searchCategory": "Equity",
|
||||
"widgetId": "nasdaq_earnings_calendar",
|
||||
"params": [
|
||||
{
|
||||
"label": "Start Date",
|
||||
"description": "Start date of the data.",
|
||||
"optional": true,
|
||||
"type": "date",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "start_date"
|
||||
},
|
||||
{
|
||||
"label": "End Date",
|
||||
"description": "End date of the data.",
|
||||
"optional": true,
|
||||
"type": "date",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "end_date"
|
||||
}
|
||||
],
|
||||
"endpoint": "earnings_calendar",
|
||||
"runButton": false,
|
||||
"gridData": {
|
||||
"w": 40,
|
||||
"h": 20
|
||||
},
|
||||
"data": {
|
||||
"dataKey": "",
|
||||
"table": {
|
||||
"showAll": true,
|
||||
"columnsDefs": [
|
||||
{
|
||||
"field": "report_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Report Date",
|
||||
"headerTooltip": "The date of the earnings report.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "symbol",
|
||||
"pinned": "left",
|
||||
"formatterFn": null,
|
||||
"headerName": "Symbol",
|
||||
"headerTooltip": "Symbol representing the entity requested in the data.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "name",
|
||||
"pinned": "left",
|
||||
"formatterFn": null,
|
||||
"headerName": "Name",
|
||||
"headerTooltip": "Name of the entity.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "eps_previous",
|
||||
"formatterFn": null,
|
||||
"headerName": "EPS Previous",
|
||||
"headerTooltip": "The earnings-per-share from the same previously reported period.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "eps_consensus",
|
||||
"formatterFn": null,
|
||||
"headerName": "EPS Consensus",
|
||||
"headerTooltip": "The analyst conesus earnings-per-share estimate.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "eps_actual",
|
||||
"formatterFn": null,
|
||||
"headerName": "EPS Actual",
|
||||
"headerTooltip": "The actual earnings per share (USD) announced.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "surprise_percent",
|
||||
"formatterFn": "normalizedPercent",
|
||||
"headerName": "Surprise Percent",
|
||||
"headerTooltip": "The earnings surprise as normalized percentage points.",
|
||||
"cellDataType": "number",
|
||||
"renderFn": "greenRed"
|
||||
},
|
||||
{
|
||||
"field": "num_estimates",
|
||||
"formatterFn": null,
|
||||
"headerName": "Num Estimates",
|
||||
"headerTooltip": "The number of analysts providing estimates for the consensus.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "period_ending",
|
||||
"pinned": "left",
|
||||
"formatterFn": null,
|
||||
"headerName": "Period Ending",
|
||||
"headerTooltip": "The fiscal period end date.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "previous_report_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Previous Report Date",
|
||||
"headerTooltip": "The previous report date for the same period last year.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "reporting_time",
|
||||
"formatterFn": null,
|
||||
"headerName": "Reporting Time",
|
||||
"headerTooltip": "The reporting time - e.g. after market close.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "market_cap",
|
||||
"formatterFn": null,
|
||||
"headerName": "Market Cap",
|
||||
"headerTooltip": "The market cap (USD) of the reporting entity.",
|
||||
"cellDataType": "number"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"Custom"
|
||||
],
|
||||
"subCategory": "Calendar",
|
||||
"refetchInterval": false
|
||||
},
|
||||
"nasdaq_dividends_calendar": {
|
||||
"name": "Dividend Calendar",
|
||||
"description": "Upcoming, and historical, dividend payments (US Markets).",
|
||||
"category": "Equity",
|
||||
"type": "table",
|
||||
"searchCategory": "Equity",
|
||||
"widgetId": "nasdaq_dividends_calendar",
|
||||
"params": [
|
||||
{
|
||||
"label": "Start Date",
|
||||
"description": "Start date of the data.",
|
||||
"optional": true,
|
||||
"type": "date",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "start_date"
|
||||
},
|
||||
{
|
||||
"label": "End Date",
|
||||
"description": "End date of the data.",
|
||||
"optional": true,
|
||||
"type": "date",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "end_date"
|
||||
}
|
||||
],
|
||||
"endpoint": "dividend_calendar",
|
||||
"runButton": false,
|
||||
"gridData": {
|
||||
"w": 40,
|
||||
"h": 20
|
||||
},
|
||||
"data": {
|
||||
"dataKey": "",
|
||||
"table": {
|
||||
"showAll": true,
|
||||
"columnsDefs": [
|
||||
{
|
||||
"field": "ex_dividend_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Ex Dividend Date",
|
||||
"headerTooltip": "The ex-dividend date - the date on which the stock begins trading without rights to the dividend.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "symbol",
|
||||
"pinned": "left",
|
||||
"formatterFn": null,
|
||||
"headerName": "Symbol",
|
||||
"headerTooltip": "Symbol representing the entity requested in the data.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "amount",
|
||||
"formatterFn": null,
|
||||
"headerName": "Amount",
|
||||
"headerTooltip": "The dividend amount per share.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "name",
|
||||
"pinned": "left",
|
||||
"formatterFn": null,
|
||||
"headerName": "Name",
|
||||
"headerTooltip": "Name of the entity.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "record_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Record Date",
|
||||
"headerTooltip": "The record date of ownership for eligibility.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "payment_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Payment Date",
|
||||
"headerTooltip": "The payment date of the dividend.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "declaration_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Declaration Date",
|
||||
"headerTooltip": "Declaration date of the dividend.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "annualized_amount",
|
||||
"formatterFn": null,
|
||||
"headerName": "Annualized Amount",
|
||||
"headerTooltip": "The indicated annualized dividend amount.",
|
||||
"cellDataType": "number"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"Custom"
|
||||
],
|
||||
"subCategory": "Calendar",
|
||||
"refetchInterval": false
|
||||
},
|
||||
"nasdaq_ipo_calendar": {
|
||||
"name": "IPO Calendar",
|
||||
"description": "IPO announcements and calendar.",
|
||||
"category": "Equity",
|
||||
"type": "table",
|
||||
"searchCategory": "Equity",
|
||||
"widgetId": "nasdaq_ipo_calendar",
|
||||
"params": [
|
||||
{
|
||||
"label": "Start Date",
|
||||
"description": "Start date of the data, in YYYY-MM-DD format.",
|
||||
"optional": true,
|
||||
"type": "date",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "start_date"
|
||||
},
|
||||
{
|
||||
"label": "End Date",
|
||||
"description": "End date of the data, in YYYY-MM-DD format.",
|
||||
"optional": true,
|
||||
"type": "date",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "end_date"
|
||||
},
|
||||
{
|
||||
"label": "Status",
|
||||
"description": "Status of the IPO. [upcoming, priced, or withdrawn]",
|
||||
"optional": true,
|
||||
"type": "text",
|
||||
"show": true,
|
||||
"options": [
|
||||
{
|
||||
"label": "upcoming",
|
||||
"value": "upcoming"
|
||||
},
|
||||
{
|
||||
"label": "priced",
|
||||
"value": "priced"
|
||||
},
|
||||
{
|
||||
"label": "filed",
|
||||
"value": "filed"
|
||||
},
|
||||
{
|
||||
"label": "withdrawn",
|
||||
"value": "withdrawn"
|
||||
}
|
||||
],
|
||||
"paramName": "status"
|
||||
},
|
||||
{
|
||||
"label": "Is SPO",
|
||||
"description": "If True, returns data for secondary public offerings (SPOs).",
|
||||
"optional": true,
|
||||
"type": "boolean",
|
||||
"value": false,
|
||||
"show": true,
|
||||
"paramName": "is_spo"
|
||||
}
|
||||
],
|
||||
"endpoint": "ipo_calendar",
|
||||
"runButton": false,
|
||||
"gridData": {
|
||||
"w": 40,
|
||||
"h": 20
|
||||
},
|
||||
"data": {
|
||||
"dataKey": "",
|
||||
"table": {
|
||||
"showAll": true,
|
||||
"columnsDefs": [
|
||||
{
|
||||
"field": "symbol",
|
||||
"pinned": "left",
|
||||
"formatterFn": null,
|
||||
"headerName": "Symbol",
|
||||
"headerTooltip": "Symbol representing the entity requested in the data.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "ipo_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "IPO Date",
|
||||
"headerTooltip": "The date of the IPO, when the stock first trades on a major exchange.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "name",
|
||||
"pinned": "left",
|
||||
"formatterFn": null,
|
||||
"headerName": "Name",
|
||||
"headerTooltip": "The name of the company.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "offer_amount",
|
||||
"formatterFn": null,
|
||||
"headerName": "Offer Amount",
|
||||
"headerTooltip": "The dollar value of the shares offered.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "share_count",
|
||||
"formatterFn": null,
|
||||
"headerName": "Share Count",
|
||||
"headerTooltip": "The number of shares offered.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "expected_price_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Expected Price Date",
|
||||
"headerTooltip": "The date the pricing is expected.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "filed_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Filed Date",
|
||||
"headerTooltip": "The date the IPO was filed.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "withdraw_date",
|
||||
"formatterFn": null,
|
||||
"headerName": "Withdraw Date",
|
||||
"headerTooltip": "The date the IPO was withdrawn.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "deal_status",
|
||||
"formatterFn": null,
|
||||
"headerName": "Deal Status",
|
||||
"headerTooltip": "The status of the deal.",
|
||||
"cellDataType": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"Custom"
|
||||
],
|
||||
"subCategory": "Calendar",
|
||||
"refetchInterval": false
|
||||
},
|
||||
"nasdaq_economic_calendar": {
|
||||
"name": "Economic Calendar",
|
||||
"description": "Upcoming, and historical, macroeconomic events.",
|
||||
"category": "Economy",
|
||||
"type": "table",
|
||||
"searchCategory": "Equity",
|
||||
"widgetId": "nasdaq_economic_calendar",
|
||||
"params": [
|
||||
{
|
||||
"label": "Start Date",
|
||||
"description": "Start Date",
|
||||
"optional": true,
|
||||
"type": "date",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "start_date"
|
||||
},
|
||||
{
|
||||
"label": "End Date",
|
||||
"description": "End Date",
|
||||
"optional": true,
|
||||
"type": "date",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "end_date"
|
||||
},
|
||||
{
|
||||
"label": "Country",
|
||||
"description": "Country",
|
||||
"optional": true,
|
||||
"type": "text",
|
||||
"value": null,
|
||||
"show": true,
|
||||
"paramName": "country",
|
||||
"options": [
|
||||
{
|
||||
"label": "United States",
|
||||
"value": "united_states"
|
||||
},
|
||||
{
|
||||
"label": "China",
|
||||
"value": "china"
|
||||
},
|
||||
{
|
||||
"label": "Hong Kong",
|
||||
"value": "hong_kong"
|
||||
},
|
||||
{
|
||||
"label": "Japan",
|
||||
"value": "japan"
|
||||
},
|
||||
{
|
||||
"label": "Singapore",
|
||||
"value": "signapore"
|
||||
},
|
||||
{
|
||||
"label": "South Korea",
|
||||
"value": "south_korea"
|
||||
},
|
||||
{
|
||||
"label": "India",
|
||||
"value": "india"
|
||||
},
|
||||
{
|
||||
"label": "Russia",
|
||||
"value": "russia"
|
||||
},
|
||||
{
|
||||
"label": "Euro Zone",
|
||||
"value": "euro_zone"
|
||||
},
|
||||
{
|
||||
"label": "Germany",
|
||||
"value": "germany"
|
||||
},
|
||||
{
|
||||
"label": "United Kingdom",
|
||||
"value": "united_kingdom"
|
||||
},
|
||||
{
|
||||
"label": "France",
|
||||
"value": "france"
|
||||
},
|
||||
{
|
||||
"label": "Spain",
|
||||
"value": "spain"
|
||||
},
|
||||
{
|
||||
"label": "Italy",
|
||||
"value": "italy"
|
||||
},
|
||||
{
|
||||
"label": "Switzerland",
|
||||
"value": "switzerland"
|
||||
},
|
||||
{
|
||||
"label": "Canada",
|
||||
"value": "canada"
|
||||
},
|
||||
{
|
||||
"label": "Australia",
|
||||
"value": "australia"
|
||||
},
|
||||
{
|
||||
"label": "New Zealand",
|
||||
"value": "new_zealand"
|
||||
},
|
||||
{
|
||||
"label": "South Africa",
|
||||
"value": "south_africa"
|
||||
},
|
||||
{
|
||||
"label": "Brazil",
|
||||
"value": "brazil"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"endpoint": "economic_calendar",
|
||||
"runButton": false,
|
||||
"gridData": {
|
||||
"w": 40,
|
||||
"h": 20
|
||||
},
|
||||
"data": {
|
||||
"dataKey": "",
|
||||
"table": {
|
||||
"showAll": false,
|
||||
"columnsDefs": [
|
||||
{
|
||||
"field": "date",
|
||||
"pinned": "left",
|
||||
"headerName": "Date",
|
||||
"headerTooltip": "The date of the data.",
|
||||
"cellDataType": "date"
|
||||
},
|
||||
{
|
||||
"field": "country",
|
||||
"headerName": "Country",
|
||||
"headerTooltip": "Country of event.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "event",
|
||||
"renderFn": "hoverCard",
|
||||
"renderFnParams": {
|
||||
"hoverCard": {
|
||||
"cellField": "value",
|
||||
"markdown": "{description}"
|
||||
}
|
||||
},
|
||||
"headerName": "Event",
|
||||
"headerTooltip": "Event name.",
|
||||
"cellDataType": "text"
|
||||
},
|
||||
{
|
||||
"field": "consensus",
|
||||
"headerName": "Consensus",
|
||||
"headerTooltip": "Average forecast among a representative group of economists.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "actual",
|
||||
"headerName": "Actual",
|
||||
"headerTooltip": "Latest released value.",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "previous",
|
||||
"headerName": "Previous",
|
||||
"headerTooltip": "Value for the previous period after the revision (if revision is applicable).",
|
||||
"cellDataType": "number"
|
||||
},
|
||||
{
|
||||
"field": "revised",
|
||||
"headerName": "Revised",
|
||||
"headerTooltip": "Revised previous value, if applicable.",
|
||||
"cellDataType": "number"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"Custom"
|
||||
],
|
||||
"subCategory": "Calendar",
|
||||
"refetchInterval": false
|
||||
}
|
||||
}
|
||||
63
openbb_platform/providers/nasdaq/tests/test_nasdaq_app.py
Normal file
63
openbb_platform/providers/nasdaq/tests/test_nasdaq_app.py
Normal file
@@ -0,0 +1,63 @@
|
||||
"""App tests for Nasdaq provider."""
|
||||
|
||||
# flake8: noqa:E501
|
||||
# pylint: disable=redefined-outer-name, unused-argument, line-too-long
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
from openbb_nasdaq.app import main
|
||||
from openbb_platform_api.utils.widgets import build_json
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def nasdaq_app():
|
||||
"""Fixture to serve FastAPI app instance."""
|
||||
app = main()
|
||||
yield app
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def expected_apps():
|
||||
"""Load expected apps.json data."""
|
||||
current_dir = Path(os.path.dirname(os.path.abspath(__file__)))
|
||||
with open(current_dir / "record" / "expected_apps.json", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def expected_widgets():
|
||||
"""Load expected widgets.json data."""
|
||||
current_dir = Path(os.path.dirname(os.path.abspath(__file__)))
|
||||
with open(current_dir / "record" / "expected_widgets.json", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def test_app_is_fastapi_instance(nasdaq_app):
|
||||
"""Test that the factory function returns a FastAPI instance."""
|
||||
assert isinstance(nasdaq_app, FastAPI)
|
||||
|
||||
|
||||
def test_app_has_routes(nasdaq_app):
|
||||
"""Test that the app has at least one route."""
|
||||
assert len(nasdaq_app.routes) > 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_apps_json(nasdaq_app, expected_apps):
|
||||
"""Test the /apps.json endpoint. This looks for changes and verifies the endpoint works."""
|
||||
route = [d for d in nasdaq_app.routes if d.path == "/apps.json"][0]
|
||||
response = await route.endpoint()
|
||||
assert isinstance(response, dict)
|
||||
assert response == expected_apps
|
||||
|
||||
|
||||
def test_widgets_json(nasdaq_app, expected_widgets):
|
||||
"""Test the /widgets.json endpoint. This looks for changes and verifies that the widgets are being generated correctly."""
|
||||
openapi_json: dict = nasdaq_app.openapi()
|
||||
assert isinstance(openapi_json, dict)
|
||||
response = build_json(openapi_json, [])
|
||||
assert isinstance(response, dict)
|
||||
assert response == expected_widgets
|
||||
Reference in New Issue
Block a user