File size: 9,787 Bytes
70dc5cc
 
 
 
 
 
d7033ec
70dc5cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67169c8
 
70dc5cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67169c8
 
70dc5cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67169c8
 
 
 
 
70dc5cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67169c8
70dc5cc
67169c8
 
 
 
 
70dc5cc
67169c8
70dc5cc
 
 
 
 
 
67169c8
 
70dc5cc
 
67169c8
 
 
 
70dc5cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67169c8
 
70dc5cc
67169c8
 
 
70dc5cc
 
 
67169c8
70dc5cc
67169c8
70dc5cc
 
67169c8
 
 
 
70dc5cc
 
 
 
 
 
 
 
67169c8
 
 
 
 
 
70dc5cc
 
 
 
 
 
 
 
 
 
 
 
 
 
67169c8
70dc5cc
 
67169c8
 
 
70dc5cc
 
 
67169c8
 
70dc5cc
67169c8
70dc5cc
 
 
 
67169c8
 
 
 
70dc5cc
 
 
 
 
 
 
 
 
 
 
67169c8
70dc5cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67169c8
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
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 = """
<style>
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
</style>
"""
st.markdown(hide_streamlit_style, unsafe_allow_html=True)