diff --git a/gamestonk_terminal/jupyter/dashboards/stocks.ipynb b/gamestonk_terminal/jupyter/dashboards/stocks.ipynb index 74a968ed941..863fec0ab33 100644 --- a/gamestonk_terminal/jupyter/dashboards/stocks.ipynb +++ b/gamestonk_terminal/jupyter/dashboards/stocks.ipynb @@ -39,6 +39,8 @@ " \"3mo\",\n", "]\n", "\n", + "rows = [\"sector\",\"marketCap\",\"beta\",\"fiftyTwoWeekHigh\",\"fiftyTwoWeekLow\",\"floatShares\",\"sharesShort\",\"exDividendDate\"]\n", + "\n", "views = {\n", " \"Raw Data\": lambda x, y: x,\n", " \"Percent Change\": lambda x, y: x.pct_change(),\n", @@ -49,6 +51,46 @@ " / (x.rolling(y).mean()),\n", "}\n", "\n", + "clean_row = {\n", + " \"sector\": \"Sector\",\n", + " \"marketCap\": \"M Cap\",\n", + " \"beta\": \"Beta\",\n", + " \"fiftyTwoWeekHigh\": \"52W High\",\n", + " \"fiftyTwoWeekLow\": \"52W Low\",\n", + " \"floatShares\": \"Floats\",\n", + " \"sharesShort\": \"Shorts\",\n", + " \"exDividendDate\": \"Ex-Div\"\n", + "}\n", + "\n", + "clean_data = {\n", + " \"sector\": lambda x: \"N/A\" if x is None else x,\n", + " \"marketCap\": lambda x: \"N/A\" if x is None else big_num(x),\n", + " \"beta\": lambda x: \"N/A\" if x is None else f\"{round(x,2)}\",\n", + " \"fiftyTwoWeekHigh\": lambda x: \"N/A\" if x is None else f\"${round(x,2)}\",\n", + " \"fiftyTwoWeekLow\": lambda x: \"N/A\" if x is None else f\"${round(x,2)}\",\n", + " \"floatShares\": lambda x: \"N/A\" if x is None else big_num(x),\n", + " \"sharesShort\": lambda x: \"N/A\" if x is None else big_num(x),\n", + " \"exDividendDate\": lambda x: \"N/A\" if x is None else datetime.fromtimestamp(x).strftime(\"%Y/%m/%d\"),\n", + "}\n", + "\n", + "def big_num(num):\n", + " if num > 1_000_000_000_000:\n", + " return f\"{round(num/1_000_000_000_000,2)}T\"\n", + " if num > 1_000_000_000:\n", + " return f\"{round(num/1_000_000_000,2)}B\"\n", + " if num > 1_000_000:\n", + " return f\"{round(num/1_000_000,2)}M\"\n", + " if num > 1_000:\n", + " return f\"{num/round(1_000,2)}K\"\n", + " return f\"{round(num,2)}\"\n", + "\n", + "def clean_str(string):\n", + " new_str = \"\"\n", + " for letter in string:\n", + " if letter.isupper():\n", + " new_str += \" \"\n", + " new_str += letter\n", + " return new_str.title()\n", "\n", "def format_plotly(fig, data, start, end, chart, calc=None):\n", " fig.update_yaxes(title=None)\n", @@ -64,10 +106,11 @@ " fig_title = \"Volume\"\n", " height = 500 if chart == \"main\" else 300\n", " fig.update_layout(\n", - " margin=dict(l=20, r=20, t=10, b=10),\n", + " margin=dict(l=0, r=10, t=10, b=10),\n", " autosize=False,\n", - " width=1200,\n", + " width=900,\n", " height=height,\n", + " legend=dict(orientation=\"h\"),\n", " title={\n", " \"text\": fig_title,\n", " \"y\": 0.95,\n", @@ -100,7 +143,16 @@ " if os.environ.get(\"SERVER_SOFTWARE\", \"jupyter\").startswith(\"voila\"):\n", " fig.show(config=config, renderer=\"notebook\")\n", " else:\n", - " fig.show(config=config)" + " fig.show(config=config)\n", + "\n", + "def table_data(infos):\n", + " cols = [\"Ticker\"] + list(infos)\n", + " data = pd.DataFrame(columns=cols)\n", + " data[\"Ticker\"] = [clean_row[x] for x in rows]\n", + " for ticker in list(infos):\n", + " data[ticker] = [clean_data[x](infos[ticker][x]) for x in rows]\n", + " new_cols = {k:clean_str(k) for k in rows}\n", + " return data" ] }, { @@ -119,6 +171,7 @@ " self.last_tickers = \"\"\n", " self.last_interval = \"1d\"\n", " self.df = pd.DataFrame()\n", + " self.infos = {}\n", "\n", " def create_stock(\n", " self, calculation, data, rolling, start, end, interval, tickers, chart\n", @@ -180,7 +233,40 @@ " name = f\"{val.upper()}\"\n", " create_line(\"line\", result.index, vals, name, \"Volume\", fig)\n", " format_plotly(fig, \"Volume\", start, end, \"volume\")\n", - " show_fig(fig)" + " show_fig(fig)\n", + "\n", + " def create_table(self, tickers):\n", + " if tickers and tickers[-1] == \",\":\n", + " clean_tickers = [x for x in tickers.split(\",\") if x]\n", + " for ticker in clean_tickers:\n", + " if ticker not in self.infos:\n", + " self.infos[ticker] = yf.Ticker(ticker).info\n", + " for ticker in self.infos:\n", + " if ticker not in tickers:\n", + " self.infos.pop(ticker)\n", + " result = table_data(self.infos)\n", + " fig = go.Figure(\n", + " data= [\n", + " go.Table(\n", + " header = dict(\n", + " values = result.columns,\n", + " fill_color=\"lightgray\",\n", + " font=dict(color=\"black\"),\n", + " align=\"left\"\n", + " ),\n", + " cells=dict(\n", + " values=[result[x] for x in result.columns],\n", + " #fill_color=base,\n", + " #format=[\"\",\",\",\".2f\",\"$.2f\",\"$.2f\",\",\",\",\",\"\"],\n", + " font=dict(color=\"black\"),\n", + " align=\"left\",\n", + " )\n", + " )\n", + " ],\n", + "\n", + " )\n", + " fig.update_layout(margin=dict(l=0, r=20, t=0, b=0), width=350)\n", + " show_fig(fig)" ] }, { @@ -250,6 +336,14 @@ " },\n", ")\n", "\n", + "table_view = widgets.interactive_output(\n", + " chart.create_table,\n", + " {\"tickers\": tickers_widget}\n", + ")\n", + "\n", + "charts = widgets.VBox([stocks_view, volume_view], layout=widgets.Layout(width='100%',padding='0',margin='0'))\n", + "figures = widgets.HBox([charts, table_view], layout=widgets.Layout(padding='0',margin='0'))\n", + "\n", "title_html = \"

Stock Analysis Dashboard

\"\n", "warning_html = '

Use a comma after EVERY stock typed.

'\n", "\n", @@ -257,8 +351,7 @@ " widgets.HTML(title_html),\n", " controls,\n", " widgets.HTML(warning_html),\n", - " stocks_view,\n", - " volume_view,\n", + " figures\n", "]\n", "app = widgets.VBox(app_contents)\n", "display(app)" @@ -267,7 +360,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bdd59bc7-582e-4c71-a0c9-ccb244567356", + "id": "8f33793c-adc9-4bc1-8fd4-aeff5a00ccba", "metadata": {}, "outputs": [], "source": []