From 5e3d4d7e834d4e8405f1c8ff70f7621177af2f30 Mon Sep 17 00:00:00 2001 From: MJ Rossetti Date: Thu, 20 Apr 2023 18:17:27 -0400 Subject: [PATCH] Multistock data dashboard --- test/alpha_test.py | 20 +++++++++ web_app/routes/dashboard_routes.py | 23 ++++++++++- web_app/services/alpha.py | 11 ++++- web_app/templates/multistock_dashboard.html | 46 +++++++++++++++++++++ 4 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 web_app/templates/multistock_dashboard.html diff --git a/test/alpha_test.py b/test/alpha_test.py index 615971b..1aea13c 100644 --- a/test/alpha_test.py +++ b/test/alpha_test.py @@ -23,3 +23,23 @@ def test_fetch_stocks_daily(): df = alpha.fetch_stocks_daily(symbol="OOPS") assert isinstance(df, DataFrame) assert df.empty + + + +def test_fetch_multistock_daily(): + alpha = AlphavantageService() + + # with valid symbol, returns the data: + result = alpha.fetch_multistock_daily(symbols=["IBM", "NFLX"]) + assert isinstance(result, dict) + assert list(result.keys()) == ["IBM", "NFLX"] + + data = result["IBM"] + assert isinstance(data, list) + assert len(data) >= 100 + assert list(data[0].keys()) == ['timestamp', 'open', 'high', 'low', 'close', 'adjusted_close', 'volume', 'dividend_amount', 'split_coefficient'] + + data = result["NFLX"] + assert isinstance(data, list) + assert len(data) >= 100 + assert list(data[0].keys()) == ['timestamp', 'open', 'high', 'low', 'close', 'adjusted_close', 'volume', 'dividend_amount', 'split_coefficient'] diff --git a/web_app/routes/dashboard_routes.py b/web_app/routes/dashboard_routes.py index e7647da..29a33b4 100644 --- a/web_app/routes/dashboard_routes.py +++ b/web_app/routes/dashboard_routes.py @@ -40,7 +40,6 @@ def stocks_dashboard(): return redirect("/stocks/form") - @dashboard_routes.route("/unemployment/dashboard") def unemployment_dashboard(): print("UNEMPLOYMENT DASHBOARD...") @@ -58,3 +57,25 @@ def unemployment_dashboard(): print("ERROR", err) #flash("OOPS", "warning") return redirect("/") + + + + + +# can hit this with: "/multistock/dashboard?symbols=NFLX&symbols=GOOGL&symbols=MSFT" +@dashboard_routes.route("/multistock/dashboard", methods=["GET"]) +def multistock_dashboard(): + print("MULTI-STOCK DASHBOARD...") + + # consider reading these symbols from a datastore, or asking for multiple inputs + symbols = request.args.getlist("symbols") or ["NFLX", "GOOGL", "MSFT"] + print(symbols) + + try: + alpha = AlphavantageService() + data = alpha.fetch_multistock_daily(symbols=symbols) + return render_template("multistock_dashboard.html", symbols=symbols, data=data) + except Exception as err: + print("ERROR", err) + #flash("OOPS", "warning") + return redirect("/") diff --git a/web_app/services/alpha.py b/web_app/services/alpha.py index b44c41c..de468ed 100644 --- a/web_app/services/alpha.py +++ b/web_app/services/alpha.py @@ -4,7 +4,6 @@ from dotenv import load_dotenv from pandas import read_csv, DataFrame - load_dotenv() ALPHAVANTAGE_API_KEY = os.getenv("ALPHAVANTAGE_API_KEY", default="demo") @@ -44,6 +43,16 @@ def fetch_stocks_daily(self, symbol="MSFT"): else: return df + def fetch_multistock_daily(self, symbols:list): + results = {} + for symbol in symbols: + request_url = f"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol={symbol}&apikey={self.api_key}&datatype=csv" + df = read_csv(request_url) + results[symbol] = df.to_dict("records") + # TODO: consider implementing some kind of validation or re-attempt in case one or more requests goes bad + return results #> {"MSFT": [], "GOOGL": [], "NFLX": []} + + def fetch_unemployment(self): """ Fetches unemployment data. diff --git a/web_app/templates/multistock_dashboard.html b/web_app/templates/multistock_dashboard.html new file mode 100644 index 0000000..c49e3fc --- /dev/null +++ b/web_app/templates/multistock_dashboard.html @@ -0,0 +1,46 @@ +{% extends "bootstrap_5_layout.html" %} +{% set active_page = "stocks_dashboard" %} + +{% block content %} + +

Multistock Dashboard

+ +

Selected Stocks: {{ symbols }}

+ +
+ + + + + +{% endblock %}