diff options
author | Pratyush Shukla <ps4534@nyu.edu> | 2024-03-17 19:28:18 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-17 19:28:18 +0530 |
commit | d3b3fb5e503f0731749ed0e70c11e01900b42a84 (patch) | |
tree | 0d5dcbd529f255f5ae2e5d7007c97734912d0d2e | |
parent | 6aa2c297bde91fb0a7c9384803661a20ca7e204c (diff) | |
parent | 655b1c861fc38ff386b3d5c8b03d1d6214a0741a (diff) |
Merge branch 'develop' into bugfix/standard-paramsbugfix/standard-params
-rw-r--r-- | examples/README.md | 16 | ||||
-rw-r--r-- | examples/content.json | 6 | ||||
-rw-r--r-- | examples/streamlit/news.py | 452 | ||||
-rw-r--r-- | examples/streamlit/requirements.txt | 3 | ||||
-rw-r--r-- | examples/streamlit_news.webp | bin | 0 -> 9448 bytes |
5 files changed, 477 insertions, 0 deletions
diff --git a/examples/README.md b/examples/README.md index b50fc62499d..e7d5a583189 100644 --- a/examples/README.md +++ b/examples/README.md @@ -77,3 +77,19 @@ This notebook demonstrates how to calculate the implied earnings move using opti - Get the last price of the underlying stock. - Find the nearest call and put strikes to the last price of the stock. - Calculate the implied daily move using the price of a straddle. + +### streamlit/news + +This is an example Streamlit dashboard for news headlines with data from Biztoc, Benzinga, FMP, Intrinio, and Tiingo. + +:::warning +At least one API key is required. You can get a free Biztoc API key [here](https://rapidapi.com/thma/api/biztoc) +::: + +To run, copy the file to your system, open a terminal, navigate to where the file is, and with your `obb` Python environment active, enter: + +``` +pip install streamlit +pip install openbb-biztoc +streamlit run news.py +``` diff --git a/examples/content.json b/examples/content.json index fd257a4a4be..ff855e3e74e 100644 --- a/examples/content.json +++ b/examples/content.json @@ -47,5 +47,11 @@ "img": "https://raw.githubusercontent.com/OpenBB-finance/OpenBBTerminal/develop/examples/impliedEarningsMove.webp", "description": "Calculate the implied earnings move using options prices. This notebook demonstrates how to get the data from free sources and apply filters to arrive at the expected move, as a percent, in either direction." + }, + { + "title": "Streamlit News Headlines", + "url": "https://github.com/OpenBB-finance/OpenBBTerminal/blob/develop/examples/streamlit/news.py", + "img": "https://raw.githubusercontent.com/OpenBB-finance/OpenBBTerminal/develop/examples/streamlit_news.webp", + "description": "An example Streamlit dashboard for news headlines with data from Biztoc, Benzinga, FMP, Intrinio, and Tiingo." } ] diff --git a/examples/streamlit/news.py b/examples/streamlit/news.py new file mode 100644 index 00000000000..d4113a4dfcd --- /dev/null +++ b/examples/streamlit/news.py @@ -0,0 +1,452 @@ +"""Streamlit News Page""" + +# flake8: noqa: I001 + +from datetime import datetime, timedelta + +from openbb import obb +from openbb_biztoc.utils.helpers import get_all_tags, get_sources + +import streamlit as st + +st.set_page_config( + layout="wide", + page_title="News", + initial_sidebar_state="expanded", +) + +st.sidebar.markdown( + """ +<style> +section[data-testid="stSidebar"] { + top: 1% !important; + height: 98.25% !important; + left: 0.33% !important; + margin-top: 0 !important; +} +section[data-testid="stSidebar"] img { + margin-top: -75px !important; + margin-left: -10px !important; + width: 95% !important; +} +section[data-testid="stVerticalBlock"] { + gap: 0rem; +} +body { + line-height: 1.2; +} +</style> +<figure style='text-align: center;'> + <img src='https://openbb.co/assets/images/ogimages/Homepage.png' /> + <figcaption style='font-size: 0.8em; color: #888;'>Powered by Open Source</figcaption> +</figure> +""", + unsafe_allow_html=True, +) + + +button_pressed = False + +SUPPORTED_SOURCES = ["benzinga", "biztoc", "intrinio", "fmp", "tiingo"] + +providers = [ + d + for d in list(obb.user.credentials.__dict__.keys()) # type: ignore + if obb.user.credentials.__dict__[d] is not None # type: ignore +] +providers = [d.split("_")[0] for d in providers if d.split("_")[0] in SUPPORTED_SOURCES] +news_sources = [d.upper() if d == "fmp" else d.title() for d in providers] + +if "news" not in st.session_state: + st.session_state.news = None +if "biztoc_tags" not in st.session_state: + st.session_state.biztoc_tags = [] +try: + _all_tags = [] + _biztoc_tags = get_all_tags(api_key=obb.user.credentials.biztoc_api_key.get_secret_value()) # type: ignore + for key, value in _biztoc_tags.items(): + _all_tags.extend(_biztoc_tags[key]) + st.session_state.biztoc_tags = _all_tags +except Exception: + st.session_state.biztoc_tags = [] +try: + _sources = get_sources(api_key=obb.user.credentials.biztoc_api_key.get_secret_value()) # type: ignore + st.session_state.biztoc_sources = [d["id"] for d in _sources] +except Exception: + st.session_state.biztoc_sources = [] + +if "biztoc_sources" not in st.session_state: + st.session_state.biztoc_sources = [] +if "news_container" not in st.session_state: + st.session_state.news_container = st.empty() +if "selected_limit" not in st.session_state: + st.session_state.selected_limit = 100 +if "selected_provider" not in st.session_state: + if len(news_sources) == 0: + st.error( + f"No news sources available. Please check your credentials for one of: {SUPPORTED_SOURCES}" + ) + st.stop() + if len(news_sources) > 0: + st.session_state.selected_provider = ( + "Biztoc" if "Biztoc" in news_sources else news_sources[0] + ) +if "selected_tags" not in st.session_state: + st.session_state.selected_tags = "" +if "selected_term" not in st.session_state: + st.session_state.selected_term = "" +if "news_start_date" not in st.session_state: + st.session_state.news_start_date = (datetime.now() - timedelta(days=2)).date() +if "news_end_date" not in st.session_state: + st.session_state.news_end_date = datetime.now().date() +if "selected_biztoc_source" not in st.session_state: + st.session_state.selected_biztoc_source = "" +if "content_type" not in st.session_state: + st.session_state.content_type = "news" +if "benzinga_tickers" not in st.session_state: + st.session_state.benzinga_tickers = "" +if "selected_benzinga_channel" not in st.session_state: + st.session_state.selected_benzinga_channel = "" +if "fmp_tickers" not in st.session_state: + st.session_state.fmp_tickers = "" +if "intrinio_tickers" not in st.session_state: + st.session_state.intrinio_tickers = "" +if "tiingo_tickers" not in st.session_state: + st.session_state.tiingo_tickers = "" +if "tiingo_source" not in st.session_state: + st.session_state.tiingo_source = "" + + +def fetch_openbb(): + kwargs = { + "provider": st.session_state.selected_provider.lower(), + "limit": st.session_state.selected_limit, + } + if st.session_state.selected_provider == "Benzinga": + kwargs["start_date"] = st.session_state.news_start_date.strftime("%Y-%m-%d") + kwargs["end_date"] = st.session_state.news_end_date.strftime("%Y-%m-%d") + kwargs["topics"] = st.session_state.selected_tags + kwargs["display"] = "full" + kwargs["page_size"] = 100 + kwargs["channels"] = ( + st.session_state.selected_benzinga_channel.lower() + if st.session_state.selected_benzinga_channel + else None + ) + kwargs["symbol"] = ( + st.session_state.benzinga_tickers + if st.session_state.benzinga_tickers + else None + ) + + if st.session_state.selected_provider == "Biztoc": + kwargs["term"] = st.session_state.selected_term + kwargs["tag"] = st.session_state.selected_tags + kwargs["filter"] = "tag" if kwargs.get("tag") else None + if kwargs.get("filter") is None: + kwargs["filter"] = "latest" + kwargs["source"] = st.session_state.selected_biztoc_source + kwargs["filter"] = "source" if kwargs.get("source") else kwargs.get("filter") + if kwargs.get("filter") == "source": + kwargs.pop("tag") + + if st.session_state.selected_provider == "FMP": + kwargs["symbol"] = ( + st.session_state.fmp_tickers if st.session_state.fmp_tickers else None + ) + + if st.session_state.selected_provider == "Intrinio": + kwargs["symbol"] = ( + st.session_state.intrinio_tickers + if st.session_state.intrinio_tickers + else None + ) + + if st.session_state.selected_provider == "Tiingo": + kwargs["start_date"] = st.session_state.news_start_date.strftime("%Y-%m-%d") + kwargs["end_date"] = st.session_state.news_end_date.strftime("%Y-%m-%d") + kwargs["symbol"] = ( + st.session_state.tiingo_tickers if st.session_state.tiingo_tickers else None + ) + + kwargs = {key: value for key, value in kwargs.items() if value is not None} + + data = ( + obb.news.company(**kwargs) # type: ignore + if kwargs.get("symbol") + else obb.news.world(**kwargs) # type: ignore + ) + if data.results != []: + return data.to_df().sort_index(ascending=False).reset_index() + + +def update_data(): + st.session_state.news = fetch_openbb() + + +with st.sidebar: + c1, c2 = st.columns(2) + with c1: + old_start_date = st.session_state.news_start_date + old_provider = st.session_state.selected_provider + st.session_state.selected_provider = st.selectbox( + label="Provider", + options=news_sources, + index=news_sources.index(st.session_state.selected_provider), + ) + old_tags = st.session_state.selected_tags + if st.session_state.selected_provider == "Benzinga": + st.session_state.news_start_date = st.date_input( + "Start Date", value=old_start_date + ) + st.session_state.selected_tags = st.text_input( + label="Tag", value=st.session_state.selected_tags + ) + old_biztoc_tags = st.session_state.biztoc_tags + old_biztoc_source = st.session_state.selected_biztoc_source + if st.session_state.selected_provider == "Biztoc": + st.session_state.selected_tags = st.selectbox( + label="Tag", options=[None] + old_biztoc_tags + ) + st.session_state.selected_biztoc_source = st.selectbox( + label="Source", options=[None] + st.session_state.biztoc_sources + ) + old_benzinga_tickers = st.session_state.benzinga_tickers + if st.session_state.selected_provider == "Benzinga": + st.session_state.benzinga_tickers = st.text_input( + label="Tickers", value=old_benzinga_tickers + ) + old_fmp_tickers = st.session_state.fmp_tickers + if st.session_state.selected_provider == "FMP": + st.session_state.fmp_tickers = st.text_input( + label="Tickers", value=old_fmp_tickers + ) + old_intrinio_tickers = st.session_state.intrinio_tickers + if st.session_state.selected_provider == "Intrinio": + st.session_state.intrinio_tickers = st.text_input( + label="Tickers", value=old_intrinio_tickers + ) + old_tiingo_tickers = st.session_state.tiingo_tickers + if st.session_state.selected_provider == "Tiingo": + st.session_state.news_start_date = st.date_input( + "Start Date", value=old_start_date + ) + old_tiingo_tickers = st.session_state.tiingo_tickers + st.session_state.tiingo_tickers = st.text_input( + label="Tickers", value=st.session_state.tiingo_tickers + ) + with c2: + old_limit = st.session_state.selected_limit + old_end_date = st.session_state.news_end_date + st.session_state.selected_limit = st.number_input( + "Number of Stories", min_value=1, value=100 + ) + old_channel = st.session_state.selected_benzinga_channel + if st.session_state.selected_provider == "Benzinga": + st.session_state.news_end_date = st.date_input( + "End Date", value=old_end_date + ) + st.session_state.selected_benzinga_channel = st.text_input( + label="Feed Channel", value=old_channel + ) + old_term = st.session_state.selected_term + if st.session_state.selected_provider == "Biztoc": + st.session_state.selected_term = st.text_input( + label="Search Term", value=old_term + ) + if st.session_state.selected_provider == "Tiingo": + st.session_state.news_end_date = st.date_input( + "End Date", value=old_end_date + ) + + if any( + [ + old_start_date != st.session_state.news_start_date, + old_end_date != st.session_state.news_end_date, + old_limit != st.session_state.selected_limit, + old_provider != st.session_state.selected_provider, + old_tags != st.session_state.selected_tags, + old_term != st.session_state.selected_term, + old_biztoc_source != st.session_state.selected_biztoc_source, + old_channel != st.session_state.selected_benzinga_channel, + old_benzinga_tickers != st.session_state.benzinga_tickers, + old_fmp_tickers != st.session_state.fmp_tickers, + old_intrinio_tickers != st.session_state.intrinio_tickers, + old_tiingo_tickers != st.session_state.tiingo_tickers, + ] + ): + update_data() + + if st.button("Fetch Data"): + update_data() + + +def main(): + with st.session_state.news_container.container(): + st.markdown( + " <style> div[class^='block-container'] { padding-top: 1rem; } h1 { margin-bottom: -50px; } </style> " + "<h1 style='text-align: center;'>Headlines and Stories</h1> ", + unsafe_allow_html=True, + ) + st.divider() + if st.session_state.news is not None: + story = -1 + expanded = False + for i in st.session_state.news.index: + story += 1 + expanded = story == 0 + text = ( + st.session_state.news.loc[i].text + if "text" in st.session_state.news.loc[i] + else st.session_state.news.loc[i].get("title") + ) + src = st.session_state.news.loc[i].url + date = str(st.session_state.news.loc[i].date) + title = st.session_state.news.loc[i].title + if text != "": + with st.expander(label=f"{date} - {title}", expanded=expanded): + st.markdown( + f""" + <div style='max-width: 90%; margin: auto; word-wrap: break-word;'> + <h2 style='text-align: center;'>{title}</h2> + </div> + """, + unsafe_allow_html=True, + ) + + if st.session_state.selected_provider == "Benzinga": + _tags = ( + st.session_state.news.loc[i].tags + if st.session_state.news.loc[i].get("tags") + else "" + ) + _stocks = ( + st.session_state.news.loc[i].stocks + if st.session_state.news.loc[i].get("stocks") + else "" + ) + _channels = ( + st.session_state.news.loc[i].channels + if st.session_state.news.loc[i].get("channels") + else "" + ) + _images = ( + st.session_state.news.loc[i].images + if st.session_state.news.loc[i].get("images") + else [] + ) + _url = st.session_state.news.loc[i].url + st.markdown( + """ + <style> + img { + max-width: 98%; + height: auto; + margin: auto; + } + </style> + """, + unsafe_allow_html=True, + ) + if _images: + img = _images[0].get("url") + if img is not None: + st.markdown( + f"<div style='text-align: center;'><img src='{img}'></div><br></br>", + unsafe_allow_html=True, + ) + if text is not None: + st.markdown(text, unsafe_allow_html=True) + st.divider() + st.write(_url) + if _tags: + st.markdown( + f"##### Tags for this story: \n {_tags} \n" + ) + if _stocks: + st.markdown(f"##### Stocks mentioned:\n {_stocks} \n") + if _channels: + st.markdown( + f"##### Channels for this story: \n {_channels} \n" + ) + + if st.session_state.selected_provider == "Biztoc": + if st.session_state.news.loc[i].get("images"): + img = st.session_state.news.loc[i].images.get("s") + img = ( + st.session_state.news.loc[i].images.get("o") + if img is None + else img + ) + if img is not None: + st.markdown( + f"<div style='text-align: center;'><img src='{img}'></div><br></br>", + unsafe_allow_html=True, + ) + if text: + st.markdown(text, unsafe_allow_html=True) + st.write(src) + _story_tags = st.session_state.news.loc[i].get("tags") + _story_tags = ",".join(_story_tags) if _story_tags else "" + if _story_tags: + st.divider() + st.markdown( + f"##### Tags for this story: \n {_story_tags} \n\n" + ) + + if st.session_state.selected_provider == "Intrinio": + _tags = st.session_state.news.loc[i].get("tags") + _stocks = ( + st.session_state.news.loc[i]["company"].get("ticker") + if st.session_state.news.loc[i].get("company") + else None + ) + _images = st.session_state.news.loc[i].get("images") + _url = st.session_state.news.loc[i].get("url") + st.markdown(text, unsafe_allow_html=True) + if _url: + st.write(_url) + if _stocks: + st.divider() + st.markdown(f"##### Stocks mentioned:\n {_stocks} \n") + + if st.session_state.selected_provider == "FMP": + _url = st.session_state.news.loc[i].get("url") + _images = st.session_state.news.loc[i].get("images") + img = _images[0].get("o") if _images else None + if img is not None: + st.markdown( + f""" + <div style='text-align: center;'> + <img src='{img}' width='95%' /> + </div> + <br> + """, + unsafe_allow_html=True, + ) + st.markdown(text, unsafe_allow_html=True) + if _url: + st.write(_url) + + if st.session_state.selected_provider == "Tiingo": + _url = st.session_state.news.loc[i].get("url") + _tags = st.session_state.news.loc[i].get("tags") + _stocks = st.session_state.news.loc[i].get("symbols") + if _url: + st.write(_url) + st.divider() + if _tags: + st.markdown( + f"##### Tags for this story: \n {_tags} \n" + ) + if _stocks: + st.markdown(f"##### Stocks mentioned:\n {_stocks} \n") + + st.divider() + st.write( + "Learn more about the OpenBB Platform [here](https://docs.openbb.co/platform)" + ) + + +if __name__ == "__main__": + main() diff --git a/examples/streamlit/requirements.txt b/examples/streamlit/requirements.txt new file mode 100644 index 00000000000..56144ee2bd9 --- /dev/null +++ b/examples/streamlit/requirements.txt @@ -0,0 +1,3 @@ +streamlit +openbb +openbb-biztoc
\ No newline at end of file diff --git a/examples/streamlit_news.webp b/examples/streamlit_news.webp Binary files differnew file mode 100644 index 00000000000..1e9abedf2be --- /dev/null +++ b/examples/streamlit_news.webp |