diff --git a/openbb_terminal/jupyter/reports/equity.ipynb b/openbb_terminal/jupyter/reports/equity.ipynb index ff798cf3955..df6fdc86f45 100644 --- a/openbb_terminal/jupyter/reports/equity.ipynb +++ b/openbb_terminal/jupyter/reports/equity.ipynb @@ -434,8 +434,7 @@ "outputs": [], "source": [ "df_sentiment_finbrain = openbb.stocks.ba.models.finbrain.get_sentiment(ticker)\n", - "finbrain_sentiment_val = float(df_sentiment_finbrain.values[-1][0])\n", - "finbrain_sentiment_val = 10" + "finbrain_sentiment_val = float(df_sentiment_finbrain.values[-1][0])" ] }, { @@ -583,160 +582,64 @@ "outputs": [], "source": [ "body = \"\"\n", - "body += f'''\n", - "
\n", - " \"OpenBB\"\n", - "
\n", - "

Analyst: {author}

\n", - "

Date : {report_date}

\n", - "

Time : {report_time} {report_timezone}

\n", - "
\n", - "

INVESTMENT RESEARCH REPORT: {ticker}

\n", - "
\n", - "
'''\n", "\n", - "body += '''\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " \n", - " \n", - " \n", - "
'''\n", + "img = f'\"OpenBB\"'\n", + "body += openbb.widgets.header(img, author, report_date, report_time, report_timezone, f'INVESTMENT RESEARCH REPORT: {ticker}')\n", "\n", - "body += '
'\n", - "body += '

KPIs:

'\n", - "if avg_ratings_last_30_days < last_price:\n", - " body += f'

❌ Last closing price ({last_price}) > Average price ratings last 30 days ({avg_ratings_last_30_days})

'\n", - "else:\n", - " body += f'

✅ Average price ratings last 30 days ({avg_ratings_last_30_days}) > Last closing price ({last_price})

'\n", + "body += openbb.widgets.tablinks([\"SUMMARY\", \"Overview\", \"Analyst Opinions\", \"Fundamental Analysis\", \"Dark Pool and Shorts\", \"Technical Analysis\", \"Insider Trading\", \"Behavioural Analysis\", \"Quantitative Analysis\", \"Prediction Techniques\"])\n", "\n", - "if regression_slope > 0:\n", - " body += f'

✅ Regression on the last 30 market days ({regression_slope} dollars/market day) is positive

'\n", - "else:\n", - " body += f'

❌ Regression on the last 30 market days ({regression_slope} dollars/market day) is negative

'\n", - " \n", - "if rsi_value < 30:\n", - " body += f'

✅ RSI level is OVERSOLD. {rsi_value} < 30

'\n", - "elif rsi_value > 70:\n", - " body += f'

❌ RSI level is OVERBOUGHT. {rsi_value} > 70

'\n", - "else:\n", - " body += f'

🟡 RSI level is NORMAL. 30 < {rsi_value} < 70

'\n", - " \n", - "if last_10_insider_trading > 0:\n", - " body += f'

✅ Last 10 insider trading. {last_10_insider_trading} M was bought in value.

'\n", - "else:\n", - " body += f'

❌ Last 10 insider trading. {last_10_insider_trading} M was sold in value

'\n", - " \n", - "if finbrain_sentiment_val > .1:\n", - " body += f'

✅ Last FinBrain sentiment is BULLISH: {finbrain_sentiment_val}

'\n", - "elif finbrain_sentiment_val < -.1:\n", - " body += f'

❌ Last FinBrain sentiment is BEARISH: {finbrain_sentiment_val}

'\n", - "else:\n", - " body += f'

🟡 Last FinBrain sentiment is NEUTRAL: {finbrain_sentiment_val}

'\n", - " \n", - "if (regression_val - last_price) > 0:\n", - " body += f'

✅ Regression for next 20th market price ({regression_val}) > Last closing price ({last_price})

'\n", - "else:\n", - " body += f'

❌ Regression for next 20th market price ({regression_val}) < Last closing price ({last_price})

'\n", - " \n", - "body += '

Opinion:

'\n", - "body += '

'\n", - "body += '
'\n", + "htmlcode = openbb.widgets.h(3, \"KPIs\")\n", + "htmlcode += openbb.widgets.kpi([last_price], [\"Last closing price is above the average price ratings of last 30 days\", \"Average price ratings of last 30 day is above last closing price\"], avg_ratings_last_30_days)\n", + "htmlcode += openbb.widgets.kpi([0], [\"Regression (dollars per market day) on last 30 market days is negative\", \"Regression (dollars per market day) on last 30 market days is positive\"], regression_slope)\n", + "htmlcode += openbb.widgets.kpi([30, 70], [\"RSI level is oversold\", \"RSI level is normal\", \"RSI level is overbought\"], rsi_value) \n", + "htmlcode += openbb.widgets.kpi([0], [\"The sum of last 10 insider trading (in millions) was negative\", \"The sum of last 10 insider trading (in millions) was positive\"], last_10_insider_trading)\n", + "htmlcode += openbb.widgets.kpi([-.1, .1], [\"Last FinBrain sentiment is bearish\", \" Last FinBrain sentiment is neutral\", \"Last FinBrain sentiment is bullish\"], finbrain_sentiment_val) \n", + "htmlcode += openbb.widgets.kpi([0], [\"The regression for the next 20th market price is below closing price\", \"The regression for the next 20th market price is above closing price\"], round(regression_val - last_price, 2)) \n", + "body += openbb.widgets.add_tab(\"SUMMARY\", htmlcode)\n", "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([price_chart])\n", - "body += openbb.widgets.row([openbb.widgets.h(3, \"Description\") + openbb.widgets.p(overview)])\n", - "body += '
'\n", + "htmlcode = openbb.widgets.row([price_chart])\n", + "htmlcode += openbb.widgets.row([openbb.widgets.h(3, \"Description\") + openbb.widgets.p(overview)])\n", + "body += openbb.widgets.add_tab(\"Overview\", htmlcode)\n", "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([price_target_chart])\n", - "body += openbb.widgets.row([ratings_over_time_chart])\n", - "body += openbb.widgets.row([df_analyst.to_html()])\n", - "body += '
'\n", + "htmlcode = openbb.widgets.row([price_target_chart])\n", + "htmlcode += openbb.widgets.row([ratings_over_time_chart])\n", + "htmlcode += openbb.widgets.row([df_analyst.to_html()])\n", + "body += openbb.widgets.add_tab(\"Analyst Opinions\", htmlcode)\n", "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([openbb.widgets.h(3, \"Estimates\") + df_year_estimates.head().to_html()])\n", - "body += openbb.widgets.row([openbb.widgets.h(3, \"Earnings\") + df_quarter_earnings.head().to_html()])\n", - "body += openbb.widgets.row([openbb.widgets.h(3, \"Revenues\") + df_quarter_revenues.head().to_html()])\n", - "body += openbb.widgets.row([openbb.widgets.h(3, \"SEC filings\") + df_sec_filings.head().to_html()])\n", - "body += '
'\n", + "htmlcode = openbb.widgets.row([openbb.widgets.h(3, \"Estimates\") + df_year_estimates.head().to_html()])\n", + "htmlcode += openbb.widgets.row([openbb.widgets.h(3, \"Earnings\") + df_quarter_earnings.head().to_html()])\n", + "htmlcode += openbb.widgets.row([openbb.widgets.h(3, \"Revenues\") + df_quarter_revenues.head().to_html()])\n", + "htmlcode += openbb.widgets.row([openbb.widgets.h(3, \"SEC filings\") + df_sec_filings.head().to_html()])\n", + "body += openbb.widgets.add_tab(\"Fundamental Analysis\", htmlcode)\n", + " \n", + "htmlcode = openbb.widgets.row([net_short_position])\n", + "htmlcode += openbb.widgets.row([price_vs_short_interest])\n", + "htmlcode += openbb.widgets.row([dark_pools])\n", + "htmlcode += openbb.widgets.row([volexch])\n", + "body += openbb.widgets.add_tab(\"Dark Pool and Shorts\", htmlcode)\n", "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([net_short_position])\n", - "body += openbb.widgets.row([price_vs_short_interest])\n", - "body += openbb.widgets.row([dark_pools])\n", - "body += openbb.widgets.row([volexch])\n", - "body += '
'\n", + "body += openbb.widgets.add_tab(\"Technical Analysis\", openbb.widgets.row([ta_rsi]))\n", "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([ta_rsi])\n", - "body += '
'\n", + "htmlcode = openbb.widgets.row([openbb.widgets.h(3, \"Last Activity\") + df_insider.head(10).to_html(col_space='75px')])\n", + "body += openbb.widgets.add_tab(\"Insider Trading\", htmlcode)\n", "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([openbb.widgets.h(3, \"Last Activity\") + df_insider.head(10).to_html(col_space='75px')])\n", - "body += '
'\n", + "htmlcode = openbb.widgets.row([finbrain_sentiment])\n", + "htmlcode += openbb.widgets.row([snews])\n", + "htmlcode += openbb.widgets.row([openbb.widgets.h(3, \"Stocktwits\") + stocktwits_sentiment])\n", + "body += openbb.widgets.add_tab(\"Behavioural Analysis\", htmlcode)\n", "\n", + "htmlcode = openbb.widgets.row([bw_month])\n", + "htmlcode += openbb.widgets.row([bw_year])\n", + "body += openbb.widgets.add_tab(\"Quantitative Analysis\", htmlcode)\n", "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([finbrain_sentiment])\n", - "body += openbb.widgets.row([snews])\n", - "body += openbb.widgets.row([openbb.widgets.h(3, \"Stocktwits\") + stocktwits_sentiment])\n", - "body += '
'\n", + "htmlcode = openbb.widgets.row([regression])\n", + "htmlcode += openbb.widgets.row([mc])\n", + "body += openbb.widgets.add_tab(\"Prediction Techniques\", htmlcode)\n", "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([bw_month])\n", - "body += openbb.widgets.row([bw_year])\n", - "body += '
'\n", - "\n", - "body += '
'\n", - "body += '

No comment.

'\n", - "body += openbb.widgets.row([regression])\n", - "body += openbb.widgets.row([mc])\n", - "body += '
'\n", - "\n", - "\n", - "body += '''\n", - " '''\n", + "body += openbb.widgets.tab_clickable_evt()\n", "\n", "report = openbb.widgets.html_report(title=report_name, stylesheet=stylesheet, body=body)\n", + "\n", "# to save the results\n", "with open(report_name + \".html\", \"w\") as fh:\n", " fh.write(report)" @@ -745,7 +648,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c692b8cf-8b9f-420f-bc01-c7b9cc7e7dd4", + "id": "e15cef06-0d10-4153-b6d3-9762be0ed1dd", "metadata": {}, "outputs": [], "source": [] @@ -757,7 +660,8 @@ "hash": "aa1c4d436101635411b2afa2ce061827695b6e3d0efa7f05338cbf11ad26165e" }, "kernelspec": { - "display_name": "Python 3.8.12 64-bit ('gst': conda)", + "display_name": "Python 3 (ipykernel)", + "language": "python", "name": "python3" }, "language_info": { @@ -770,7 +674,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.8.6" } }, "nbformat": 4, diff --git a/openbb_terminal/jupyter/widget_helpers.py b/openbb_terminal/jupyter/widget_helpers.py index 090a5ce87ae..2d9ea2cecf6 100644 --- a/openbb_terminal/jupyter/widget_helpers.py +++ b/openbb_terminal/jupyter/widget_helpers.py @@ -75,23 +75,205 @@ def html_report(title: str = "", stylesheet: str = "", body: str = "") -> str: os.path.join(os.path.dirname(os.path.abspath(__file__)), "widgets", "report.j2") ) as f: template = Template(f.read()) - card = template.render(title=title, stylesheet=stylesheet, body=body) - return card + return template.render(title=title, stylesheet=stylesheet, body=body) def h(level: int, text: str) -> str: - """Wrap text into an HTML `h` tag.""" + """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"{text}" def p(text: str) -> str: - """Wrap text into an HTML `p` tag.""" + """Wrap text into an HTML `p` tag. + + Parameters + ---------- + text : str + Contents for HTML `p` tag + + Returns + ------- + str + HTML code as string + """ return f"

{text}

" 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'

❌ {sentences[0]}. {value} < {thresholds[0]}

' + return f'

✅ {sentences[1]}. {value} > {thresholds[0]}

' + if len(thresholds) == 2 and len(sentences) == 3: + if value < thresholds[0]: + return f'

❌ {sentences[0]}. {value} < {thresholds[0]}

' + if value > thresholds[1]: + return f'

✅ {sentences[2]}. {value} > {thresholds[1]}

' + return f'

🟡 {sentences[1]}. {thresholds[0]} < {value} < {thresholds[1]}

' + print("Error. KPI condition is not correctly set") + return "" + + +def add_tab(title: str, htmlcode: 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 + + Returns + ------- + str + HTML code as string + """ + return f"""

+

+ No comment. +

{htmlcode} +
""" + + +def tab_clickable_evt() -> str: + """Adds javascript code within HTML at the bottom that allows the interactivity with tabs. + + Returns + ------- + str + javascript code in HTML to process interactive tabs + """ + return """ + """ + + +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 = '
' + for idx, tab in enumerate(tabs): + htmlcode += f"""""" + if ((idx + 1) % 5) == 0: + htmlcode += "
" + htmlcode += "
" + return htmlcode + + +def header(img, author, report_date, report_time, report_tz, title) -> str: + """Creates reports header + + Parameters + ---------- + img : str + Image for customizable report + 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 + """ + return f""" +
+ {img} +
+

Analyst: {author}

+

Date : {report_date}

+

Time : {report_time} {report_tz}

+
+

{title}

+
+
"""