Spaces:
Sleeping
Sleeping
File size: 6,613 Bytes
93e192b 1acda85 8c7c777 93e192b 8c7c777 93e192b 8c7c777 93e192b 8c7c777 93e192b eb16aa2 93e192b 528380b 93e192b da6ae15 93e192b da6ae15 93e192b 8c7c777 93e192b fe9c26b eb16aa2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | 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
##############################################
@st.cache_data(show_spinner=False)
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)
|