import streamlit as st import requests import pandas as pd from datetime import date import asyncio import aiohttp import os st.set_page_config(layout="wide") API_KEY = os.getenv("FMP_API_KEY") ######################################## # SYNCHRONOUS FUNCTION FOR LIVE FEED ######################################## @st.cache_data(show_spinner=False) def get_live_feed_data(limit, filing_type, from_date, to_date, is_done): params = { "apikey": API_KEY, "limit": limit, "from": from_date, "to": to_date, "isDone": str(is_done).lower() } if filing_type != "All": params["type"] = filing_type url = "https://financialmodelingprep.com/api/v4/rss_feed" response = requests.get(url, params=params) if response.status_code == 200: return pd.DataFrame(response.json()) else: st.error(f"Error fetching data (Status Code {response.status_code}).") return pd.DataFrame() ######################################## # ASYNCHRONOUS FUNCTIONS FOR 8-K FILINGS ######################################## async def fetch_8k_page(session, page, from_date, to_date, has_financial): params = { "apikey": API_KEY, "page": page, "from": from_date, "to": to_date, "hasFinancial": str(has_financial).lower() } url = "https://financialmodelingprep.com/api/v4/rss_feed_8k" async with session.get(url, params=params) as resp: if resp.status == 200: data = await resp.json() return pd.DataFrame(data) else: return pd.DataFrame() async def fetch_all_8k(pages_to_fetch, from_date, to_date, has_financial): async with aiohttp.ClientSession() as session: tasks = [fetch_8k_page(session, p, from_date, to_date, has_financial) for p in range(pages_to_fetch)] 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 / pages_to_fetch) return results ######################################## # ASYNCHRONOUS FUNCTIONS FOR COMPANY FILINGS ######################################## async def fetch_company_page(session, symbol, filing_type, page): params = { "apikey": API_KEY, "page": page, "type": filing_type } url = f"https://financialmodelingprep.com/api/v3/sec_filings/{symbol}" async with session.get(url, params=params) as resp: if resp.status == 200: data = await resp.json() return pd.DataFrame(data) else: return pd.DataFrame() async def fetch_all_company(symbol, filing_type, pages_to_fetch): async with aiohttp.ClientSession() as session: tasks = [fetch_company_page(session, symbol, filing_type, p) for p in range(pages_to_fetch)] 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 / pages_to_fetch) return results ######################################## # PAGE FUNCTIONS ######################################## def live_feed_page(): st.title("Live SEC Filings Feed") st.write( """ This page displays a list of recent SEC filings by public companies. Filings include annual reports (10-K), quarterly reports (10-Q), and other important updates. Use the filters to narrow down the list by filing type, date range, and whether the filing is complete. """ ) # Initialize session state if not set. if "live_feed_results" not in st.session_state: st.session_state.live_feed_results = None with st.sidebar: with st.expander("Live Feed Filter Parameters", expanded=True): filing_type = st.selectbox( "Filing Type", options=["All", "10-K", "10-Q", "8-K", "6-K"], help="Choose a specific filing type or 'All' for no filtering." ) from_date = st.date_input( "From Date", value=date(2025, 1, 1), help="Start date for the filings." ) to_date = st.date_input( "To Date", value=date.today(), help="End date for the filings." ) is_done = st.checkbox( "Completed Filings Only", value=True, help="Check to show only filings marked as completed." ) run_live = st.button("Run Live Feed Query") limit = 500 if run_live: st.session_state.live_feed_results = get_live_feed_data( limit, filing_type, from_date.isoformat(), to_date.isoformat(), is_done ) if st.session_state.live_feed_results is not None: st.write("### Live SEC Filings Data") st.dataframe(st.session_state.live_feed_results, use_container_width=True) def eight_k_page(): st.title("8-K Filings Specialized") st.write( """ This page displays 8-K filings from public companies. 8-K filings are reports companies file when major events occur. Use the filter below to show only filings that include financial information. """ ) if "eight_k_results" not in st.session_state: st.session_state.eight_k_results = None with st.sidebar: with st.expander("8-K Filter Parameters", expanded=True): from_date = st.date_input( "From Date (8-K)", value=date(2025, 1, 1), help="Start date for 8-K filings." ) to_date = st.date_input( "To Date (8-K)", value=date.today(), help="End date for 8-K filings." ) has_financial_option = st.selectbox( "Only Filings with Financial Data", options=["True", "False"], help="Select 'True' to display only filings that include financial statements." ) has_financial = has_financial_option.lower() == "true" run_8k = st.button("Run 8-K Query") pages_to_fetch = 15 if run_8k: results = asyncio.run( fetch_all_8k(pages_to_fetch, from_date.isoformat(), to_date.isoformat(), has_financial) ) dfs = [df for df in results if not df.empty] if dfs: df_all = pd.concat(dfs, ignore_index=True) st.session_state.eight_k_results = df_all else: st.session_state.eight_k_results = None st.warning("No data returned for the given parameters.") if st.session_state.eight_k_results is not None: st.write("### 8-K Filings Data") st.dataframe(st.session_state.eight_k_results, use_container_width=True) def company_specific_page(): st.title("Company Specific SEC Filings") st.write( """ This page displays filings for a specific company. Enter a company ticker (e.g., AAPL) and select a filing type (like 10-K or 10-Q) to view the reports. """ ) if "company_results" not in st.session_state: st.session_state.company_results = None if "company_symbol" not in st.session_state: st.session_state.company_symbol = None with st.sidebar: with st.expander("Company Filings Parameters", expanded=True): symbol = st.text_input( "Company Ticker", value="AAPL", help="Enter the ticker symbol of the company (e.g., AAPL)." ) filing_type = st.selectbox( "Filing Type", options=["10-K", "10-Q", "8-K", "6-K"], help="Select the type of filing to retrieve." ) run_company = st.button("Run Company Query") pages_to_fetch = 10 if run_company: if symbol.strip(): results = asyncio.run( fetch_all_company(symbol.upper(), filing_type, pages_to_fetch) ) dfs = [df for df in results if not df.empty] if dfs: df_all = pd.concat(dfs, ignore_index=True) st.session_state.company_results = df_all st.session_state.company_symbol = symbol.upper() else: st.session_state.company_results = None st.warning("No filings found for the given parameters.") else: st.warning("Please enter a valid company ticker.") if st.session_state.company_results is not None: st.write(f"### SEC Filings for {st.session_state.company_symbol}") st.dataframe(st.session_state.company_results, use_container_width=True) ######################################## # MAIN APPLICATION ######################################## def main(): st.sidebar.title("Input Parameters") page_selection = st.sidebar.radio( "Select a Page", ("Live Feed", "8-K Specialized", "Company Specific"), help="Navigate to the desired SEC filings page." ) if page_selection == "Live Feed": live_feed_page() elif page_selection == "8-K Specialized": eight_k_page() elif page_selection == "Company Specific": company_specific_page() if __name__ == "__main__": main() hide_streamlit_style = """ """ st.markdown(hide_streamlit_style, unsafe_allow_html=True)