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)