diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 17ba82ef845..13c9be331d3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: key: ${{ runner.os }}-linting restore-keys: ${{ runner.os }}-linting - - run: pip install bandit black codespell flake8 mypy pyupgrade safety pylint==2.12.2 black[jupyter] + - run: pip install bandit black codespell flake8 mypy pyupgrade safety pylint==2.12.2 - run: pip install types-pytz types-requests types-termcolor types-tabulate types-PyYAML types-python-dateutil types-setuptools - run: bandit -x ./tests -r . || true - run: black --check . diff --git a/gamestonk_terminal/jupyter/dashboards/chains.ipynb b/gamestonk_terminal/jupyter/dashboards/chains.ipynb new file mode 100644 index 00000000000..af55e079b05 --- /dev/null +++ b/gamestonk_terminal/jupyter/dashboards/chains.ipynb @@ -0,0 +1,179 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 6, + "id": "e9ad60bc", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import ipywidgets as widgets\n", + "import plotly.graph_objs as go\n", + "import yfinance as yf\n", + "from IPython.display import display" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "beb36881", + "metadata": {}, + "outputs": [], + "source": [ + "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, x, y, ticker, expiry, inst):\n", + " fig.update_yaxes(title=clean_str(x))\n", + " fig.update_xaxes(title=clean_str(y))\n", + " title = f\"{clean_str(y)} vs. {clean_str(x)} for {ticker.upper()} {inst}s on {expiry}\"\n", + " fig.update_layout(\n", + " autosize=False,\n", + " width=1000,\n", + " height=500,\n", + " title={\n", + " \"text\": title,\n", + " \"y\": 0.95,\n", + " \"x\": 0.5,\n", + " \"xanchor\": \"center\",\n", + " \"yanchor\": \"top\",\n", + " },\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "f8c2f65c", + "metadata": { + "tags": [ + "parameters" + ] + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "295abc68725748ad95afc1ffdf7825de", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HTML(value='

Option Chain Dashboard

'), VBox(children=(Text(value='', description='Ticke…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def view_chart(ticker, expiry, inst, x, y):\n", + " global last_ticker, last_exp\n", + " # set_interval_opts(interval_widget,start,end)\n", + " if ticker:\n", + " stock = yf.Ticker(ticker)\n", + " if ticker != last_ticker:\n", + " exps = stock.options\n", + " exps = [\"\"] + list(exps)\n", + " exp_w.options = exps\n", + " last_ticker = ticker\n", + "\n", + " if expiry:\n", + " chains = stock.option_chain(expiry)\n", + " df = chains.calls if inst == \"Call\" else chains.puts\n", + "\n", + " fig = go.Figure()\n", + " plot = go.Scatter(\n", + " x=df[x],\n", + " y=df[y],\n", + " mode=\"lines\",\n", + " )\n", + " fig.add_trace(plot)\n", + "\n", + " format_plotly(fig, x, y, ticker, expiry, inst)\n", + "\n", + " if os.environ.get(\"SERVER_SOFTWARE\", \"jupyter\").startswith(\"voila\"):\n", + " fig.show(config={\"showTips\": False}, renderer=\"notebook\")\n", + " else:\n", + " fig.show(config={\"showTips\": False})\n", + "\n", + "\n", + "last_ticker = \"\"\n", + "last_exp = \"\"\n", + "opts = [\n", + " \"lastTradeDate\",\n", + " \"strike\",\n", + " \"lastPrice\",\n", + " \"bid\",\n", + " \"ask\",\n", + " \"change\",\n", + " \"percentChange\",\n", + " \"volume\",\n", + " \"openInterest\",\n", + " \"impliedVolatility\",\n", + "]\n", + "\n", + "x_w = widgets.Dropdown(options=opts, value=\"strike\", description=\"X\")\n", + "y_w = widgets.Dropdown(options=opts, value=\"lastPrice\", description=\"Y\")\n", + "tickers_w = widgets.Text(description=\"Ticker\")\n", + "exp_w = widgets.Dropdown(description=\"Expiry\")\n", + "inst_w = widgets.Dropdown(options=[\"Put\", \"Call\"], value=\"Call\", description=\"Type\")\n", + "controls = widgets.VBox([tickers_w, exp_w, inst_w, x_w, y_w])\n", + "\n", + "stocks_view = widgets.interactive_output(\n", + " view_chart,\n", + " {\"ticker\": tickers_w, \"expiry\": exp_w, \"inst\": inst_w, \"x\": x_w, \"y\": y_w},\n", + ")\n", + "\n", + "title_html = \"

