Skip to content

Commit

Permalink
Add ETF county weighting command with FMP data (#5645)
Browse files Browse the repository at this point in the history
* Remove code that wrongfully infers the filing date as end of quarter

* Add etf countries command with fmp data

* Add countries command to etf router

* Update sector and country weighting fmp models

* Fix docstring typo

* Add unit tests and update mock data

* Add integration tests for etf.countries

* Bring back missing integration tests

* Fix economic calendar integration tests
  • Loading branch information
piiq committed Nov 1, 2023
1 parent 83874da commit 96a20a6
Show file tree
Hide file tree
Showing 14 changed files with 374 additions and 225 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ repos:
entry: codespell
args:
[
"--ignore-words-list=VAI,MIS,shs,gard,te,commun,parana,ro,zar,vie,hel,jewl,zlot,ba,buil,coo,ether,hist,hsi,mape,navagation,operatio,pres,ser,yeld,shold,ist,varian,datas,ake,creat,statics,ket,toke,certi,buidl,ot",
"--ignore-words-list=VAI,MIS,shs,gard,te,commun,parana,ro,zar,vie,hel,jewl,zlot,ba,buil,coo,ether,hist,hsi,mape,navagation,operatio,pres,ser,yeld,shold,ist,varian,datas,ake,creat,statics,ket,toke,certi,buidl,ot,fo",
"--quiet-level=2",
"--skip=./**/tests/**,./**/test_*.py,.git,*.css,*.csv,*.html,*.ini,*.ipynb,*.js,*.json,*.lock,*.scss,*.txt,*.yaml,build/pyinstaller/*,./website/config.toml",
"-x=openbb_terminal/economy/fedreserve_model.py",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,10 +496,10 @@ def test_economy_gdpforecast(params, headers):
[
(
{
"provider": "tradingeconomics",
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"country": "mexico,sweden",
"provider": "tradingeconomics",
}
),
(
Expand All @@ -514,7 +514,7 @@ def test_economy_calendar(params, headers):
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/economy/econcal?{query_str}"
url = f"http://0.0.0.0:8000/api/v1/economy/calendar?{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 @@ -452,7 +452,7 @@ def test_economy_gdpforecast(params, obb):
def test_economy_calendar(params, obb):
params = {p: v for p, v in params.items() if v}

result = obb.economy.econcal(**params)
result = obb.economy.calendar(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
53 changes: 34 additions & 19 deletions openbb_platform/extensions/etf/integration/test_etf_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,29 +103,47 @@ def test_etf_sectors(params, headers):
assert result.status_code == 200


@pytest.mark.parametrize(
"params",
[
({"symbol": "IOO"}),
({"symbol": "MISL", "cik": None, "provider": "fmp"}),
],
)
@pytest.mark.integration
def test_etf_holdings_date(params, headers):
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/etf/holdings_date?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200


@pytest.mark.parametrize(
"params",
[
(
{
"symbol": "IOO",
"date": "2023-01-01",
"date": "2023-03-31",
"cik": None,
"provider": "fmp",
}
),
(
{
"symbol": "SPY",
"date": "2023-04-20",
"symbol": "SILJ",
"date": "2019-12-31",
"cik": None,
"provider": "fmp",
}
),
(
{
"symbol": "MISL",
"date": "2023-04-20",
"date": "2023-03-31",
"cik": "0001329377",
"provider": "fmp",
}
Expand All @@ -145,77 +163,74 @@ def test_etf_holdings(params, headers):

@pytest.mark.parametrize(
"params",
[
({"symbol": "IOO"}),
({"symbol": "MISL", "cik": None, "provider": "fmp"}),
],
[({"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK", "provider": "fmp"})],
)
@pytest.mark.integration
def test_etf_holdings_date(params, headers):
def test_etf_price_performance(params, headers):
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/etf/holdings_date?{query_str}"
url = f"http://0.0.0.0:8000/api/v1/etf/price_performance?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200


@pytest.mark.parametrize(
"params",
[({"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK", "provider": "fmp"})],
[({"symbol": "IOO"})],
)
@pytest.mark.integration
def test_etf_price_performance(params, headers):
def test_etf_countries(params, headers):
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/etf/price_performance?{query_str}"
url = f"http://0.0.0.0:8000/api/v1/etf/countries?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200


@pytest.mark.parametrize(
"params",
[({"sort": "desc", "limit": 10, "provider": "wsj"})],
[({"sort": "desc", "limit": 10})],
)
@pytest.mark.integration
def test_etf_disc_gainers(params, headers):
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/stocks/disc/gainers?{query_str}"
url = f"http://0.0.0.0:8000/api/v1/etf/disc/gainers?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200


@pytest.mark.parametrize(
"params",
[({"sort": "desc", "limit": 10, "provider": "wsj"})],
[({"sort": "desc", "limit": 10})],
)
@pytest.mark.integration
def test_etf_disc_losers(params, headers):
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/stocks/disc/losers?{query_str}"
url = f"http://0.0.0.0:8000/api/v1/etf/disc/losers?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200


@pytest.mark.parametrize(
"params",
[({"sort": "desc", "limit": 10, "provider": "wsj"})],
[({"sort": "desc", "limit": 10})],
)
@pytest.mark.integration
def test_etf_disc_active(params, headers):
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/stocks/disc/active?{query_str}"
url = f"http://0.0.0.0:8000/api/v1/etf/disc/active?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200
46 changes: 30 additions & 16 deletions openbb_platform/extensions/etf/integration/test_etf_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,29 +97,46 @@ def test_etf_sectors(params, obb):
assert len(result.results) > 0


@pytest.mark.parametrize(
"params",
[
({"symbol": "IOO"}),
({"symbol": "MISL", "cik": None, "provider": "fmp"}),
],
)
@pytest.mark.integration
def test_etf_holdings_date(params, obb):
params = {p: v for p, v in params.items() if v}

result = obb.etf.holdings_date(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0


@pytest.mark.parametrize(
"params",
[
(
{
"symbol": "IOO",
"date": "2023-01-01",
"date": "2023-03-31",
"cik": None,
"provider": "fmp",
}
),
(
{
"symbol": "SPY",
"date": "2023-04-20",
"symbol": "SILJ",
"date": "2019-12-31",
"cik": None,
"provider": "fmp",
}
),
(
{
"symbol": "MISL",
"date": "2023-04-20",
"date": "2023-03-31",
"cik": "0001329377",
"provider": "fmp",
}
Expand All @@ -138,30 +155,27 @@ def test_etf_holdings(params, obb):

@pytest.mark.parametrize(
"params",
[
({"symbol": "IOO"}),
({"symbol": "MISL", "cik": None, "provider": "fmp"}),
],
[({"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK", "provider": "fmp"})],
)
@pytest.mark.integration
def test_etf_holdings_date(params, obb):
def test_etf_price_performance(params, obb):
params = {p: v for p, v in params.items() if v}

result = obb.etf.holdings_date(**params)
result = obb.etf.price_performance(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0


@pytest.mark.parametrize(
"params",
[({"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK", "provider": "fmp"})],
[({"symbol": "IOO"})],
)
@pytest.mark.integration
def test_etf_price_performance(params, obb):
def test_etf_countries(params, obb):
params = {p: v for p, v in params.items() if v}

result = obb.etf.price_performance(**params)
result = obb.etf.countries(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
Expand All @@ -175,7 +189,7 @@ def test_etf_price_performance(params, obb):
def test_etf_disc_gainers(params, obb):
params = {p: v for p, v in params.items() if v}

result = obb.stocks.disc.gainers(**params)
result = obb.etf.disc.gainers(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
Expand All @@ -189,7 +203,7 @@ def test_etf_disc_gainers(params, obb):
def test_etf_disc_losers(params, obb):
params = {p: v for p, v in params.items() if v}

result = obb.stocks.disc.losers(**params)
result = obb.etf.disc.losers(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
Expand All @@ -203,7 +217,7 @@ def test_etf_disc_losers(params, obb):
def test_etf_disc_active(params, obb):
params = {p: v for p, v in params.items() if v}

result = obb.stocks.disc.active(**params)
result = obb.etf.disc.active(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
11 changes: 11 additions & 0 deletions openbb_platform/extensions/etf/openbb_etf/etf_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ def sectors(
return OBBject(results=Query(**locals()).execute())


@router.command(model="EtfCountries")
def countries(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,
extra_params: ExtraParams,
) -> OBBject[BaseModel]:
"""ETF Country weighting."""
return OBBject(results=Query(**locals()).execute())


@router.command(model="PricePerformance")
def price_performance(
cc: CommandContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
class EtfCountriesQueryParams(QueryParams):
"""ETF Countries Query Params."""

symbol: str = Field(description=QUERY_DESCRIPTIONS.get("symbol", ""))
symbol: str = Field(description=QUERY_DESCRIPTIONS.get("symbol", "") + " (ETF)")

@field_validator("symbol")
@classmethod
Expand All @@ -27,4 +27,6 @@ class EtfCountriesData(Data):
"""ETF Countries Data."""

country: str = Field(description="The country of the exposure.")
weight: float = Field(description="The weight of the country in the ETF.")
weight: float = Field(
description="Exposure of the ETF to the country in normalized percentage points."
)
8 changes: 5 additions & 3 deletions openbb_platform/providers/fmp/openbb_fmp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from openbb_fmp.models.earnings_calendar import FMPEarningsCalendarFetcher
from openbb_fmp.models.earnings_call_transcript import FMPEarningsCallTranscriptFetcher
from openbb_fmp.models.economic_calendar import FMPEconomicCalendarFetcher
from openbb_fmp.models.etf_countries import FMPEtfCountriesFetcher
from openbb_fmp.models.etf_holdings import FMPEtfHoldingsFetcher
from openbb_fmp.models.etf_holdings_date import FMPEtfHoldingsDateFetcher
from openbb_fmp.models.etf_info import FMPEtfInfoFetcher
Expand Down Expand Up @@ -89,11 +90,12 @@
"CompanyFilings": FMPCompanyFilingsFetcher,
"TreasuryRates": FMPTreasuryRatesFetcher,
"ExecutiveCompensation": FMPExecutiveCompensationFetcher,
"EtfSearch": FMPEtfSearchFetcher,
"EtfSectors": FMPEtfSectorsFetcher,
"EtfInfo": FMPEtfInfoFetcher,
"EtfCountries": FMPEtfCountriesFetcher,
"EtfHoldings": FMPEtfHoldingsFetcher,
"EtfHoldingsDate": FMPEtfHoldingsDateFetcher,
"EtfInfo": FMPEtfInfoFetcher,
"EtfSearch": FMPEtfSearchFetcher,
"EtfSectors": FMPEtfSectorsFetcher,
"CryptoHistorical": FMPCryptoHistoricalFetcher,
"ForexHistorical": FMPForexHistoricalFetcher,
"ForexPairs": FMPForexPairsFetcher,
Expand Down
Loading

0 comments on commit 96a20a6

Please sign in to comment.