Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import requests | |
| import pandas as pd | |
| import os | |
| import asyncio | |
| import aiohttp | |
| # Global API key and default parameters | |
| API_KEY = os.getenv("FMP_API_KEY") | |
| DEFAULT_COMPANY = "syros" | |
| NUM_PAGES = 10 # Backend variable: number of pages to fetch | |
| # Initialize session state run flags and inputs if not already set | |
| if "run_mna_feed" not in st.session_state: | |
| st.session_state.run_mna_feed = False | |
| if "run_mna_search" not in st.session_state: | |
| st.session_state.run_mna_search = False | |
| if "search_company" not in st.session_state: | |
| st.session_state.search_company = DEFAULT_COMPANY | |
| if "feed_date" not in st.session_state: | |
| st.session_state.feed_date = pd.to_datetime("2025-01-01").date() | |
| ############################################## | |
| # ASYNCHRONOUS FUNCTIONS FOR M&A FEED | |
| ############################################## | |
| async def fetch_mna_feed_page(session, page): | |
| url = f"https://financialmodelingprep.com/api/v4/mergers-acquisitions-rss-feed?page={page}&apikey={API_KEY}" | |
| try: | |
| async with session.get(url) as response: | |
| if response.status == 200: | |
| data = await response.json() | |
| return pd.DataFrame(data) | |
| else: | |
| return pd.DataFrame() | |
| except Exception: | |
| # Fail gracefully without exposing the data source | |
| return pd.DataFrame() | |
| async def fetch_all_mna_feed(num_pages=NUM_PAGES): | |
| async with aiohttp.ClientSession() as session: | |
| tasks = [fetch_mna_feed_page(session, page) for page in range(num_pages)] | |
| results = [] | |
| progress_bar = st.progress(0) | |
| completed = 0 | |
| for task in asyncio.as_completed(tasks): | |
| result = await task | |
| results.append(result) | |
| completed += 1 | |
| progress_bar.progress(completed / num_pages) | |
| return results | |
| def async_fetch_mna_feed(num_pages=NUM_PAGES) -> pd.DataFrame: | |
| results = asyncio.run(fetch_all_mna_feed(num_pages)) | |
| if results: | |
| df = pd.concat(results, ignore_index=True) | |
| if "transactionDate" in df.columns: | |
| df["transactionDate"] = pd.to_datetime(df["transactionDate"], errors="coerce") | |
| return df | |
| return pd.DataFrame() | |
| ############################################## | |
| # CACHED FUNCTION FOR M&A SEARCH | |
| ############################################## | |
| def fetch_mna_search(company_name: str) -> pd.DataFrame: | |
| """ | |
| Fetch M&A news filtered by company name using the search endpoint. | |
| """ | |
| url = f"https://financialmodelingprep.com/api/v4/mergers-acquisitions/search?name={company_name}&apikey={API_KEY}" | |
| try: | |
| response = requests.get(url) | |
| response.raise_for_status() | |
| data = response.json() | |
| except: | |
| return pd.DataFrame() | |
| if not data: | |
| return pd.DataFrame() | |
| return pd.DataFrame(data) | |
| ############################################## | |
| # MAIN APP | |
| ############################################## | |
| def main(): | |
| st.set_page_config(page_title="M&A Feed Dashboard", layout="wide") | |
| st.title("M&A Transaction Analysis") | |
| st.write( | |
| "This dashboard provides a real-time stream of Mergers & Acquisitions news and announcements. " | |
| "Use the side menu below to choose between viewing the full M&A live feed or searching for M&A news by company name." | |
| ) | |
| # Sidebar (inside an expander) for navigation and options | |
| with st.sidebar.expander("Navigation and Options", expanded=True): | |
| page = st.radio( | |
| "Select Page", | |
| ("M&A Feed", "M&A Search"), | |
| help="Choose 'M&A Feed' to view the complete RSS feed or 'M&A Search' to search for news by company name." | |
| ) | |
| if page == "M&A Feed": | |
| feed_date = st.date_input( | |
| "From Date", | |
| value=pd.to_datetime("2025-01-01").date(), | |
| help="Select a starting date. Only M&A transactions on or after this date will be shown." | |
| ) | |
| st.session_state.feed_date = feed_date | |
| if st.button("Run M&A Feed"): | |
| st.session_state.run_mna_feed = True | |
| else: | |
| company = st.text_input( | |
| "Company Name", | |
| value=DEFAULT_COMPANY, | |
| help="Enter the company name to search for M&A news (default is 'syros')." | |
| ) | |
| st.session_state.search_company = company | |
| if st.button("Run M&A Search"): | |
| st.session_state.run_mna_search = True | |
| # Display page content based on the selected page | |
| if page == "M&A Feed": | |
| st.header("M&A RSS Feed") | |
| st.write( | |
| "Below is the latest M&A live feed data filtered by transaction date. " | |
| "Only M&A transactions on or after the selected date are shown. " | |
| "The table displays details such as the acquiring company, target company, transaction date, and URL." | |
| ) | |
| if st.session_state.run_mna_feed: | |
| df_feed = async_fetch_mna_feed() | |
| if df_feed.empty: | |
| st.error("No data returned from the M&A feed.") | |
| else: | |
| if "transactionDate" in df_feed.columns: | |
| filtered_df = df_feed[df_feed["transactionDate"].dt.date >= st.session_state.feed_date] | |
| else: | |
| filtered_df = df_feed | |
| if filtered_df.empty: | |
| st.error("No M&A transactions found on or after the selected date.") | |
| else: | |
| st.dataframe(filtered_df, use_container_width=True) | |
| else: | |
| st.info("Click 'Run M&A Feed' in the sidebar to fetch data.") | |
| else: | |
| st.header("M&A Search") | |
| st.write( | |
| "Search for M&A news by company name. " | |
| "The table below displays the matching announcements, including details such as the acquiring company, " | |
| "target company, transaction date, and announcement URL." | |
| ) | |
| if st.session_state.run_mna_search: | |
| df_search = fetch_mna_search(st.session_state.search_company) | |
| if df_search.empty: | |
| st.error("No M&A news found for the specified company name.") | |
| else: | |
| st.dataframe(df_search, use_container_width=True) | |
| else: | |
| st.info("Enter a company name in the sidebar and click 'Run M&A Search' to fetch data.") | |
| if __name__ == "__main__": | |
| main() | |
| hide_streamlit_style = """ | |
| <style> | |
| #MainMenu {visibility: hidden;} | |
| footer {visibility: hidden;} | |
| </style> | |
| """ | |
| st.markdown(hide_streamlit_style, unsafe_allow_html=True) | |