Option Chain Dashboard

\"\n", + "app_contents = [\n", + " widgets.HTML(title_html),\n", + " controls,\n", + " stocks_view,\n", + "]\n", + "app = widgets.VBox(app_contents)\n", + "display(app)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a84c7390-6b43-4a25-8aa2-31aa84f52605", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + }, + "metadata": { + "interpreter": { + "hash": "e896a00ead8b521528d79ac9ef24990696f2b751eb283ab8e0d078c9c4971ffc" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/gamestonk_terminal/jupyter/dashboards/dashboards_controller.py b/gamestonk_terminal/jupyter/dashboards/dashboards_controller.py index e3a258f0f9f..f7f9f13000e 100644 --- a/gamestonk_terminal/jupyter/dashboards/dashboards_controller.py +++ b/gamestonk_terminal/jupyter/dashboards/dashboards_controller.py @@ -22,7 +22,7 @@ from gamestonk_terminal.menu import session class DashboardsController(BaseController): """Dashboards Controller class""" - CHOICES_COMMANDS = ["stocks", "correlation", "vsurf"] + CHOICES_COMMANDS = ["stocks", "correlation", "vsurf", "chains"] PATH = "/jupyter/dashboard/" def __init__(self, queue: List[str] = None): @@ -36,9 +36,10 @@ class DashboardsController(BaseController): def print_help(self): """Print help""" help_text = """[cmds] - stocks interactive dashboard with ticker information - correlation interactive dashboard with correlation information - vsurf options volatility surface[/cmds] + stocks historic stock information + correlation stock correlations + vsurf options volatility surface + chains options chain analysis[/cmds] """ console.print(text=help_text, menu="Jupyter - Dashboards") @@ -54,6 +55,10 @@ class DashboardsController(BaseController): """Process vsurf command""" create_call(other_args, "vsurf", "") + def call_chains(self, other_args: List[str]): + """Process vsurf command""" + create_call(other_args, "chains", "") + def create_call(other_args: List[str], name: str, filename: str = None) -> None: filename = filename if filename else name diff --git a/website/content/jupyter/dashboards/chains/_index.md b/website/content/jupyter/dashboards/chains/_index.md new file mode 100644 index 00000000000..16dbcbf3ff6 --- /dev/null +++ b/website/content/jupyter/dashboards/chains/_index.md @@ -0,0 +1,11 @@ +``` +usage: chains [-j] [-h] +``` + +Opens a voila dashboard showing option chain information for a given ticker and expiration + +``` +optional arguments: + -j opens in jupyterlab instead of voila (default: False) + -h, --help show this help message +``` diff --git a/website/data/menu/main.yml b/website/data/menu/main.yml index ad0016f3f70..f9a9c264976 100755 --- a/website/data/menu/main.yml +++ b/website/data/menu/main.yml @@ -1226,3 +1226,19 @@ main: ref: "/common/prediction_techniques/conv1d" - name: mc ref: "/common/prediction_techniques/mc" + - name: jupyter + ref: "/jupyter" + sub: + - name: "dashboards" + ref: "/jupyter/dashboards" + sub: + - name: "stocks" + ref: "/jupyter/dashboards/stocks" + - name: "correlation" + ref: "/jupyter/dashboards/correlation" + - name: "vsurf" + ref: "/jupyter/dashboards/vsurf" + - name: "chains" + ref: "/jupyter/dashboards/chains" + - name: "reports" + ref: "/jupyter/reports"