mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-28 04:52:07 +00:00
Merge branch 'develop' into release/3.2.3
This commit is contained in:
@@ -50,6 +50,7 @@ class ETFController(BaseController):
|
||||
"load",
|
||||
"overview",
|
||||
"holdings",
|
||||
"holding_perf",
|
||||
"news",
|
||||
"candle",
|
||||
"weights",
|
||||
@@ -106,6 +107,7 @@ class ETFController(BaseController):
|
||||
mt.add_raw("\n")
|
||||
mt.add_cmd("overview", self.etf_name)
|
||||
mt.add_cmd("holdings", self.etf_name)
|
||||
mt.add_cmd("holding_perf", self.etf_name)
|
||||
mt.add_cmd("weights", self.etf_name)
|
||||
mt.add_cmd("news", self.etf_name)
|
||||
mt.add_cmd("candle", self.etf_name)
|
||||
@@ -638,3 +640,60 @@ class ETFController(BaseController):
|
||||
if ns_parser.sheet_name
|
||||
else None,
|
||||
)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_holding_perf(self, other_args: List[str]):
|
||||
"""Process holdings performance command"""
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="holding_perf",
|
||||
description="Look at ETF company holdings' performance",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--start-date",
|
||||
type=valid_date,
|
||||
default=(datetime.now().date() - timedelta(days=366)),
|
||||
dest="start",
|
||||
help="The starting date (format YYYY-MM-DD) to get each holding's price",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
"--end-date",
|
||||
type=valid_date,
|
||||
default=datetime.now().date(),
|
||||
dest="end",
|
||||
help="The ending date (format YYYY-MM-DD) to get each holding's price",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--limit",
|
||||
type=check_positive,
|
||||
dest="limit",
|
||||
help="Number of holdings to get",
|
||||
default=20,
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-l")
|
||||
|
||||
ns_parser = self.parse_known_args_and_warn(
|
||||
parser,
|
||||
other_args,
|
||||
export_allowed=EXPORT_BOTH_RAW_DATA_AND_FIGURES,
|
||||
raw=True,
|
||||
)
|
||||
if ns_parser:
|
||||
if self.etf_name:
|
||||
fmp_view.view_etf_holdings_performance(
|
||||
ticker=self.etf_name,
|
||||
start_date=ns_parser.start,
|
||||
end_date=ns_parser.end,
|
||||
limit=ns_parser.limit,
|
||||
export=ns_parser.export,
|
||||
sheet_name=ns_parser.sheet_name,
|
||||
raw=ns_parser.raw,
|
||||
)
|
||||
else:
|
||||
console.print("Please load a ticker using <load name>. \n")
|
||||
|
||||
@@ -3,13 +3,16 @@ __docformat__ = "numpy"
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Dict
|
||||
from typing import Any, Dict, List
|
||||
from urllib.error import HTTPError
|
||||
from urllib.request import urlopen
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from openbb_terminal.core.session.current_user import get_current_user
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.decorators import check_api_key, log_start_end
|
||||
from openbb_terminal.helper_funcs import request
|
||||
from openbb_terminal.rich_config import console, optional_rich_track
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -47,3 +50,158 @@ def get_etf_sector_weightings(name: str) -> Dict:
|
||||
raise ValueError(data["Error Message"])
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
@check_api_key(["API_KEY_FINANCIALMODELINGPREP"])
|
||||
def get_stock_price_change(
|
||||
tickers: List[str], start_date: str, end_date: str
|
||||
) -> Dict[str, float]:
|
||||
"""Get stock's price percent change over specified time period.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
tickers : List[str]
|
||||
Ticker(s) to get information for.
|
||||
start: str
|
||||
Date from which data is fetched in format YYYY-MM-DD
|
||||
end: str
|
||||
Date from which data is fetched in format YYYY-MM-DD
|
||||
|
||||
Returns
|
||||
-------
|
||||
Dict[str, float]
|
||||
Percent change of closing price over time period, or dictionary of ticker, change pairs.
|
||||
"""
|
||||
tickers_tracker = optional_rich_track(
|
||||
tickers, False, "Gathering stock prices", len(tickers)
|
||||
)
|
||||
current_user = get_current_user()
|
||||
data_aggregate = dict()
|
||||
|
||||
for tick in tickers_tracker:
|
||||
tickers_req = str(tick) + ","
|
||||
for _ in range(4):
|
||||
try:
|
||||
_tick = next(tickers_tracker)
|
||||
tickers_req += _tick + ","
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
url = f"""https://financialmodelingprep.com/api/v3/historical-price-full/{tickers_req}?\
|
||||
from={start_date}&to={end_date}&serietype=line\
|
||||
&apikey={current_user.credentials.API_KEY_FINANCIALMODELINGPREP}"""
|
||||
|
||||
response = request(url)
|
||||
if response.status_code != 200 or "Error Message" in response.json():
|
||||
message = f"Error, Status Code: {response.status_code}."
|
||||
message = (
|
||||
message
|
||||
if "Error Message" not in response.json()
|
||||
else message + "\n" + response.json()["Error Message"] + ".\n"
|
||||
)
|
||||
console.print(message)
|
||||
return dict()
|
||||
|
||||
data = response.json()
|
||||
stock_list = data
|
||||
if "historicalStockList" in data:
|
||||
stock_list = data["historicalStockList"]
|
||||
|
||||
for stock in stock_list:
|
||||
close_end = stock["historical"][0]["close"]
|
||||
close_start = stock["historical"][-1]["close"]
|
||||
pct_change = 100 * (close_end - close_start) / close_start
|
||||
data_aggregate[stock["symbol"]] = pct_change
|
||||
|
||||
return data_aggregate
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
@check_api_key(["API_KEY_FINANCIALMODELINGPREP"])
|
||||
def get_etf_holdings(ticker: str, limit: int = 10) -> List[Dict[str, Any]]:
|
||||
"""This endpoint returns all stocks held by a specific ETF.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
ETF ticker.
|
||||
limit: int
|
||||
Limit amount of stocks to return. FMP returns data
|
||||
by descending weighting.
|
||||
|
||||
Returns
|
||||
-------
|
||||
List[Dict[str,any]]
|
||||
Info for stock holdings in the ETF.
|
||||
"""
|
||||
|
||||
current_user = get_current_user()
|
||||
url = f"""https://financialmodelingprep.com/api/v3/etf-holder/{ticker}\
|
||||
?apikey={current_user.credentials.API_KEY_FINANCIALMODELINGPREP}"""
|
||||
response = request(url)
|
||||
if response.status_code != 200 or "Error Message" in response.json():
|
||||
message = f"Error, Status Code: {response.status_code}."
|
||||
message = (
|
||||
message
|
||||
if "Error Message" not in response.json()
|
||||
else message + "\n" + response.json()["Error Message"] + ".\n"
|
||||
)
|
||||
console.print(message)
|
||||
return []
|
||||
|
||||
return response.json()[0:limit]
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
@check_api_key(["API_KEY_FINANCIALMODELINGPREP"])
|
||||
def get_holdings_pct_change(
|
||||
ticker: str,
|
||||
start_date: str,
|
||||
end_date: str,
|
||||
limit: int = 10,
|
||||
) -> pd.DataFrame:
|
||||
"""Calculate percent change for each holding in ETF.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
ETF ticker.
|
||||
limit: int
|
||||
Limit amount of stocks to return. FMP returns data
|
||||
by descending weighting.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Calculated percentage change for each stock in the ETF, in descending order.
|
||||
"""
|
||||
|
||||
df = pd.DataFrame(columns=["Ticker", "Name", "Percent Change"], data=[])
|
||||
holdings = get_etf_holdings(ticker, limit)
|
||||
tickers = []
|
||||
for stock in holdings:
|
||||
tickers.append(stock.get("asset", " "))
|
||||
|
||||
pct_changes = get_stock_price_change(tickers, start_date, end_date)
|
||||
|
||||
for stock in holdings:
|
||||
pct_change = pct_changes.get(stock["asset"], 0)
|
||||
if pct_change == 0:
|
||||
console.print(
|
||||
f"""Percent change not found for: {stock["asset"]}: {stock["name"]}"""
|
||||
)
|
||||
new_df = pd.DataFrame(
|
||||
{
|
||||
"Ticker": stock["asset"],
|
||||
"Name": stock["name"],
|
||||
"Percent Change": pct_changes.get(stock["asset"], 0),
|
||||
},
|
||||
index=[0],
|
||||
)
|
||||
|
||||
df = pd.concat([df, new_df], ignore_index=True)
|
||||
|
||||
sorted_df = df.sort_values(by="Percent Change", ascending=False, inplace=False)
|
||||
|
||||
return sorted_df
|
||||
|
||||
@@ -8,12 +8,9 @@ from typing import Optional
|
||||
import pandas as pd
|
||||
|
||||
from openbb_terminal import OpenBBFigure, theme
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.decorators import check_api_key, log_start_end
|
||||
from openbb_terminal.etf import fmp_model
|
||||
from openbb_terminal.helper_funcs import (
|
||||
export_data,
|
||||
print_rich_table,
|
||||
)
|
||||
from openbb_terminal.helper_funcs import export_data, print_rich_table
|
||||
from openbb_terminal.rich_config import console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -120,3 +117,80 @@ def display_etf_weightings(
|
||||
)
|
||||
|
||||
return fig.show(external=external_axes)
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
@check_api_key(["API_KEY_FINANCIALMODELINGPREP"])
|
||||
def view_etf_holdings_performance(
|
||||
ticker: str,
|
||||
start_date: str,
|
||||
end_date: str,
|
||||
limit: int = 10,
|
||||
raw: bool = False,
|
||||
export: str = "",
|
||||
sheet_name: Optional[str] = None,
|
||||
):
|
||||
"""Display ETF's holdings' performance over specified time. [Source: FinancialModelingPrep]
|
||||
Parameters
|
||||
----------
|
||||
ticker: str
|
||||
ETF ticker.
|
||||
start_date: str
|
||||
Date from which data is fetched in format YYYY-MM-DD.
|
||||
end: str
|
||||
Date from which data is fetched in format YYYY-MM-DD.
|
||||
limit: int
|
||||
Limit number of holdings to view. Sorted by holding percentage (desc).
|
||||
raw: bool
|
||||
Display holding performance
|
||||
sheet_name: str
|
||||
Optionally specify the name of the sheet the data is exported to.
|
||||
export: str
|
||||
Type of format to export data.
|
||||
"""
|
||||
data = fmp_model.get_holdings_pct_change(ticker, start_date, end_date, limit)[::-1]
|
||||
|
||||
if raw:
|
||||
print_rich_table(
|
||||
data,
|
||||
show_index=False,
|
||||
headers=["Ticker", "Name", "Percent Change"],
|
||||
title="ETF Holdings' Performance",
|
||||
limit=limit,
|
||||
export=bool(export),
|
||||
)
|
||||
|
||||
fig = OpenBBFigure()
|
||||
|
||||
if not raw or fig.is_image_export(export):
|
||||
fig.add_bar(
|
||||
hovertext=[f"{x:.2f}" + "%" for x in data["Percent Change"]],
|
||||
x=data["Percent Change"],
|
||||
y=data["Name"],
|
||||
name="Stock",
|
||||
orientation="h",
|
||||
marker_color=[
|
||||
"darkgreen" if x > 0 else "darkred" for x in data["Percent Change"]
|
||||
],
|
||||
)
|
||||
|
||||
fig.update_layout(
|
||||
title=f"Percent Change in Price for Each Holding from {start_date} to {end_date} for {ticker}",
|
||||
xaxis=dict(title="Percent Change"),
|
||||
yaxis=dict(title="Asset Name"),
|
||||
)
|
||||
|
||||
if export:
|
||||
export_data(
|
||||
export_type=export,
|
||||
dir_path=os.path.dirname(os.path.abspath(__file__)),
|
||||
func_name=f"{ticker}_holdings_perf",
|
||||
df=data,
|
||||
sheet_name=sheet_name,
|
||||
figure=fig,
|
||||
)
|
||||
return
|
||||
|
||||
fig.show(external=raw or bool(export))
|
||||
|
||||
return
|
||||
|
||||
1
openbb_terminal/miscellaneous/i18n/en.yml
vendored
1
openbb_terminal/miscellaneous/i18n/en.yml
vendored
@@ -702,6 +702,7 @@ en:
|
||||
etf/scr: screener ETFs overview/performance, using preset filters
|
||||
etf/overview: get overview
|
||||
etf/holdings: top company holdings
|
||||
etf/holding_perf: Performance of holdings in ETF.
|
||||
etf/weights: sector weights allocation
|
||||
etf/candle: view a candle chart for ETF
|
||||
etf/news: latest news of the company
|
||||
|
||||
@@ -2,6 +2,7 @@ etf
|
||||
load spy
|
||||
overview
|
||||
holdings
|
||||
holdings_perf --limit 3
|
||||
weights
|
||||
weights --raw
|
||||
candle
|
||||
|
||||
@@ -504,7 +504,8 @@
|
||||
"holdings": ["StockAnalysis"],
|
||||
"weights": ["FinancialModelingPrep"],
|
||||
"news": ["NewsApi"],
|
||||
"compare": ["StockAnalysis"]
|
||||
"compare": ["StockAnalysis"],
|
||||
"holding_perf": ["FinancialModelingPrep"]
|
||||
},
|
||||
"economy": {
|
||||
"overview": ["WallStreetJournal"],
|
||||
|
||||
48
tests/openbb_terminal/etf/cassettes/test_fmp_model/test_get_etf_holdings[ARKK].yaml
vendored
Normal file
48
tests/openbb_terminal/etf/cassettes/test_fmp_model/test_get_etf_holdings[ARKK].yaml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://financialmodelingprep.com/api/v3/etf-holder/ARKK?apikey=MOCK_API_KEY
|
||||
response:
|
||||
body:
|
||||
string: "{\n \"Error Message\": \"Invalid API KEY. Please retry or visit our
|
||||
documentation to create one FREE https://site.financialmodelingprep.com/developer/docs\"\n}"
|
||||
headers:
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
Access-Control-Allow-Headers:
|
||||
- X-Requested-With, content-type, auth-token, Authorization, stripe-signature,
|
||||
APPS
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, POST, OPTIONS
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Access-Control-Max-Age:
|
||||
- '3600'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '154'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Wed, 27 Sep 2023 14:51:51 GMT
|
||||
ETag:
|
||||
- W/"9a-ufKRTAmgqkT6Vv3bqU5trChBRE8"
|
||||
Server:
|
||||
- nginx/1.18.0 (Ubuntu)
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Powered-By:
|
||||
- Express
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
||||
48
tests/openbb_terminal/etf/cassettes/test_fmp_model/test_get_etf_holdings[VTI].yaml
vendored
Normal file
48
tests/openbb_terminal/etf/cassettes/test_fmp_model/test_get_etf_holdings[VTI].yaml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://financialmodelingprep.com/api/v3/etf-holder/VTI?apikey=MOCK_API_KEY
|
||||
response:
|
||||
body:
|
||||
string: "{\n \"Error Message\": \"Invalid API KEY. Please retry or visit our
|
||||
documentation to create one FREE https://site.financialmodelingprep.com/developer/docs\"\n}"
|
||||
headers:
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
Access-Control-Allow-Headers:
|
||||
- X-Requested-With, content-type, auth-token, Authorization, stripe-signature,
|
||||
APPS
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, POST, OPTIONS
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Access-Control-Max-Age:
|
||||
- '3600'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '154'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Wed, 27 Sep 2023 14:40:52 GMT
|
||||
ETag:
|
||||
- W/"9a-ufKRTAmgqkT6Vv3bqU5trChBRE8"
|
||||
Server:
|
||||
- nginx/1.18.0 (Ubuntu)
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Powered-By:
|
||||
- Express
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
||||
@@ -0,0 +1,48 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://financialmodelingprep.com/api/v3/etf-holder/ARKK?apikey=MOCK_API_KEY
|
||||
response:
|
||||
body:
|
||||
string: "{\n \"Error Message\": \"Invalid API KEY. Please retry or visit our
|
||||
documentation to create one FREE https://site.financialmodelingprep.com/developer/docs\"\n}"
|
||||
headers:
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
Access-Control-Allow-Headers:
|
||||
- X-Requested-With, content-type, auth-token, Authorization, stripe-signature,
|
||||
APPS
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, POST, OPTIONS
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Access-Control-Max-Age:
|
||||
- '3600'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '154'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Wed, 27 Sep 2023 17:42:35 GMT
|
||||
ETag:
|
||||
- W/"9a-ufKRTAmgqkT6Vv3bqU5trChBRE8"
|
||||
Server:
|
||||
- nginx/1.18.0 (Ubuntu)
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Powered-By:
|
||||
- Express
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
||||
@@ -0,0 +1,48 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://financialmodelingprep.com/api/v3/etf-holder/TSLA?apikey=MOCK_API_KEY
|
||||
response:
|
||||
body:
|
||||
string: "{\n \"Error Message\": \"Invalid API KEY. Please retry or visit our
|
||||
documentation to create one FREE https://site.financialmodelingprep.com/developer/docs\"\n}"
|
||||
headers:
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
Access-Control-Allow-Headers:
|
||||
- X-Requested-With, content-type, auth-token, Authorization, stripe-signature,
|
||||
APPS
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, POST, OPTIONS
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Access-Control-Max-Age:
|
||||
- '3600'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '154'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Wed, 27 Sep 2023 17:42:36 GMT
|
||||
ETag:
|
||||
- W/"9a-ufKRTAmgqkT6Vv3bqU5trChBRE8"
|
||||
Server:
|
||||
- nginx/1.18.0 (Ubuntu)
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Powered-By:
|
||||
- Express
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
||||
@@ -0,0 +1,48 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://financialmodelingprep.com/api/v3/etf-holder/TSLA?apikey=MOCK_API_KEY
|
||||
response:
|
||||
body:
|
||||
string: "{\n \"Error Message\": \"Invalid API KEY. Please retry or visit our
|
||||
documentation to create one FREE https://site.financialmodelingprep.com/developer/docs\"\n}"
|
||||
headers:
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
Access-Control-Allow-Headers:
|
||||
- X-Requested-With, content-type, auth-token, Authorization, stripe-signature,
|
||||
APPS
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, POST, OPTIONS
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Access-Control-Max-Age:
|
||||
- '3600'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '154'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Wed, 27 Sep 2023 17:52:02 GMT
|
||||
ETag:
|
||||
- W/"9a-ufKRTAmgqkT6Vv3bqU5trChBRE8"
|
||||
Server:
|
||||
- nginx/1.18.0 (Ubuntu)
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Powered-By:
|
||||
- Express
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
||||
@@ -0,0 +1,11 @@
|
||||
,Ticker,Name,Percent Change
|
||||
4,EXAS,EXACT SCIENCES CORP,134.98896247240614
|
||||
7,SHOP,SHOPIFY INC - CLASS A,113.33546530220659
|
||||
9,DKNG,DRAFTKINGS INC-CL A,85.71428571428571
|
||||
2,ROKU,ROKU INC,19.648609077598834
|
||||
3,COIN,COINBASE GLOBAL INC -CLASS A,19.01419197314206
|
||||
6,PATH,UIPATH INC - CLASS A,-1.670792079207918
|
||||
0,TSLA,TESLA INC,-11.599797950642241
|
||||
1,ZM,ZOOM VIDEO COMMUNICATIONS-A,-11.609563717032293
|
||||
5,SQ,BLOCK INC,-15.389090909090905
|
||||
8,TDOC,TELADOC HEALTH INC,-25.746753246753247
|
||||
|
@@ -0,0 +1 @@
|
||||
,Ticker,Name,Percent Change
|
||||
|
1
tests/openbb_terminal/etf/json/test_fmp_model/test_get_etf_holdings[ARKK].json
vendored
Normal file
1
tests/openbb_terminal/etf/json/test_fmp_model/test_get_etf_holdings[ARKK].json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -28,3 +28,67 @@ def test_get_etf_sector_weightings(recorder, name):
|
||||
result = fmp_model.get_etf_sector_weightings(name)
|
||||
|
||||
recorder.capture(result)
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.parametrize(
|
||||
"ticker",
|
||||
[
|
||||
"ARKK",
|
||||
],
|
||||
)
|
||||
def test_get_etf_holdings(recorder, ticker):
|
||||
result = fmp_model.get_etf_holdings(ticker)
|
||||
|
||||
assert result.count != 0
|
||||
recorder.capture(result)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"ticker",
|
||||
[
|
||||
"ARKK",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"start_date",
|
||||
[
|
||||
"2022-09-01",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"end_date",
|
||||
[
|
||||
"2023-09-01",
|
||||
],
|
||||
)
|
||||
def test_get_holdings_pct_change(recorder, ticker: str, start_date: str, end_date: str):
|
||||
result = fmp_model.get_holdings_pct_change(ticker, start_date, end_date)
|
||||
|
||||
assert not result.empty
|
||||
recorder.capture(result)
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.parametrize(
|
||||
"ticker",
|
||||
[
|
||||
"TSLA",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"start_date",
|
||||
[
|
||||
"2022-09-01",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"end_date",
|
||||
[
|
||||
"2023-09-01",
|
||||
],
|
||||
)
|
||||
def test_get_stock_price_change(recorder, ticker: str, start_date: str, end_date: str):
|
||||
result = fmp_model.get_holdings_pct_change(ticker, start_date, end_date)
|
||||
|
||||
recorder.capture(result)
|
||||
|
||||
@@ -24,3 +24,28 @@ def vcr_config():
|
||||
)
|
||||
def test_display_etf_weightings(name):
|
||||
fmp_view.display_etf_weightings(name, raw=True, export="")
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.parametrize(
|
||||
"ticker",
|
||||
[
|
||||
"TSLA",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"start_date",
|
||||
[
|
||||
"2022-09-01",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"end_date",
|
||||
[
|
||||
"2023-09-01",
|
||||
],
|
||||
)
|
||||
def test_view_etf_holdings_performance(ticker, start_date, end_date):
|
||||
fmp_view.view_etf_holdings_performance(
|
||||
ticker, start_date, end_date, raw=True, export=""
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ Major holdings:
|
||||
|
||||
[unvl] overview get overview[/unvl] [StockAnalysis]
|
||||
[unvl] holdings top company holdings[/unvl] [StockAnalysis]
|
||||
[unvl] holding_perf Performance of holdings in ETF.[/unvl] [FinancialModelingPrep]
|
||||
[unvl] weights sector weights allocation[/unvl] [FinancialModelingPrep]
|
||||
[unvl] news latest news of the company[/unvl] [NewsApi]
|
||||
[unvl] candle view a candle chart for ETF[/unvl]
|
||||
|
||||
Reference in New Issue
Block a user