Skip to content

Commit

Permalink
[Feature] Add Historical Market Cap (#6603)
Browse files Browse the repository at this point in the history
* add historical market cap

* add to equity view

* chart things

* raise not return

* pass all kwargs to line_chart

* tests..

* docstring

* static assets

* black

* chart integration test

---------

Co-authored-by: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com>
  • Loading branch information
deeleeramone and IgorWounds authored Aug 4, 2024
1 parent d5dfe84 commit 4500132
Show file tree
Hide file tree
Showing 14 changed files with 670 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Historical Market Cap Model."""

from datetime import date as dateType
from typing import Optional, Union

from pydantic import Field, field_validator

from openbb_core.provider.abstract.data import Data
from openbb_core.provider.abstract.query_params import QueryParams
from openbb_core.provider.utils.descriptions import (
DATA_DESCRIPTIONS,
QUERY_DESCRIPTIONS,
)


class HistoricalMarketCapQueryParams(QueryParams):
"""Historical Market Cap Query."""

symbol: str = Field(description=QUERY_DESCRIPTIONS.get("symbol", ""))
start_date: Optional[dateType] = Field(
default=None, description=QUERY_DESCRIPTIONS.get("start_date", "")
)
end_date: Optional[dateType] = Field(
default=None, description=QUERY_DESCRIPTIONS.get("end_date", "")
)

@field_validator("symbol", mode="before", check_fields=False)
@classmethod
def to_upper(cls, v: str) -> str:
"""Convert field to uppercase."""
return v.upper()


class HistoricalMarketCapData(Data):
"""Historical Market Cap Data."""

date: dateType = Field(description=DATA_DESCRIPTIONS.get("date", ""))
symbol: str = Field(description=DATA_DESCRIPTIONS.get("symbol", ""))
market_cap: Union[int, float] = Field(
description="Market capitalization of the security.",
json_schema_extra={"x-unit_measurement": "currency"},
)
25 changes: 25 additions & 0 deletions openbb_platform/extensions/equity/integration/test_equity_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2067,3 +2067,28 @@ def test_equity_compare_company_facts(params, headers):
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200


@parametrize(
"params",
[
(
{
"symbol": "AAPL,MSFT",
"start_date": None,
"end_date": None,
"provider": "fmp",
}
)
],
)
@pytest.mark.integration
def test_equity_historical_market_cap(params, headers):
"""Test the equity historical market cap endpoint."""
params = {p: v for p, v in params.items() if v}

query_str = get_querystring(params, [])
url = f"http://0.0.0.0:8000/api/v1/equity/historical_market_cap?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200
Original file line number Diff line number Diff line change
Expand Up @@ -1932,3 +1932,27 @@ def test_equity_compare_company_facts(params, obb):
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0


@parametrize(
"params",
[
(
{
"symbol": "AAPL,MSFT",
"start_date": None,
"end_date": None,
"provider": "fmp",
}
)
],
)
@pytest.mark.integration
def test_equity_historical_market_cap(params, obb):
"""Test the equity historical market cap endpoint."""
params = {p: v for p, v in params.items() if v}

result = obb.equity.historical_market_cap(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
14 changes: 14 additions & 0 deletions openbb_platform/extensions/equity/openbb_equity/equity_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,17 @@ async def market_snapshots(
) -> OBBject:
"""Get an updated equity market snapshot. This includes price data for thousands of stocks."""
return await OBBject.from_query(Query(**locals()))


@router.command(
model="HistoricalMarketCap",
examples=[APIEx(parameters={"provider": "fmp", "symbol": "AAPL"})],
)
async def historical_market_cap(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,
extra_params: ExtraParams,
) -> OBBject:
"""Get the historical market cap of a ticker symbol."""
return await OBBject.from_query(Query(**locals()))
53 changes: 53 additions & 0 deletions openbb_platform/extensions/equity/openbb_equity/equity_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,56 @@ def equity_price_performance( # noqa: PLR0912
from openbb_charting.charts.price_performance import price_performance

return price_performance(**kwargs)

@staticmethod
def equity_historical_market_cap( # noqa: PLR0912
**kwargs,
) -> Tuple["OpenBBFigure", Dict[str, Any]]:
"""Equity Historical Market Cap Chart."""
# pylint: disable=import-outside-toplevel
from openbb_charting.charts.generic_charts import line_chart
from openbb_core.app.utils import basemodel_to_df
from pandas import DataFrame

title = kwargs.pop("title", "Historical Market Cap")

data = DataFrame()

if "data" in kwargs and isinstance(kwargs["data"], DataFrame):
data = kwargs["data"]
elif "data" in kwargs and isinstance(kwargs["data"], list):
data = basemodel_to_df(kwargs["data"], index=kwargs.get("index", "date")) # type: ignore
else:
data = basemodel_to_df(
kwargs["obbject_item"],
index=kwargs.get("index", "date"), # type: ignore
)

if "date" in data.columns:
data = data.set_index("date")

if data.empty:
raise ValueError("Data is empty")

df = data.pivot(columns="symbol", values="market_cap")

scatter_kwargs = kwargs.pop("scatter_kwargs", {})

if "hovertemplate" not in scatter_kwargs:
scatter_kwargs["hovertemplate"] = "%{y}"

ytital = kwargs.pop("ytitle", "Market Cap ($)")
y = kwargs.pop("y", df.columns.tolist())

fig = line_chart(
data=df,
title=title,
y=y,
ytitle=ytital,
same_axis=True,
scatter_kwargs=scatter_kwargs,
**kwargs,
)
content = fig.show(external=True).to_plotly_json()

return fig, content
Original file line number Diff line number Diff line change
Expand Up @@ -600,9 +600,7 @@ def test_charting_technical_relative_rotation(params):
)
data_query_str = get_querystring(data_params, [])
data_url = f"http://0.0.0.0:8000/api/v1/equity/price/historical?{data_query_str}"
data_result = requests.get(data_url, headers=get_headers(), timeout=10).json()[
"results"
]
data_result = requests.get(data_url, headers=get_headers(), timeout=10).json()["results"]
body = json.dumps({"data": data_result})
query_str = get_querystring(params, ["data"])
url = f"http://0.0.0.0:8000/api/v1/technical/relative_rotation?{query_str}"
Expand Down Expand Up @@ -634,11 +632,7 @@ def test_charting_technical_relative_rotation(params):
def test_charting_equity_price_performance(params, headers):
"""Test chart equity price performance."""
params = {p: v for p, v in params.items() if v}
body = (
json.dumps(
{"extra_params": {"chart_params": {"limit": 4, "orientation": "h"}}}
),
)
body = (json.dumps({"extra_params": {"chart_params": {"limit": 4, "orientation": "h"}}}),)
query_str = get_querystring(params, [])
url = f"http://0.0.0.0:8000/api/v1/equity/price/performance?{query_str}"
result = requests.get(url, headers=headers, timeout=10, json=body)
Expand Down Expand Up @@ -702,11 +696,7 @@ def test_charting_etf_price_performance(params, headers):
def test_charting_etf_holdings(params, headers):
"""Test chart etf holdings."""
params = {p: v for p, v in params.items() if v}
body = (
json.dumps(
{"extra_params": {"chart_params": {"orientation": "v", "limit": 10}}}
),
)
body = (json.dumps({"extra_params": {"chart_params": {"orientation": "v", "limit": 10}}}),)
query_str = get_querystring(params, [])
url = f"http://0.0.0.0:8000/api/v1/etf/holdings?{query_str}"
result = requests.get(url, headers=headers, timeout=10, json=body)
Expand Down Expand Up @@ -831,3 +821,36 @@ def test_charting_derivatives_futures_curve(params, headers):
assert chart
assert not fig
assert list(chart.keys()) == ["content", "format"]


@parametrize(
"params",
[
(
{
"provider": "fmp",
"symbol": "AAPL",
"start_date": "2024-01-01",
"end_date": "2024-06-30",
"chart": True,
}
)
],
)
@pytest.mark.integration
def test_charting_equity_historical_market_cap(params, headers):
"""Test chart equity historical market cap."""
params = {p: v for p, v in params.items() if v}
body = (json.dumps({"extra_params": {"chart_params": {"title": "test chart"}}}),)
query_str = get_querystring(params, [])
url = f"http://0.0.0.0:8000/api/v1/equity/historical_market_cap?{query_str}"
result = requests.get(url, headers=headers, timeout=10, json=body)
assert isinstance(result, requests.Response)
assert result.status_code == 200

chart = result.json()["chart"]
fig = chart.pop("fig", {})

assert chart
assert not fig
assert list(chart.keys()) == ["content", "format"]
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ def get_equity_data():
symbol = "AAPL"
provider = "fmp"

data["stocks_data"] = openbb.obb.equity.price.historical(
symbol=symbol, provider=provider
).results
data["stocks_data"] = openbb.obb.equity.price.historical(symbol=symbol, provider=provider).results
return data["stocks_data"]


Expand Down Expand Up @@ -678,3 +676,28 @@ def test_charting_derivatives_futures_curve(params, obb):
assert len(result.results) > 0
assert result.chart.content
assert isinstance(result.chart.fig, OpenBBFigure)


@parametrize(
"params",
[
(
{
"provider": "fmp",
"symbol": "AAPL",
"start_date": "2024-01-01",
"end_date": "2024-06-30",
"chart": True,
}
),
],
)
@pytest.mark.integration
def test_charting_equity_historical_market_cap(params, obb):
"""Test chart equity historical market cap."""
result = obb.equity.historical_market_cap(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
assert result.chart.content
assert isinstance(result.chart.fig, OpenBBFigure)
103 changes: 103 additions & 0 deletions openbb_platform/openbb/assets/reference.json
Original file line number Diff line number Diff line change
Expand Up @@ -28001,6 +28001,109 @@
},
"model": "MarketSnapshots"
},
"/equity/historical_market_cap": {
"deprecated": {
"flag": null,
"message": null
},
"description": "Get the historical market cap of a ticker symbol.",
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.equity.historical_market_cap(provider='fmp', symbol='AAPL')\n```\n\n",
"parameters": {
"standard": [
{
"name": "symbol",
"type": "Union[str, List[str]]",
"description": "Symbol to get data for. Multiple items allowed for provider(s): fmp.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "start_date",
"type": "Union[date, str]",
"description": "Start date of the data, in YYYY-MM-DD format.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "end_date",
"type": "Union[date, str]",
"description": "End date of the data, in YYYY-MM-DD format.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "provider",
"type": "Literal['fmp']",
"description": "The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fmp.",
"default": null,
"optional": true
}
],
"fmp": []
},
"returns": {
"OBBject": [
{
"name": "results",
"type": "List[HistoricalMarketCap]",
"description": "Serializable results."
},
{
"name": "provider",
"type": "Optional[Literal['fmp']]",
"description": "Provider name."
},
{
"name": "warnings",
"type": "Optional[List[Warning_]]",
"description": "List of warnings."
},
{
"name": "chart",
"type": "Optional[Chart]",
"description": "Chart object."
},
{
"name": "extra",
"type": "Dict[str, Any]",
"description": "Extra info."
}
]
},
"data": {
"standard": [
{
"name": "date",
"type": "date",
"description": "The date of the data.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "symbol",
"type": "str",
"description": "Symbol representing the entity requested in the data.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "market_cap",
"type": "Union[int, float]",
"description": "Market capitalization of the security.",
"default": "",
"optional": false,
"choices": null
}
],
"fmp": []
},
"model": "HistoricalMarketCap"
},
"/etf/search": {
"deprecated": {
"flag": null,
Expand Down
Loading

0 comments on commit 4500132

Please sign in to comment.