mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-28 21:12:16 +00:00
* fix gov tests * refactor insider * new virtual path extraction * removed some symbol default params as they're considered critical * little adjustments * portfolio refactor * merge API factory * add helpers, stocks, crypto, forex * minor forex changes * include forex api paths * add 2 missing forex funcs * portfolio brokers refactor * display help on api func call * add econometrics virtual paths to api * add api unit test * fixed report for the new api * minor portfolio refactorings * added gdapps * anchor_yield path * some more crypto path fixes * small change * fixed wrong param * minor fixes * wip - inital commit for forex report * add bw as a model, we'll get better solution afterwards * added ema with dummy model as it adds great functionality to the report * minor fixes * wip - added functions to forex report * add feedparser news path * add new virtual paths to api * adding commands to equity report * revert to old paths, new ones were breaking * Add in very basic ETF report * Add candle chart to ETF report * add etf load * allow use of candle without data * add raw to candle * added forex report * ongoing equity report * equity report change * fix some portfolio bugs and add docstrings * include portfolio paths and coin class * add crypto paths * change event dates to str * starting economy report * window for limit * equity report and refactor newsapi * add helper to api * update on economy report * equity report * update economy report * refactor some docstrings * change maturities helper * refactor newsapi * refactor futures command * add some sauce to ycrv plot * black * update report * refactor alphavantage * refactor wsj * update economy report * ycrv tenor * map avaiable_indices * map economy helpers * fix econdb docstring * add plots on economy report * minor fixes * wip - crypto report * update economy report * added same default args as view * added view to explicity use chart=True when suing the api * adjustments - removed rich tables to use only df * final version economy report * change report name * equity report for review * linting * add etf symbols endpoint * incorporate feedback economy report * fix reports launch by adding tag to economy report * fix equity bug * remove analyst name * fix * fix news * make links hyperlinks for equity * click links * fixed arg name * improved news * small improves * Fix light terminal stylesheet that would prevent using it in notebooks (#2473) * improved report * run reports in installer * fix #2209 * minor ycrv refactoring * refactor portfolio/holdv virtual path * refactor benchmark trades * fix events args * adapt economy report to changes * fix portfolio controller bug * holdv refactor * refactor perf command * start portfolio report * remove perf view * refactor holp * add textwrap3 to poetry (doesn't solve the error) * fix equity after merge * add some rolling commands * fix equity after save button * improved crypto report, plus minor fixes * minor fixes on the reports * add maxdd and distr * refactor qa * var command * refactor qa expected shortfall * add es command * add es command * fix qa percentile bug * fix economy rendering * refactor qa omega * add om command * add summary command * add dret command * add mret command * add yret command * add metrics * add allocs to report * remove bro and po commands, add later * fixed some tests * adjustments to crypto report * Fix docstring for VSCode Added a note about installing Jupyter PowerToys extension for optimal API usage in Jupyter VSCode, in the API_README.md. * minor adjustment * remove nft calendar model virtual paths * Add in Portfolio report * fix external axes portfolio view * Update portfolio report with rolling plots * Details for ETF and Portfolio * fix economy report * change analyst to openbb * floppy * fixed unmatched axis in reports * Speed up tests * fix file and load on po * get_news output * add some po paths * Add integration tests for Reports menu * refactor maxsharpe * open maxsharpe * open minrisk * open maxutil * open maxret * Added fixes * black * remove useless views * Fixed small issue * refactor ef * open ef api * portfolio optimization report * Added fixes * unblock api loading * add more endpoints * update po report * unblock api loading * update po report * expose herc * expose property endpoint * Added fixes * More api fixes * flake8 * Fixed some mypy * news api model * flake8 * mypy fix * mypy * black * pylint * fix tests * markdown * markdown * Added fixes * fix economy report * merge * fix economy report * remove empty notebook * expose nco * remove jupyter notebook * expose plot endpoint * remove po report, just used for tests * api v paths plot * remove api_old * change loading msg Co-authored-by: montezdesousa <montezdesousa@gmail.com> Co-authored-by: hjoaquim <h.joaquim@campus.fct.unl.pt> Co-authored-by: montezdesousa <79287829+montezdesousa@users.noreply.github.com> Co-authored-by: Om Gupta <guptagom@gmail.com> Co-authored-by: minhhoang1023 <40023817+minhhoang1023@users.noreply.github.com> Co-authored-by: JerBouma <jer.bouma@gmail.com> Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com> Co-authored-by: Om Gupta <85685255+soggyomelette@users.noreply.github.com> Co-authored-by: Diogo Sousa <diogosousa@Diogos-MBP.lan> Co-authored-by: Colin Delahunty <72827203+colin99d@users.noreply.github.com> Co-authored-by: northern-64bit <75195383+northern-64bit@users.noreply.github.com> Co-authored-by: colin99d <colin99delahunty@gmail.com> Co-authored-by: Minh Hoang <nminh.hoang1023@gmail.com>
378 lines
11 KiB
Python
378 lines
11 KiB
Python
"""Widgets Helper Library.
|
|
|
|
A library of `ipywidgets` wrappers for notebook based reports and voila dashboards.
|
|
The library includes both python code and html/css/js elements that can be found in the
|
|
`./widgets` folder.
|
|
"""
|
|
import os
|
|
from typing import List
|
|
import base64
|
|
from jinja2 import Template
|
|
|
|
|
|
def price_card_stylesheet():
|
|
"""Load a default CSS stylesheet from file."""
|
|
with open(
|
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "widgets", "style.css")
|
|
) as f:
|
|
style = f.read()
|
|
return style
|
|
|
|
|
|
def price_card(ticker: str, price: str, price_color: str = "neutral_color") -> str:
|
|
"""Prepare a styled HTML element of a 128 by 128 price card.
|
|
|
|
Parameters
|
|
----------
|
|
ticker : str
|
|
Instrument ticker for the price card
|
|
price : str
|
|
Instrument price as a string
|
|
price_color : str, optional
|
|
The color of the price. Accepts "up_color", "down_color" and default "neutral_color"
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code as string
|
|
"""
|
|
with open(
|
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "widgets", "card.j2")
|
|
) as f:
|
|
template = Template(f.read())
|
|
card = template.render(ticker=ticker, price=price, price_color=price_color)
|
|
return card
|
|
|
|
|
|
def html_report_stylesheet():
|
|
"""Load a default CSS stylesheet from file."""
|
|
with open(
|
|
os.path.join(
|
|
os.path.dirname(os.path.abspath(__file__)), "widgets", "report.css"
|
|
)
|
|
) as f:
|
|
style = f.read()
|
|
return style
|
|
|
|
|
|
def html_report(title: str = "", stylesheet: str = "", body: str = "") -> str:
|
|
"""Prepare a styled HTML page element.
|
|
|
|
Parameters
|
|
----------
|
|
title : str, optional
|
|
Contents of the title tag, by default ""
|
|
stylesheet : str, optional
|
|
Contents of the stylesheet tag, by default ""
|
|
body : str, optional
|
|
Contents of the body tag, by default ""
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code as string
|
|
"""
|
|
with open(
|
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "widgets", "report.j2")
|
|
) as f:
|
|
template = Template(f.read())
|
|
return template.render(title=title, stylesheet=stylesheet, body=body + "</html>")
|
|
|
|
|
|
def h(level: int, text: str) -> str:
|
|
"""Wrap text into an HTML `h` tag.
|
|
|
|
Parameters
|
|
----------
|
|
level : int
|
|
HTML `h` level tag
|
|
text : str
|
|
Contents for `h` level tag
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code as string
|
|
"""
|
|
return f"<h{str(level)}>{text}</h{level}>"
|
|
|
|
|
|
def p(text: str, style: str = "") -> str:
|
|
"""Wrap text into an HTML `p` tag.
|
|
|
|
Parameters
|
|
----------
|
|
text : str
|
|
Contents for HTML `p` tag
|
|
style: str
|
|
Div style
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code as string
|
|
"""
|
|
return f'<p style="{style}">{text}</p>'
|
|
|
|
|
|
def row(elements: List) -> str:
|
|
"""HTML code elements to add in a single row
|
|
|
|
Parameters
|
|
----------
|
|
elements : List
|
|
List of HTML code elements to add in a row
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code as string
|
|
"""
|
|
with open(
|
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "widgets", "row.j2")
|
|
) as f:
|
|
template = Template(f.read())
|
|
return template.render(elements=elements)
|
|
|
|
|
|
def kpi(thresholds: List[float], sentences: List[str], value: float) -> str:
|
|
"""Add new key performance indicator to main page of report
|
|
|
|
Parameters
|
|
----------
|
|
thresholds : List[float]
|
|
List of thresholds to take into account
|
|
sentences : List[str]
|
|
List of sentences to take into account. len(sentences) = len(thresholds)+1
|
|
value : float
|
|
Current value for the KPI in question
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code as string
|
|
"""
|
|
if len(thresholds) == 1 and len(sentences) == 2:
|
|
if value < thresholds[0]:
|
|
return f'<p style="color:red">❌ {sentences[0]}. {value} < {thresholds[0]} </p>'
|
|
return f'<p style="color:green">✅ {sentences[1]}. {value} > {thresholds[0]} </p>'
|
|
if len(thresholds) == 2 and len(sentences) == 3:
|
|
if value < thresholds[0]:
|
|
return f'<p style="color:red">❌ {sentences[0]}. {value} < {thresholds[0]} </p>'
|
|
if value > thresholds[1]:
|
|
return f'<p style="color:green">✅ {sentences[2]}. {value} > {thresholds[1]} </p>'
|
|
return f'<p style="color:orange">🟡 {sentences[1]}. {thresholds[0]} < {value} < {thresholds[1]} </p>'
|
|
print("Error. KPI condition is not correctly set")
|
|
return ""
|
|
|
|
|
|
def add_tab(
|
|
title: str, htmlcode: str, comment_cell: bool = True, commment_text: str = ""
|
|
) -> str:
|
|
"""Add new tab section for the report. By default adds an opinion editable box at the start.
|
|
|
|
Parameters
|
|
----------
|
|
title : str
|
|
Title associated with this tab / section
|
|
htmlcode : str
|
|
All HTML code contain within this section
|
|
comment_cell : bool
|
|
Comment cell
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code as string
|
|
"""
|
|
html_text = f'<div id="{title}" class="tabcontent"></br>'
|
|
if comment_cell:
|
|
comment = commment_text if commment_text else "No comment."
|
|
html_text += f"""<p style="border:3px; border-style:solid;
|
|
border-color:#000000; padding: 1em; width: 1050px;" contentEditable="true">
|
|
{comment}
|
|
</p>"""
|
|
html_text += f"{htmlcode}</div>"
|
|
return html_text
|
|
|
|
|
|
def tab_clickable_and_save_evt() -> str:
|
|
"""Adds javascript code within HTML at the bottom that allows the interactivity with tabs.
|
|
|
|
Parameters
|
|
----------
|
|
report_name : str
|
|
Report name for the file to be saved
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
javascript code in HTML to process interactive tabs
|
|
"""
|
|
return """
|
|
<script>
|
|
function menu(evt, menu_name) {
|
|
var i, tabcontent, tablinks;
|
|
tabcontent = document.getElementsByClassName("tabcontent");
|
|
for (i = 0; i < tabcontent.length; i++) {
|
|
tabcontent[i].style.display = "none";
|
|
}
|
|
tablinks = document.getElementsByClassName("tablinks");
|
|
for (i = 0; i < tablinks.length; i++) {
|
|
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
|
tablinks[i].style.backgroundColor = "white";
|
|
tablinks[i].style.color = "black";
|
|
}
|
|
document.getElementById(menu_name).style.display = "block";
|
|
|
|
evt.currentTarget.className += " active";
|
|
evt.currentTarget.style.backgroundColor = "black";
|
|
evt.currentTarget.style.color = "white";
|
|
}
|
|
|
|
function saveReport() {
|
|
const markup = document.documentElement.innerHTML;
|
|
var bl = new Blob([markup], { type: "text/html" });
|
|
var a = document.createElement("a");
|
|
a.href = URL.createObjectURL(bl);
|
|
a.download = "openbb_report.html";
|
|
a.hidden = true;
|
|
document.body.appendChild(a);
|
|
a.innerHTML = "Download";
|
|
a.click();
|
|
}
|
|
|
|
function readCommentsAndUpdateValues() {
|
|
var inputs, index;
|
|
|
|
inputs = document.getElementsByTagName('input');
|
|
for (index = 0; index < inputs.length; ++index) {
|
|
const elem = inputs[index];
|
|
elem.addEventListener('input', (e) => {
|
|
console.log(elem.name, elem.value, e.target.value);
|
|
elem.setAttribute("value", e.target.value)
|
|
});
|
|
}
|
|
}
|
|
|
|
window.onload=function(){
|
|
readCommentsAndUpdateValues();
|
|
menu(event, 'SUMMARY');
|
|
};
|
|
</script>"""
|
|
|
|
|
|
def tablinks(tabs: List[str]) -> str:
|
|
"""Adds list of tabs/sections for the reports that are able to be clicked. For every
|
|
6 tabs we push them onto a new line.
|
|
|
|
Parameters
|
|
----------
|
|
tabs : List[str]
|
|
List of tabs/sections for the reports.
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code for interactive tabs
|
|
"""
|
|
htmlcode = '<div class="tab">'
|
|
for idx, tab in enumerate(tabs):
|
|
htmlcode += f"""<button class="tablinks" onclick="menu(event, '{tab}')">{tab}</button>"""
|
|
if ((idx + 1) % 5) == 0:
|
|
htmlcode += "</br>"
|
|
htmlcode += "</div>"
|
|
return htmlcode
|
|
|
|
|
|
def header(
|
|
openbb_img, floppy_disk_img, author, report_date, report_time, report_tz, title
|
|
) -> str:
|
|
"""Creates reports header
|
|
|
|
Parameters
|
|
----------
|
|
openbb_img : str
|
|
Image of OpenBB logo
|
|
floppy_disk_img : str
|
|
Image of floppy disk containing the save button
|
|
author : str
|
|
Name of author responsible by report
|
|
report_date : str
|
|
Date when report is run
|
|
report_time : str
|
|
Time when report is run
|
|
report_tz : str
|
|
Timezone associated with datetime of report being run
|
|
title : str
|
|
Title of the report
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code for interactive tabs
|
|
"""
|
|
try:
|
|
with open(openbb_img, "rb") as image_file:
|
|
openbb_image_encoded = base64.b64encode(image_file.read())
|
|
openbb_img = f"""
|
|
<img src="data:image/png;base64,{openbb_image_encoded.decode()}"
|
|
alt="OpenBB" style="width:144px;">"""
|
|
except Exception:
|
|
openbb_img = ""
|
|
|
|
try:
|
|
with open(floppy_disk_img, "rb") as image_file:
|
|
floppy_disk_encoded = base64.b64encode(image_file.read())
|
|
flask_disk_save = f"""
|
|
<center><img src="data:image/png;base64,{floppy_disk_encoded.decode()}"
|
|
alt="OpenBB" style="width:40px;"></center>"""
|
|
except Exception:
|
|
flask_disk_save = ""
|
|
|
|
return f"""
|
|
<html lang="en" class="" data-lt-installed="true">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>OpenBB Terminal Report</title>
|
|
<meta name="robots" content="noindex">
|
|
</head>
|
|
<div style="display:flex; margin-bottom:1cm;">
|
|
{openbb_img}
|
|
<div style="margin-left:2em">
|
|
<p><b>Analyst:</b> {author}</p>
|
|
<p><b>Date :</b> {report_date}</p>
|
|
<p><b>Time :</b> {report_time} {report_tz}</p>
|
|
<br/>
|
|
<p>{title}</p>
|
|
</div>
|
|
<button style="margin-left:7em; border:0px solid black;
|
|
background-color: transparent;" onclick="saveReport()">
|
|
{flask_disk_save}Save changes
|
|
</button>
|
|
</div>
|
|
"""
|
|
|
|
|
|
def add_external_fig(figloc: str, style: str = "") -> str:
|
|
"""Add external figure to HTML
|
|
|
|
Parameters
|
|
----------
|
|
figloc : str
|
|
Relative figure location
|
|
style: str
|
|
Div style
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
HTML code for figure
|
|
"""
|
|
try:
|
|
with open(figloc, "rb") as image_file:
|
|
img = base64.b64encode(image_file.read()).decode()
|
|
return f'<img src="data:image/{figloc.split(".")[1]};base64,{img}"style="{style}">'
|
|
except Exception:
|
|
return ""
|