QuantumLearner commited on
Commit
c071b61
·
verified ·
1 Parent(s): 97b4e4b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +714 -0
app.py ADDED
@@ -0,0 +1,714 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # insider_trading_app.py
2
+
3
+ import streamlit as st
4
+ import requests
5
+ import pandas as pd
6
+ import plotly.graph_objects as go
7
+ import plotly.express as px
8
+
9
+ # ----------------------------
10
+ # Configuration
11
+ # ----------------------------
12
+
13
+ API_KEY = "b431ec171262073909ebf8c0c4afba71" # Hardcoded API Key
14
+ API_ENDPOINT_INSIDER_TRADING = "https://financialmodelingprep.com/api/v4/insider-trading"
15
+ API_ENDPOINT_TRADE_STATISTICS = "https://financialmodelingprep.com/api/v4/insider-roster-statistic" # Corrected endpoint
16
+
17
+ TOTAL_PAGES_LIVE_FEED = 50 # Fixed number of pages to fetch
18
+ DEFAULT_TOP_N = 5 # Default number of top traded securities to display
19
+
20
+ # ----------------------------
21
+ # Page Configuration
22
+ # ----------------------------
23
+
24
+ st.set_page_config(
25
+ page_title="Insider Trading Analysis",
26
+ layout="wide",
27
+ initial_sidebar_state="expanded",
28
+ )
29
+
30
+ # Initialize session state for both pages
31
+ if 'ticker_insider_trades' not in st.session_state:
32
+ st.session_state['ticker_insider_trades'] = {}
33
+ if 'insider_trades_live_feed' not in st.session_state:
34
+ st.session_state['insider_trades_live_feed'] = {}
35
+
36
+ # Sidebar for page navigation and inputs
37
+ st.sidebar.title("Input Parameters")
38
+
39
+ with st.sidebar.expander("Pages", expanded=True):
40
+ page = st.radio("Select Page", ["Ticker Insider Trades", "Insider Trades Live Feed"])
41
+
42
+ # ----------------------------
43
+ # Helper Functions
44
+ # ----------------------------
45
+
46
+ def get_insider_trading_data(symbol):
47
+ base_url = "https://financialmodelingprep.com/api/v4"
48
+
49
+ # Get the latest transactions table
50
+ transactions_endpoint = f"{base_url}/insider-trading"
51
+ transactions_params = {"symbol": symbol, "page": 0, "apikey": API_KEY}
52
+ transactions_response = requests.get(transactions_endpoint, params=transactions_params)
53
+ transactions_data = transactions_response.json()
54
+
55
+ # Convert transactions data to a DataFrame
56
+ transactions_df = pd.DataFrame(transactions_data)
57
+
58
+ # Get the trade statistics over time
59
+ statistics_endpoint = f"{base_url}/insider-roaster-statistic"
60
+ statistics_params = {"symbol": symbol, "apikey": API_KEY}
61
+ statistics_response = requests.get(statistics_endpoint, params=statistics_params)
62
+ statistics_data = statistics_response.json()
63
+
64
+ # Convert statistics data to a DataFrame
65
+ statistics_df = pd.DataFrame(statistics_data)
66
+
67
+ return transactions_df, statistics_df
68
+
69
+ def fetch_insider_trading_live_feed():
70
+ all_data = []
71
+ print(f"Starting to fetch live feed data from {TOTAL_PAGES_LIVE_FEED} pages.")
72
+ for page_num in range(1, TOTAL_PAGES_LIVE_FEED + 1):
73
+ params = {
74
+ 'apikey': API_KEY,
75
+ 'page': page_num
76
+ }
77
+ try:
78
+ response = requests.get(API_ENDPOINT_INSIDER_TRADING, params=params)
79
+ print(f"Fetching page {page_num}: Status Code {response.status_code}")
80
+ response.raise_for_status()
81
+ data = response.json()
82
+ print(f"Page {page_num} returned {len(data)} records.")
83
+ if not data:
84
+ print(f"No data returned for page {page_num}. Stopping pagination.")
85
+ break # Stop if no more data
86
+ all_data.extend(data)
87
+ except requests.exceptions.RequestException as e:
88
+ print(f"Error fetching page {page_num}: {e}")
89
+ continue # Skip to next page on error
90
+ if not all_data:
91
+ raise ValueError("No data fetched from the API.")
92
+ print(f"Total records fetched: {len(all_data)}")
93
+ return pd.DataFrame(all_data)
94
+
95
+ def create_monthly_transactions_chart(transactions_df):
96
+ transactions_df['transactionDate'] = pd.to_datetime(transactions_df['transactionDate'])
97
+ transactions_df['transactionMonth'] = transactions_df['transactionDate'].dt.to_period('M').dt.to_timestamp()
98
+
99
+ agg_data = transactions_df.groupby(['transactionMonth', 'acquistionOrDisposition']).agg({
100
+ 'transactionDate': 'count', # Count of transactions
101
+ 'securitiesTransacted': 'sum' # Sum of securities transacted
102
+ }).reset_index()
103
+
104
+ d_data = agg_data[agg_data['acquistionOrDisposition'] == 'D']
105
+ a_data = agg_data[agg_data['acquistionOrDisposition'] == 'A']
106
+
107
+ fig = go.Figure()
108
+
109
+ # Add line traces for count of transactions over time
110
+ fig.add_trace(go.Scatter(
111
+ x=d_data['transactionMonth'],
112
+ y=d_data['transactionDate'],
113
+ mode='lines+markers+text',
114
+ name='Disposition Transactions (Count)',
115
+ line=dict(color='red'),
116
+ text=d_data['transactionDate'],
117
+ textposition='top center'
118
+ ))
119
+
120
+ fig.add_trace(go.Scatter(
121
+ x=a_data['transactionMonth'],
122
+ y=a_data['transactionDate'],
123
+ mode='lines+markers+text',
124
+ name='Acquisition Transactions (Count)',
125
+ line=dict(color='green'),
126
+ text=a_data['transactionDate'],
127
+ textposition='top center'
128
+ ))
129
+
130
+ # Add bar traces for securities transacted
131
+ fig.add_trace(go.Bar(
132
+ x=d_data['transactionMonth'],
133
+ y=d_data['securitiesTransacted'],
134
+ name='Disposition Securities (Volume)',
135
+ marker_color='red',
136
+ yaxis='y2',
137
+ text=d_data['securitiesTransacted'],
138
+ textposition='auto'
139
+ ))
140
+
141
+ fig.add_trace(go.Bar(
142
+ x=a_data['transactionMonth'],
143
+ y=a_data['securitiesTransacted'],
144
+ name='Acquisition Securities (Volume)',
145
+ marker_color='green',
146
+ yaxis='y2',
147
+ text=a_data['securitiesTransacted'],
148
+ textposition='auto'
149
+ ))
150
+
151
+ # Update layout for dual y-axes
152
+ fig.update_layout(
153
+ title='Insider Trading Activity: Monthly Transactions and Securities Transacted (Count vs Volume)',
154
+ xaxis_title='Transaction Month',
155
+ yaxis=dict(title='Number of Transactions (Count)'),
156
+ yaxis2=dict(title='Securities Transacted (Volume)', overlaying='y', side='right'),
157
+ barmode='group',
158
+ legend_title='Legend',
159
+ template='plotly_white',
160
+ font=dict(size=12),
161
+ title_font=dict(size=16),
162
+ hovermode='x unified'
163
+ )
164
+
165
+ return fig
166
+
167
+ def create_trade_statistics_over_time_chart(trade_statistics_df):
168
+ trade_statistics_df['time'] = trade_statistics_df['year'].astype(str) + ' Q' + trade_statistics_df['quarter'].astype(str)
169
+ trade_statistics_df['datetime'] = pd.to_datetime(trade_statistics_df['year'].astype(str) + '-Q' + trade_statistics_df['quarter'].astype(str))
170
+ trade_statistics_df = trade_statistics_df.sort_values(by='datetime')
171
+
172
+ fig1 = go.Figure()
173
+
174
+ fig1.add_trace(go.Scatter(
175
+ x=trade_statistics_df['time'],
176
+ y=trade_statistics_df['purchases'],
177
+ mode='lines+markers',
178
+ name='Purchases',
179
+ line=dict(color='blue')
180
+ ))
181
+
182
+ fig1.add_trace(go.Scatter(
183
+ x=trade_statistics_df['time'],
184
+ y=trade_statistics_df['sales'],
185
+ mode='lines+markers',
186
+ name='Sales',
187
+ line=dict(color='orange')
188
+ ))
189
+
190
+ fig1.add_trace(go.Scatter(
191
+ x=trade_statistics_df['time'],
192
+ y=trade_statistics_df['buySellRatio'],
193
+ mode='lines+markers',
194
+ name='Buy/Sell Ratio',
195
+ line=dict(color='purple'),
196
+ yaxis='y2'
197
+ ))
198
+
199
+ # Update layout for dual y-axes
200
+ fig1.update_layout(
201
+ title='Trade Statistics: Purchases, Sales, and Buy/Sell Ratio Over Time',
202
+ xaxis=dict(title='Time (Year and Quarter)', tickmode='linear'),
203
+ yaxis=dict(title='Count (Purchases/Sales)'),
204
+ yaxis2=dict(title='Buy/Sell Ratio', overlaying='y', side='right'),
205
+ legend_title='Legend',
206
+ template='plotly_white',
207
+ font=dict(size=12),
208
+ title_font=dict(size=16),
209
+ hovermode='x unified'
210
+ )
211
+
212
+ return fig1
213
+
214
+ def create_total_avg_bought_sold_chart(trade_statistics_df):
215
+ trade_statistics_df = trade_statistics_df.sort_values(by=['year', 'quarter'], ascending=True)
216
+ trade_statistics_df['avgBuySellRatio'] = trade_statistics_df['averageBought'] / trade_statistics_df['averageSold']
217
+
218
+ fig2 = go.Figure()
219
+
220
+ fig2.add_trace(go.Bar(
221
+ x=trade_statistics_df['time'],
222
+ y=trade_statistics_df['totalBought'],
223
+ name='Total Bought',
224
+ marker_color='green'
225
+ ))
226
+
227
+ fig2.add_trace(go.Bar(
228
+ x=trade_statistics_df['time'],
229
+ y=trade_statistics_df['totalSold'],
230
+ name='Total Sold',
231
+ marker_color='red'
232
+ ))
233
+
234
+ fig2.add_trace(go.Scatter(
235
+ x=trade_statistics_df['time'],
236
+ y=trade_statistics_df['averageBought'],
237
+ mode='lines+markers',
238
+ name='Average Bought',
239
+ line=dict(color='blue')
240
+ ))
241
+
242
+ fig2.add_trace(go.Scatter(
243
+ x=trade_statistics_df['time'],
244
+ y=trade_statistics_df['averageSold'],
245
+ mode='lines+markers',
246
+ name='Average Sold',
247
+ line=dict(color='orange')
248
+ ))
249
+
250
+ fig2.add_trace(go.Scatter(
251
+ x=trade_statistics_df['time'],
252
+ y=trade_statistics_df['avgBuySellRatio'],
253
+ mode='lines+markers',
254
+ name='Average Buy/Sell Ratio',
255
+ line=dict(color='purple'),
256
+ yaxis='y2'
257
+ ))
258
+
259
+ # Update layout for dual y-axes
260
+ fig2.update_layout(
261
+ title='Trade Statistics: Total and Average Bought/Sold with Average Buy/Sell Ratio Over Time',
262
+ xaxis=dict(title='Time (Year and Quarter)', tickmode='linear'),
263
+ yaxis=dict(title='Values (Total/Average Bought/Sold)'),
264
+ yaxis2=dict(title='Average Buy/Sell Ratio', overlaying='y', side='right'),
265
+ barmode='group',
266
+ legend_title='Legend',
267
+ template='plotly_white',
268
+ font=dict(size=12),
269
+ title_font=dict(size=16),
270
+ hovermode='x unified'
271
+ )
272
+
273
+ return fig2
274
+
275
+ def create_daily_counts_chart(df):
276
+ df['filingDate'] = pd.to_datetime(df['filingDate']).dt.date
277
+
278
+ aggregation = df.groupby(['filingDate', 'acquistionOrDisposition']).size().unstack(fill_value=0).reset_index()
279
+ aggregation = aggregation.rename(columns={
280
+ 'A': 'Acquisition',
281
+ 'D': 'Disposition'
282
+ })
283
+
284
+ for col in ['Acquisition', 'Disposition']:
285
+ if col not in aggregation.columns:
286
+ aggregation[col] = 0
287
+
288
+ min_date = aggregation['filingDate'].min()
289
+ max_date = aggregation['filingDate'].max()
290
+ all_dates = pd.DataFrame({'filingDate': pd.date_range(start=min_date, end=max_date)})
291
+ all_dates['filingDate'] = pd.to_datetime(all_dates['filingDate']).dt.date
292
+ daily_counts = all_dates.merge(aggregation, on='filingDate', how='left').fillna(0)
293
+ daily_counts[['Acquisition', 'Disposition']] = daily_counts[['Acquisition', 'Disposition']].astype(int)
294
+
295
+ fig_daily = px.bar(
296
+ daily_counts,
297
+ x='filingDate',
298
+ y=['Acquisition', 'Disposition'],
299
+ title='Daily Counts of Acquisitions (A) and Dispositions (D)',
300
+ labels={'filingDate': 'Filing Date', 'value': 'Count'},
301
+ barmode='group',
302
+ color_discrete_sequence=['#1f77b4', '#ff7f0e']
303
+ )
304
+
305
+ fig_daily.update_traces(
306
+ texttemplate='%{y}',
307
+ textposition='outside'
308
+ )
309
+
310
+ fig_daily.update_layout(
311
+ xaxis_title='Filing Date',
312
+ yaxis_title='Count',
313
+ uniformtext_minsize=8,
314
+ uniformtext_mode='hide',
315
+ legend=dict(
316
+ orientation="h",
317
+ yanchor="bottom",
318
+ y=1.02,
319
+ xanchor="right",
320
+ x=1
321
+ ),
322
+ margin=dict(t=50, b=50),
323
+ template='plotly_white',
324
+ font=dict(size=12),
325
+ title_font=dict(size=16),
326
+ hovermode='x unified'
327
+ )
328
+
329
+ return fig_daily
330
+
331
+ def create_top_bought_chart(df, top_n):
332
+ security_stats = df.groupby(['symbol', 'acquistionOrDisposition']).agg(
333
+ Transaction_Count=('acquistionOrDisposition', 'size'),
334
+ Total_Securities=('securitiesTransacted', 'sum')
335
+ ).unstack(fill_value=0).reset_index()
336
+
337
+ security_stats.columns = ['symbol'] + [f"{stat}_{action}" for stat, action in security_stats.columns if stat != 'symbol']
338
+
339
+ required_columns = ['Transaction_Count_A', 'Transaction_Count_D', 'Total_Securities_A', 'Total_Securities_D']
340
+ for col in required_columns:
341
+ if col not in security_stats.columns:
342
+ security_stats[col] = 0
343
+
344
+ security_stats = security_stats.rename(columns={
345
+ 'Transaction_Count_A': 'Acquisition',
346
+ 'Transaction_Count_D': 'Disposition',
347
+ 'Total_Securities_A': 'Total_Securities_Bought',
348
+ 'Total_Securities_D': 'Total_Securities_Sold'
349
+ })
350
+
351
+ top_bought = (
352
+ security_stats[security_stats['Acquisition'] > 0]
353
+ .sort_values(by='Acquisition', ascending=False)
354
+ .head(top_n)
355
+ .reset_index(drop=True)
356
+ )
357
+
358
+ top_bought['Total_Sold'] = top_bought['Disposition']
359
+
360
+ fig_top_bought = go.Figure()
361
+
362
+ fig_top_bought.add_trace(
363
+ go.Bar(
364
+ x=top_bought['symbol'],
365
+ y=top_bought['Acquisition'],
366
+ name='Acquisition',
367
+ marker_color='#1f77b4',
368
+ text=top_bought['Acquisition'],
369
+ textposition='outside'
370
+ )
371
+ )
372
+
373
+ fig_top_bought.add_trace(
374
+ go.Bar(
375
+ x=top_bought['symbol'],
376
+ y=top_bought['Total_Sold'],
377
+ name='Total Sold',
378
+ marker_color='#aec7e8',
379
+ text=top_bought['Total_Sold'],
380
+ textposition='outside'
381
+ )
382
+ )
383
+
384
+ fig_top_bought.add_trace(
385
+ go.Scatter(
386
+ x=top_bought['symbol'],
387
+ y=top_bought['Total_Securities_Bought'],
388
+ name='Total Securities Bought',
389
+ mode='lines+markers+text',
390
+ yaxis='y2',
391
+ marker=dict(color='green'),
392
+ text=top_bought['Total_Securities_Bought'],
393
+ textposition='top center',
394
+ textfont=dict(color='green')
395
+ )
396
+ )
397
+
398
+ fig_top_bought.update_layout(
399
+ title=f'Top {top_n} Most Frequently Bought Securities',
400
+ xaxis=dict(title='Symbol'),
401
+ yaxis=dict(
402
+ title='Transaction Count',
403
+ titlefont=dict(color='#1f77b4'),
404
+ tickfont=dict(color='#1f77b4')
405
+ ),
406
+ yaxis2=dict(
407
+ title='Total Securities Bought',
408
+ titlefont=dict(color='green'),
409
+ tickfont=dict(color='green'),
410
+ overlaying='y',
411
+ side='right'
412
+ ),
413
+ legend=dict(
414
+ x=1.05,
415
+ y=1,
416
+ traceorder='normal',
417
+ bgcolor='rgba(255,255,255,0)',
418
+ bordercolor='rgba(255,255,255,0)'
419
+ ),
420
+ barmode='group',
421
+ uniformtext_minsize=8,
422
+ uniformtext_mode='hide',
423
+ margin=dict(l=50, r=150, t=50, b=50),
424
+ template='plotly_white',
425
+ font=dict(size=12),
426
+ title_font=dict(size=16),
427
+ hovermode='x unified'
428
+ )
429
+
430
+ fig_top_bought.update_traces(
431
+ selector=dict(name='Total Securities Bought'),
432
+ texttemplate='%{y}',
433
+ textposition='top center'
434
+ )
435
+
436
+ return fig_top_bought
437
+
438
+ def create_top_sold_chart(df, top_n):
439
+ security_stats = df.groupby(['symbol', 'acquistionOrDisposition']).agg(
440
+ Transaction_Count=('acquistionOrDisposition', 'size'),
441
+ Total_Securities=('securitiesTransacted', 'sum')
442
+ ).unstack(fill_value=0).reset_index()
443
+
444
+ security_stats.columns = ['symbol'] + [f"{stat}_{action}" for stat, action in security_stats.columns if stat != 'symbol']
445
+
446
+ required_columns = ['Transaction_Count_A', 'Transaction_Count_D', 'Total_Securities_A', 'Total_Securities_D']
447
+ for col in required_columns:
448
+ if col not in security_stats.columns:
449
+ security_stats[col] = 0
450
+
451
+ security_stats = security_stats.rename(columns={
452
+ 'Transaction_Count_A': 'Acquisition',
453
+ 'Transaction_Count_D': 'Disposition',
454
+ 'Total_Securities_A': 'Total_Securities_Bought',
455
+ 'Total_Securities_D': 'Total_Securities_Sold'
456
+ })
457
+
458
+ top_sold = (
459
+ security_stats[security_stats['Disposition'] > 0]
460
+ .sort_values(by='Disposition', ascending=False)
461
+ .head(top_n)
462
+ .reset_index(drop=True)
463
+ )
464
+
465
+ top_sold['Total_Bought'] = top_sold['Acquisition']
466
+
467
+ fig_top_sold = go.Figure()
468
+
469
+ fig_top_sold.add_trace(
470
+ go.Bar(
471
+ x=top_sold['symbol'],
472
+ y=top_sold['Disposition'],
473
+ name='Disposition',
474
+ marker_color='#ff7f0e',
475
+ text=top_sold['Disposition'],
476
+ textposition='outside'
477
+ )
478
+ )
479
+
480
+ fig_top_sold.add_trace(
481
+ go.Bar(
482
+ x=top_sold['symbol'],
483
+ y=top_sold['Total_Bought'],
484
+ name='Total Bought',
485
+ marker_color='#ffbb78',
486
+ text=top_sold['Total_Bought'],
487
+ textposition='outside'
488
+ )
489
+ )
490
+
491
+ fig_top_sold.add_trace(
492
+ go.Scatter(
493
+ x=top_sold['symbol'],
494
+ y=top_sold['Total_Securities_Sold'],
495
+ name='Total Securities Sold',
496
+ mode='lines+markers+text',
497
+ yaxis='y2',
498
+ marker=dict(color='purple'),
499
+ text=top_sold['Total_Securities_Sold'],
500
+ textposition='top center',
501
+ textfont=dict(color='purple')
502
+ )
503
+ )
504
+
505
+ fig_top_sold.update_layout(
506
+ title=f'Top {top_n} Most Frequently Sold Securities',
507
+ xaxis=dict(title='Symbol'),
508
+ yaxis=dict(
509
+ title='Transaction Count',
510
+ titlefont=dict(color='#ff7f0e'),
511
+ tickfont=dict(color='#ff7f0e')
512
+ ),
513
+ yaxis2=dict(
514
+ title='Total Securities Sold',
515
+ titlefont=dict(color='purple'),
516
+ tickfont=dict(color='purple'),
517
+ overlaying='y',
518
+ side='right'
519
+ ),
520
+ legend=dict(
521
+ x=1.05,
522
+ y=1,
523
+ traceorder='normal',
524
+ bgcolor='rgba(255,255,255,0)',
525
+ bordercolor='rgba(255,255,255,0)'
526
+ ),
527
+ barmode='group',
528
+ uniformtext_minsize=8,
529
+ uniformtext_mode='hide',
530
+ margin=dict(l=50, r=150, t=50, b=50),
531
+ template='plotly_white',
532
+ font=dict(size=12),
533
+ title_font=dict(size=16),
534
+ hovermode='x unified'
535
+ )
536
+
537
+ fig_top_sold.update_traces(
538
+ selector=dict(name='Total Securities Sold'),
539
+ texttemplate='%{y}',
540
+ textposition='top center'
541
+ )
542
+
543
+ return fig_top_sold
544
+
545
+ # ----------------------------
546
+ # Page 1: Ticker Insider Trades
547
+ # ----------------------------
548
+ def ticker_insider_trades_page():
549
+ st.title("Ticker Insider Trades")
550
+ st.markdown("""
551
+ Analyze insider trading activities for a specific stock ticker.
552
+ View the latest insider transactions, trade statistics over time, and detailed data tables.
553
+ """)
554
+
555
+ # Inputs in the sidebar
556
+ with st.sidebar.expander("Parameters", expanded=True):
557
+ symbol = st.text_input(
558
+ "Enter Stock Ticker Symbol",
559
+ value=st.session_state['ticker_insider_trades'].get('symbol', 'AAPL'),
560
+ help="Enter the stock ticker symbol (e.g., AAPL for Apple Inc.).").upper()
561
+
562
+ if st.sidebar.button("Fetch Data"):
563
+ with st.spinner("Fetching insider trading data..."):
564
+ try:
565
+ latest_transactions, trade_statistics = get_insider_trading_data(symbol)
566
+ # Save to session state
567
+ st.session_state['ticker_insider_trades']['symbol'] = symbol
568
+ st.session_state['ticker_insider_trades']['latest_transactions'] = latest_transactions
569
+ st.session_state['ticker_insider_trades']['trade_statistics'] = trade_statistics
570
+ st.success("Data fetched successfully!")
571
+ except Exception as e:
572
+ st.error(f"Error fetching data: {e}")
573
+
574
+ # Check if data is available
575
+ if 'latest_transactions' in st.session_state['ticker_insider_trades']:
576
+ latest_transactions = st.session_state['ticker_insider_trades']['latest_transactions']
577
+ trade_statistics = st.session_state['ticker_insider_trades']['trade_statistics']
578
+
579
+ # Display Charts
580
+ #st.subheader("Insider Trading Activity Insights")
581
+
582
+ # Chart 1: Monthly Transactions and Securities Transacted
583
+ st.markdown("""
584
+ ### Monthly Transactions and Securities Transacted
585
+ This chart visualizes the number of acquisition and disposition transactions each month, alongside the total volume of securities transacted.
586
+ - **Lines** represent the count of transactions.
587
+ - **Bars** represent the volume of securities transacted.
588
+ This dual-axis chart helps in understanding both the frequency and the magnitude of insider trades over time.
589
+ """)
590
+ st.plotly_chart(create_monthly_transactions_chart(latest_transactions), use_container_width=True)
591
+
592
+ # Chart 2: Trade Statistics Over Time
593
+ st.markdown("""
594
+ ### Trade Statistics Over Time
595
+ This chart displays the trends in purchases, sales, and the buy/sell ratio over different quarters.
596
+ - **Purchases and Sales**: Represent the count of buy and sell transactions.
597
+ - **Buy/Sell Ratio**: Indicates the balance between buying and selling activities.
598
+ """)
599
+ st.plotly_chart(create_trade_statistics_over_time_chart(trade_statistics), use_container_width=True)
600
+
601
+ # Chart 3: Total and Average Bought/Sold
602
+ st.markdown("""
603
+ ### Total and Average Bought/Sold with Average Buy/Sell Ratio Over Time
604
+ This chart combines total and average amounts of securities bought and sold, along with the average buy/sell ratio.
605
+ - **Bars** show the total bought and sold.
606
+ - **Lines** indicate the average bought and sold per transaction.
607
+ - **Secondary Y-axis** displays the average buy/sell ratio.
608
+ """)
609
+ st.plotly_chart(create_total_avg_bought_sold_chart(trade_statistics), use_container_width=True)
610
+
611
+ # Display DataFrames
612
+ st.subheader("Latest Transactional Data")
613
+ st.markdown("""
614
+ Below is the detailed table of the most recent insider transactions for the selected ticker.
615
+ It includes information such as the date of transaction, type (acquisition or disposition), and the number of securities transacted.
616
+ """)
617
+ st.dataframe(latest_transactions, use_container_width=True)
618
+
619
+ st.subheader("Trade Statistics Data")
620
+ st.markdown("""
621
+ This table presents aggregated trade statistics over time, including total purchases, sales, and the buy/sell ratio for each quarter.
622
+ """)
623
+ st.dataframe(trade_statistics, use_container_width=True)
624
+
625
+ # ----------------------------
626
+ # Page 2: Insider Trades Live Feed
627
+ # ----------------------------
628
+ def insider_trades_live_feed_page():
629
+ st.title("Insider Trades Live Feed")
630
+ st.markdown("""
631
+ Monitor real-time insider trading activities across various securities.
632
+ Visualize daily counts, and identify top traded securities.
633
+ """)
634
+
635
+
636
+ with st.sidebar.expander("Parameters", expanded=True):
637
+ # Inputs in the sidebar
638
+ top_n = st.number_input(
639
+ "Number of Top Securities to Display",
640
+ min_value=1,
641
+ max_value=20,
642
+ value=st.session_state['insider_trades_live_feed'].get('top_n', DEFAULT_TOP_N),
643
+ help="Specify the number of top traded securities to display."
644
+ )
645
+
646
+ if st.sidebar.button("Fetch Live Feed"):
647
+ with st.spinner("Fetching live insider trading data..."):
648
+ try:
649
+ df = fetch_insider_trading_live_feed()
650
+ # Save to session state
651
+ st.session_state['insider_trades_live_feed']['top_n'] = top_n
652
+ st.session_state['insider_trades_live_feed']['df'] = df
653
+ st.success("Live feed data fetched successfully!")
654
+ except Exception as e:
655
+ st.error(f"Error fetching live feed data: {e}")
656
+
657
+ # Check if data is available
658
+ if 'df' in st.session_state['insider_trades_live_feed']:
659
+ df = st.session_state['insider_trades_live_feed']['df']
660
+ top_n = st.session_state['insider_trades_live_feed']['top_n']
661
+
662
+ # Display Charts
663
+ #st.subheader("Live Insider Trading Activity Charts")
664
+
665
+ # Chart 1: Daily Counts of Acquisitions and Dispositions
666
+ st.markdown("""
667
+ ### Daily Counts of Acquisitions and Dispositions
668
+ This chart displays the daily number of acquisition (A) and disposition (D) transactions across all tracked securities.
669
+ - **Bars** represent the count of acquisitions and dispositions each day.
670
+ """)
671
+ st.plotly_chart(create_daily_counts_chart(df), use_container_width=True)
672
+
673
+ # Chart 2: Top N Most Frequently Bought Securities
674
+ st.markdown(f"""
675
+ ### Top {top_n} Most Frequently Bought Securities
676
+ This chart highlights the top {top_n} securities with the highest number of acquisition transactions.
677
+ - **Bars** represent the count of acquisitions.
678
+ - **Secondary Line** shows the total volume of securities bought.
679
+ """)
680
+ st.plotly_chart(create_top_bought_chart(df, top_n), use_container_width=True)
681
+
682
+ # Chart 3: Top N Most Frequently Sold Securities
683
+ st.markdown(f"""
684
+ ### Top {top_n} Most Frequently Sold Securities
685
+ This chart highlights the top {top_n} securities with the highest number of disposition transactions.
686
+ - **Bars** represent the count of dispositions.
687
+ - **Secondary Line** shows the total volume of securities sold.
688
+ """)
689
+ st.plotly_chart(create_top_sold_chart(df, top_n), use_container_width=True)
690
+
691
+ # Display DataFrames
692
+ st.subheader("Complete Insider Trades Data")
693
+ st.markdown("""
694
+ Below is the comprehensive table of all fetched insider trading activities.
695
+ It includes details such as the filing date, transaction type (A for acquisition, D for disposition), and the number of securities transacted.
696
+ """)
697
+ st.dataframe(df, use_container_width=True)
698
+
699
+ # ----------------------------
700
+ # Display the Selected Page
701
+ # ----------------------------
702
+ if page == "Ticker Insider Trades":
703
+ ticker_insider_trades_page()
704
+ elif page == "Insider Trades Live Feed":
705
+ insider_trades_live_feed_page()
706
+
707
+
708
+ hide_streamlit_style = """
709
+ <style>
710
+ #MainMenu {visibility: hidden;}
711
+ footer {visibility: hidden;}
712
+ </style>
713
+ """
714
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)