Hotfix/options plot-smile (#4613)

* init

* Update style.css

* oops was stashed

* Update popups.js

* bump plotly.js version

* fix disappearing modebar
This commit is contained in:
teh_coderer
2023-03-29 12:51:02 -05:00
committed by GitHub
parent aabf0fc80f
commit 30ca6c69e0
8 changed files with 114 additions and 60 deletions

View File

@@ -48,7 +48,7 @@ else:
JUPYTER_NOTEBOOK = True
PLOTS_CORE_PATH = Path(__file__).parent.resolve()
PLOTLYJS_PATH = PLOTS_CORE_PATH / "assets" / "plotly-2.18.2.min.js"
PLOTLYJS_PATH = PLOTS_CORE_PATH / "assets" / "plotly-2.20.0.min.js"
BACKEND = None
@@ -93,7 +93,9 @@ class Backend(PyWry):
try:
with open(PLOTS_CORE_PATH / "plotly.html", encoding="utf-8") as file: # type: ignore
html = file.read()
html = html.replace("{{MAIN_PATH}}", str(PLOTS_CORE_PATH.as_uri()))
html = html.replace(
"{{MAIN_PATH}}", str(PLOTS_CORE_PATH.as_uri())
).replace("{{PLOTLYJS_PATH}}", str(PLOTLYJS_PATH.as_uri()))
# We create a temporary file to inject the path to the script tag
# This is so we don't have to modify the original file
@@ -374,7 +376,9 @@ async def download_plotly_js():
try:
# we use aiohttp to download plotly.js
# this is so we don't have to block the main thread
async with aiohttp.ClientSession() as session:
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
async with session.get(f"https://cdn.plot.ly/{js_filename}") as resp:
with open(str(PLOTLYJS_PATH), "wb") as f:
while True:

View File

@@ -12,7 +12,7 @@
<script src="/{{MAIN_PATH}}/web/popups.js" type="text/javascript"></script>
<script src="/{{MAIN_PATH}}/web/main.js" type="text/javascript"></script>
<script
src="/{{MAIN_PATH}}/assets/plotly-2.18.2.min.js"
src="/{{PLOTLYJS_PATH}}"
type="text/javascript"
></script>
<script
@@ -25,11 +25,11 @@
<body>
<!-- Plotly -->
<div id="all-your-base">
<div id="openbb_container">
<div
id="openbb_header"
class="_header flex items-center justify-between gap-4 py-2 px-4 text-center"
style="z-index: 99999999999; width: 100%; top: 0;"
style="z-index: 99999999999; width: 100%; top: 0; max-height: 60px;"
>
<div class="w-1/3">
<svg
@@ -52,10 +52,15 @@
id="openbb_chart"
class="plotly-graph-div"
></div>
<div
id="openbb_footer"
class="_footer flex items-center justify-between gap-4 py-2 px-4 text-center"
style="z-index: 99999999999; width: 100%; bottom: 0; max-height: 60px;"
>......................</div>
</div>
<div id="saving" class="saving">
Saving Image <div id="loader" class="loader"></div>
<div id="loading" class="saving">
<div id="loading_text" class="loading_text"></div><div id="loader" class="loader"></div>
</div>

View File

@@ -1525,7 +1525,7 @@ class OpenBBFigure(go.Figure):
return
margin_add = (
dict(l=80, r=60, b=85, t=60, pad=0)
dict(l=80, r=60, b=85, t=40, pad=0)
if not self._has_secondary_y
else dict(l=60, r=50, b=85, t=40, pad=0)
)

View File

@@ -237,7 +237,7 @@ function downloadImage() {
const loader = document.getElementById("loader");
loader.classList.add("show");
domtoimage
.toPng(document.getElementById("all-your-base"))
.toPng(document.getElementById("openbb_container"))
.then(function (dataUrl) {
let img = new Image(
globals.CHART_DIV.clientWidth,

View File

@@ -46,7 +46,8 @@ body {
display: flex;
}
.all-your-base {
.openbb_container {
align-items: center;
width: 100%;
height: 100%;
background-color: #000000;
@@ -74,7 +75,6 @@ body {
visibility: visible;
}
#changecolor {
position: absolute;
z-index: 9;
@@ -196,13 +196,13 @@ body {
.modebar {
z-index: 5000 !important;
position: absolute !important;
bottom: 0px !important;
position: fixed !important;
bottom: 10px !important;
top: auto !important;
left: 50% !important;
right: auto !important;
align-items: center;
transform: translateX(-50%) translateY(80%) !important;
transform: translate(-50%, 10%) !important;
}
@media screen and (max-width: 600px) {
@@ -212,7 +212,7 @@ body {
}
.modebar {
bottom: 60px !important;
bottom: 20px !important;
}
}
@@ -597,10 +597,6 @@ button {
width: 20px;
height: 20px;
animation: spin 1.5s linear infinite;
opacity: 0;
}
.loader.show {
opacity: 1;
}
@@ -1315,3 +1311,13 @@ video {
#06101a 82%,
#060709);
}
@media screen and (max-height: 1000px) and (max-width: 1100px) {
._header strong {
font-size: 1.1rem !important;
}
._header p {
font-size: 1.0rem !important;
}
}

View File

@@ -6,6 +6,30 @@ let globals = {
cmd_src_idx: null,
};
function loadingOverlay(message) {
const loading = document.getElementById("loading");
const loading_text = document.getElementById("loading_text");
loading_text.innerHTML = message;
loading.classList.add("show");
let is_loaded = setInterval(function () {
if (loading.classList.contains("show")) {
clearInterval(is_loaded);
}
}, 10);
}
const non_blocking = (func, delay) => {
let timeout;
return function () {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), delay);
};
};
function OpenBBMain(plotly_figure, chartdiv, csvdiv, textdiv, titlediv) {
// Main function that plots the graphs and initializes the bar menus
globals.CHART_DIV = chartdiv;
@@ -16,15 +40,22 @@ function OpenBBMain(plotly_figure, chartdiv, csvdiv, textdiv, titlediv) {
console.log("plotly_figure", plotly_figure);
let graphs = plotly_figure;
const loader = document.getElementById("loader");
const saving = document.getElementById("saving");
const loading = document.getElementById("loading");
// We add the event listeners for csv file/type changes
globals.CSV_DIV.querySelector("#csv_file").addEventListener(
"change",
function () {
console.log("file changed");
checkFile(globals.CSV_DIV);
loadingOverlay("Loading CSV");
setTimeout(function () {
non_blocking(function () {
checkFile(globals.CSV_DIV);
}, 2)();
setTimeout(function () {
loading.classList.remove("show");
}, 200);
}, 1000);
}
);
globals.CSV_DIV.querySelector("#csv_trace_type").addEventListener(
@@ -34,17 +65,8 @@ function OpenBBMain(plotly_figure, chartdiv, csvdiv, textdiv, titlediv) {
checkFile(globals.CSV_DIV, true);
}
);
globals.filename = openbbFilename(graphs);
const non_blocking = (func, delay) => {
let timeout;
return function () {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), delay);
};
};
globals.filename = openbbFilename(graphs);
// Sets the config with the custom buttons
CONFIG = {
@@ -59,19 +81,12 @@ function OpenBBMain(plotly_figure, chartdiv, csvdiv, textdiv, titlediv) {
name: "Download Data (Ctrl+S)",
icon: Plotly.Icons.disk,
click: function (gd) {
let saved_csv = document.createElement("div");
saved_csv.innerHTML = "Saved CSV";
saved_csv.classList.add("saving");
saved_csv.classList.add("show");
document.body.appendChild(saved_csv);
loadingOverlay("Saving CSV");
setTimeout(function () {
downloadData(gd);
}, 500);
setTimeout(function () {
saved_csv.classList.remove("show");
setTimeout(function () {
document.body.removeChild(saved_csv);
}, 500);
loading.classList.remove("show");
}, 1000);
},
},
@@ -86,15 +101,13 @@ function OpenBBMain(plotly_figure, chartdiv, csvdiv, textdiv, titlediv) {
name: "Download Plot",
icon: Plotly.Icons.camera,
click: function () {
saving.classList.add("show");
loader.classList.add("show");
loadingOverlay("Saving Image");
hideModebar();
non_blocking(function () {
downloadImage();
setTimeout(function () {
setTimeout(function () {
saving.classList.remove("show");
loader.classList.remove("show");
loading.classList.remove("show");
hideModebar();
}, 50);
}, 25);
@@ -259,10 +272,12 @@ function OpenBBMain(plotly_figure, chartdiv, csvdiv, textdiv, titlediv) {
// We check for the dark mode
if (graphs.layout.template.layout.mapbox.style == "dark") {
document.body.style.backgroundColor = "#000000";
document.getElementById("openbb_footer").style.color = "#000000";
graphs.layout.template.layout.paper_bgcolor = "#000000";
graphs.layout.template.layout.plot_bgcolor = "#000000";
} else {
document.body.style.backgroundColor = "#FFFFFF";
document.getElementById("openbb_footer").style.color = "#FFFFFF";
}
// We set the plot config and plot the chart

View File

@@ -384,6 +384,7 @@ function on_submit(popup_id, on_annotation = null) {
yaxis = main_trace.yaxis.replace("yaxis", "y");
yaxis_id = main_trace.yaxis;
}
gd.layout.showlegend = true;
if (popup_data.trace_type == "candlestick") {
trace = {
@@ -410,7 +411,6 @@ function on_submit(popup_id, on_annotation = null) {
yaxis: yaxis,
};
} else {
gd.layout.showlegend = true;
orginal_data = data;
let non_null = data.findIndex(

View File

@@ -10,7 +10,7 @@ import numpy as np
from scipy.spatial import Delaunay
from scipy.stats import binom
from openbb_terminal import OpenBBFigure
from openbb_terminal import OpenBBFigure, theme
from openbb_terminal.core.plots.config.openbb_styles import (
PLT_3DMESH_COLORSCALE,
PLT_3DMESH_HOVERLABEL,
@@ -95,6 +95,7 @@ def plot_plot(
external_axes : bool, optional
Whether to return the figure object or not, by default False
"""
is_smile = custom == "smile"
convert = {
"ltd": "lastTradeDate",
"s": "strike",
@@ -107,7 +108,8 @@ def plot_plot(
"oi": "openInterest",
"iv": "impliedVolatility",
}
if custom == "smile":
if is_smile:
x = "strike"
y = "impliedVolatility"
else:
@@ -130,20 +132,42 @@ def plot_plot(
f"[red]'{y}' is not a valid option. Defaulting to `impliedVolatility`.[/red]\n"
)
varis = op_helpers.opt_chain_cols
chain = yfinance_model.get_option_chain(symbol, expiry)
values = chain.puts if put else chain.calls
x_data = values[x]
y_data = values[y]
fig = OpenBBFigure()
if not is_smile:
varis = op_helpers.opt_chain_cols
values = chain.puts if put else chain.calls
option = "puts" if put else "calls"
fig = OpenBBFigure(
title=f"{varis[y]['label']} vs. {varis[x]['label']} for {symbol} {option} on {expiry}",
xaxis_title=varis[x]["label"],
yaxis_title=varis[y]["label"],
)
fig.add_scatter(x=x_data, y=y_data, mode="lines+markers")
x_data = values[x]
y_data = values[y]
option = "puts" if put else "calls"
title = f"{varis[y]['label']} vs. {varis[x]['label']} for {symbol} {option} on {expiry}"
xaxis_title = varis[x]["label"]
yaxis_title = varis[y]["label"]
fig.add_scatter(x=x_data, y=y_data, mode="lines+markers")
else:
calls = chain.calls[chain.calls["impliedVolatility"] > 0.00002].dropna()
puts = chain.puts[chain.puts["impliedVolatility"] > 0.00002].dropna()
for data, name in zip([calls, puts], ["Calls", "Puts"]):
fig.add_scatter(
x=data["strike"],
y=data["impliedVolatility"],
mode="lines+markers",
name=name,
line_color=theme.up_color if name == "Calls" else theme.down_color,
)
title = f"Implied Volatility Smile for {symbol} on {expiry}"
xaxis_title = "Strike"
yaxis_title = "Implied Volatility"
fig.set_title(title)
fig.set_xaxis_title(xaxis_title)
fig.set_yaxis_title(yaxis_title)
export_data(
export,