Tharindu1527 commited on
Commit
7e422c3
·
verified ·
1 Parent(s): 26a33a5

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +1566 -0
  2. requirements.txt +0 -0
app.py ADDED
@@ -0,0 +1,1566 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pandas as pd
3
+ import matplotlib.pyplot as plt
4
+ from datetime import datetime, timedelta
5
+ import requests
6
+ import json
7
+ import yfinance as yf
8
+ from crewai import Agent, Task, Crew, Process, LLM
9
+ from langchain_google_genai import ChatGoogleGenerativeAI
10
+ from dotenv import load_dotenv
11
+ import streamlit as st
12
+ from langfuse.client import Langfuse
13
+ import numpy as np
14
+ import random
15
+ from datetime import datetime, timedelta
16
+ import plotly.express as px
17
+ import plotly.graph_objects as go
18
+
19
+ # Load environment variables
20
+ load_dotenv()
21
+
22
+ # Setup API keys (replace with your actual keys)
23
+ ALPHAVANTAGE_API_KEY = os.getenv("ALPHAVANTAGE_API_KEY")
24
+ FMP_API_KEY = os.getenv("FMP_API_KEY")
25
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
26
+ LANGFUSE_SECRET_KEY = os.getenv("LANGFUSE_SECRET_KEY")
27
+ LANGFUSE_PUBLIC_KEY = os.getenv("LANGFUSE_PUBLIC_KEY")
28
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
29
+
30
+ # Initialize Langfuse for telemetry
31
+ langfuse = Langfuse(
32
+ secret_key=LANGFUSE_SECRET_KEY,
33
+ public_key=LANGFUSE_PUBLIC_KEY,
34
+ )
35
+
36
+ # Create a trace for the entire process
37
+ trace = langfuse.trace(
38
+ name="Stock Analysis System",
39
+ metadata={"timestamp": datetime.now().isoformat()}
40
+ )
41
+
42
+ # Initialize LLM
43
+ llm = LLM(
44
+ model="gemini/gemini-1.5-flash",
45
+ temperature=0.7
46
+ )
47
+ # Define the Data Collection Agent
48
+ data_collection_agent = Agent(
49
+ role="Data Collection Specialist",
50
+ goal="Gather comprehensive stock data from multiple financial APIs",
51
+ backstory="""You are a data specialist with extensive experience in financial markets.
52
+ Your expertise lies in collecting and organizing data from various financial sources.
53
+ You know how to query APIs efficiently and structure data for further analysis.""",
54
+ verbose=True,
55
+ allow_delegation=True,
56
+ llm=llm
57
+ )
58
+
59
+ # Define the Technical Analysis Agent
60
+ technical_analysis_agent = Agent(
61
+ role="Technical Analysis Expert",
62
+ goal="Perform in-depth technical analysis on stock data to identify patterns and trends",
63
+ backstory="""You are a seasoned technical analyst with years of experience in chart patterns,
64
+ technical indicators, and price action analysis. You can spot trends and reversals that
65
+ others might miss. Your analysis is rooted in statistical evidence and historical patterns.""",
66
+ verbose=True,
67
+ allow_delegation=False,
68
+ llm=llm
69
+ )
70
+
71
+ # Define the Fundamental Analysis Agent
72
+ fundamental_analysis_agent = Agent(
73
+ role="Fundamental Analysis Expert",
74
+ goal="Analyze company fundamentals, financial health, and news sentiment",
75
+ backstory="""You are a fundamental analyst with a background in accounting and finance.
76
+ You excel at dissecting financial statements, evaluating management effectiveness,
77
+ and understanding the competitive positioning of companies. You also track news sentiment
78
+ to gauge market perception.""",
79
+ verbose=True,
80
+ allow_delegation=False,
81
+ llm=llm
82
+ )
83
+
84
+ # Define the Risk Assessment Agent
85
+ risk_assessment_agent = Agent(
86
+ role="Risk Assessment Specialist",
87
+ goal="Evaluate risk profiles of potential investments based on volatility and market conditions",
88
+ backstory="""You are a risk management professional who has developed strategies for
89
+ major investment firms. You understand volatility, drawdowns, and correlation effects.
90
+ Your expertise helps in balancing reward potential with risk mitigation.""",
91
+ verbose=True,
92
+ allow_delegation=False,
93
+ llm=llm
94
+ )
95
+
96
+ # Define the Portfolio Recommendation Agent
97
+ portfolio_recommendation_agent = Agent(
98
+ role="Investment Advisor",
99
+ goal="Synthesize all analyses to recommend the top 5 investable stocks",
100
+ backstory="""You are a senior investment advisor who has guided high-net-worth clients
101
+ through multiple market cycles. You have a holistic view of the market and can weigh
102
+ different analytical perspectives to form a coherent investment strategy. You focus on
103
+ identifying the best opportunities with favorable risk-reward profiles.""",
104
+ verbose=True,
105
+ allow_delegation=True,
106
+ llm=llm
107
+ )
108
+
109
+ # Helper functions for API calls
110
+ def fetch_yahoo_finance_data(symbols, period="1mo"):
111
+ """Fetch stock data from Yahoo Finance API"""
112
+ span = langfuse.span(
113
+ name="Yahoo Finance API Call",
114
+ parent_id=trace.id
115
+ )
116
+
117
+ try:
118
+ data = {}
119
+ for symbol in symbols:
120
+ stock = yf.Ticker(symbol)
121
+ hist = stock.history(period=period)
122
+ data[symbol] = {
123
+ "price_data": hist.to_dict(),
124
+ "info": stock.info
125
+ }
126
+ span.end(status="success")
127
+ return data
128
+ except Exception as e:
129
+ span.end(status="error", statusMessage=str(e))
130
+ return {"error": str(e)}
131
+
132
+ def fetch_alpha_vantage_data(symbol):
133
+ """Fetch fundamental data from Alpha Vantage API"""
134
+ span = langfuse.span(
135
+ name="Alpha Vantage API Call",
136
+ parent_id=trace.id
137
+ )
138
+
139
+ try:
140
+ url = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={symbol}&apikey={ALPHAVANTAGE_API_KEY}"
141
+ response = requests.get(url)
142
+ data = response.json()
143
+ span.end(status="success")
144
+ return data
145
+ except Exception as e:
146
+ span.end(status="error", statusMessage=str(e))
147
+ return {"error": str(e)}
148
+
149
+ def fetch_fmp_data(symbol):
150
+ """Fetch financial statements from Financial Modeling Prep API"""
151
+ span = langfuse.span(
152
+ name="Financial Modeling Prep API Call",
153
+ parent_id=trace.id
154
+ )
155
+
156
+ try:
157
+ url = f"https://financialmodelingprep.com/api/v3/income-statement/{symbol}?apikey={FMP_API_KEY}"
158
+ response = requests.get(url)
159
+ data = response.json()
160
+ span.end(status="success")
161
+ return data
162
+ except Exception as e:
163
+ span.end(status="error", statusMessage=str(e))
164
+ return {"error": str(e)}
165
+
166
+ def get_sp500_symbols():
167
+ """Get a list of S&P 500 stocks"""
168
+ url = "https://en.wikipedia.org/wiki/List_of_S%26P_500_companies"
169
+ tables = pd.read_html(url)
170
+ df = tables[0]
171
+ return df['Symbol'].tolist()
172
+
173
+ # Define Tasks
174
+
175
+ # Task 1: Collect Data
176
+ collect_data_task = Task(
177
+ description="""
178
+ Collect comprehensive stock data for potential analysis. Follow these steps:
179
+ 1. Get a list of the top 30 stocks by market cap in the S&P 500 index
180
+ 2. For each stock, fetch data from:
181
+ - Yahoo Finance: price, volume, and basic info
182
+ - Alpha Vantage: company fundamentals
183
+ - Financial Modeling Prep: financial statements
184
+ 3. Organize the data in a structured format for further analysis
185
+ 4. Return a JSON with the collected data
186
+
187
+ Example stocks to include: AAPL, MSFT, AMZN, GOOGL, META
188
+
189
+ The data should include at minimum:
190
+ - Current and historical prices (1 month)
191
+ - Key financial metrics (P/E, EPS, dividend yield)
192
+ - Company overview
193
+
194
+ Your output should be detailed enough for technical and fundamental analysis.
195
+ """,
196
+ agent=data_collection_agent,
197
+ expected_output="""A detailed JSON containing structured data from all three APIs for at least 30 major stocks,
198
+ ready for analysis by other agents. Ensure it includes historical prices, key financial metrics,
199
+ and fundamental information."""
200
+ )
201
+
202
+ # Task 2: Technical Analysis
203
+ technical_analysis_task = Task(
204
+ description="""
205
+ Perform comprehensive technical analysis on the collected stock data. Your analysis should include:
206
+
207
+ 1. Trend analysis using moving averages (50-day and 200-day)
208
+ 2. Momentum indicators assessment (RSI, MACD)
209
+ 3. Volume analysis and what it indicates about price movements
210
+ 4. Support and resistance levels identification
211
+ 5. Chart pattern recognition
212
+
213
+ For each stock, provide:
214
+ - Current trend direction (bullish, bearish, or sideways)
215
+ - Key technical indicators and their current readings
216
+ - Technical strength score (1-10)
217
+ - Potential price targets based on chart patterns
218
+ - Any warning signals or confirmation signals
219
+
220
+ Rank the stocks based on their technical strength and provide justification for your rankings.
221
+ Identify the top 10 stocks with the strongest technical setups.
222
+ """,
223
+ agent=technical_analysis_agent,
224
+ expected_output="""A detailed technical analysis report for each stock, including trend analysis,
225
+ indicator readings, support/resistance levels, and a final ranking of the top 10 stocks based on
226
+ technical strength with clear justification.""",
227
+ context=[collect_data_task]
228
+ )
229
+
230
+ # Task 3: Fundamental Analysis
231
+ fundamental_analysis_task = Task(
232
+ description="""
233
+ Analyze the fundamental health and outlook of each stock using the collected data. Your analysis should include:
234
+
235
+ 1. Profitability metrics assessment (ROE, ROA, profit margins)
236
+ 2. Valuation analysis (P/E, P/B, P/S ratios) relative to industry and historical averages
237
+ 3. Growth prospects evaluation based on historical performance and forward guidance
238
+ 4. Balance sheet strength and debt levels
239
+ 5. Dividend policy and sustainability
240
+ 6. Recent news sentiment and its impact on future prospects
241
+
242
+ For each stock, provide:
243
+ - Overall fundamental health grade (A to F)
244
+ - Key strengths and weaknesses
245
+ - Valuation assessment (undervalued, fairly valued, overvalued)
246
+ - Growth outlook (poor, moderate, strong)
247
+ - Recent news sentiment summary
248
+
249
+ Rank the stocks based on their fundamental attractiveness and provide justification for your rankings.
250
+ Identify the top 10 stocks with the strongest fundamentals.
251
+ """,
252
+ agent=fundamental_analysis_agent,
253
+ expected_output="""A comprehensive fundamental analysis for each stock, including profitability,
254
+ valuation, growth prospects, balance sheet analysis, and a final ranking of the top 10 stocks based
255
+ on fundamental strength with clear justification.""",
256
+ context=[collect_data_task]
257
+ )
258
+
259
+ # Task 4: Risk Assessment
260
+ risk_assessment_task = Task(
261
+ description="""
262
+ Evaluate the risk profile of each stock based on quantitative and qualitative factors. Your assessment should include:
263
+
264
+ 1. Volatility analysis (Beta, standard deviation of returns)
265
+ 2. Drawdown analysis (maximum historical drawdowns)
266
+ 3. Liquidity assessment (trading volume, bid-ask spreads)
267
+ 4. Industry and macroeconomic risk factors
268
+ 5. Company-specific risks (competition, regulatory, litigation)
269
+
270
+ For each stock, provide:
271
+ - Overall risk score (1-10, where 1 is lowest risk and 10 is highest)
272
+ - Volatility metrics and what they indicate
273
+ - Maximum drawdown potential in different market scenarios
274
+ - Key risk factors specific to the company
275
+ - Risk mitigation recommendations
276
+
277
+ Rank the stocks based on their risk-adjusted return potential and provide justification for your rankings.
278
+ Identify the 10 stocks with the most favorable risk-reward profiles.
279
+ """,
280
+ agent=risk_assessment_agent,
281
+ expected_output="""A detailed risk assessment for each stock, including volatility metrics,
282
+ drawdown analysis, liquidity assessment, key risk factors, and a final ranking of the top 10 stocks
283
+ with the most favorable risk-reward profiles.""",
284
+ context=[collect_data_task, technical_analysis_task, fundamental_analysis_task]
285
+ )
286
+
287
+ # Task 5: Final Portfolio Recommendation
288
+ portfolio_recommendation_task = Task(
289
+ description="""
290
+ Synthesize all previous analyses to identify the top 5 investable stocks in the US market for today.
291
+
292
+ Your recommendation should:
293
+ 1. Integrate technical, fundamental, and risk analyses
294
+ 2. Consider current market conditions and sector trends
295
+ 3. Balance growth potential with risk mitigation
296
+ 4. Include near-term catalysts and potential headwinds
297
+
298
+ For each recommended stock, provide:
299
+ - A comprehensive investment thesis
300
+ - Why it ranks in the top 5
301
+ - Key metrics that support the recommendation
302
+ - Suggested position sizing based on risk profile
303
+ - Potential entry points and price targets
304
+ - Recommended holding period
305
+
306
+ Your final output should be a professional investment recommendation report that could be presented to clients.
307
+ """,
308
+ agent=portfolio_recommendation_agent,
309
+ expected_output="""A professional investment recommendation report identifying the top 5 investable
310
+ stocks with comprehensive justification, supported by technical, fundamental, and risk analyses.
311
+ Include specific entry points, price targets, and holding periods.""",
312
+ context=[technical_analysis_task, fundamental_analysis_task, risk_assessment_task]
313
+ )
314
+
315
+ # Create the Crew
316
+ stock_analysis_crew = Crew(
317
+ agents=[
318
+ data_collection_agent,
319
+ technical_analysis_agent,
320
+ fundamental_analysis_agent,
321
+ risk_assessment_agent,
322
+ portfolio_recommendation_agent
323
+ ],
324
+ tasks=[
325
+ collect_data_task,
326
+ technical_analysis_task,
327
+ fundamental_analysis_task,
328
+ risk_assessment_task,
329
+ portfolio_recommendation_task
330
+ ],
331
+ verbose=True,
332
+ process=Process.sequential
333
+ )
334
+
335
+ # Streamlit UI
336
+ def main():
337
+ st.set_page_config(
338
+ page_title="Multi-Agent Stock Analysis System",
339
+ layout="wide",
340
+ initial_sidebar_state="expanded"
341
+ )
342
+
343
+ # Custom CSS for better styling
344
+ st.markdown("""
345
+ <style>
346
+ .main-header {
347
+ font-size: 2.5rem;
348
+ font-weight: 700;
349
+ margin-bottom: 1rem;
350
+ }
351
+ .sub-header {
352
+ font-size: 1.8rem;
353
+ font-weight: 600;
354
+ margin-top: 2rem;
355
+ margin-bottom: 1rem;
356
+ }
357
+ .card {
358
+ padding: 1.5rem;
359
+ border-radius: 0.5rem;
360
+ background-color: #f8f9fa;
361
+ margin-bottom: 1rem;
362
+ }
363
+ .metric-value {
364
+ font-size: 1.8rem;
365
+ font-weight: 700;
366
+ }
367
+ .metric-label {
368
+ font-size: 1rem;
369
+ color: #6c757d;
370
+ }
371
+ </style>
372
+ """, unsafe_allow_html=True)
373
+
374
+ # Header section
375
+ col1, col2 = st.columns([5, 1])
376
+ with col1:
377
+ st.markdown('<div class="main-header">Multi-Agent Stock Analysis System</div>', unsafe_allow_html=True)
378
+ st.markdown("Powered by CrewAI and Google Gemini 1.5")
379
+ with col2:
380
+ st.image("https://img.icons8.com/color/96/000000/stocks.png", width=80)
381
+
382
+ st.markdown("---")
383
+
384
+ # Sidebar configuration
385
+ with st.sidebar:
386
+ st.header("Analysis Configuration")
387
+
388
+ # Date range selection
389
+ st.subheader("Time Period")
390
+ date_range = st.selectbox(
391
+ "Select historical data timeframe:",
392
+ ["1 Month", "3 Months", "6 Months", "1 Year", "5 Years"],
393
+ index=0
394
+ )
395
+
396
+ period_mapping = {
397
+ "1 Month": "1mo",
398
+ "3 Months": "3mo",
399
+ "6 Months": "6mo",
400
+ "1 Year": "1y",
401
+ "5 Years": "5y"
402
+ }
403
+ selected_period = period_mapping[date_range]
404
+
405
+ # Stock filtering options
406
+ st.subheader("Stock Filters")
407
+ market_cap_filter = st.multiselect(
408
+ "Market Cap Range:",
409
+ ["Mega Cap (>$200B)", "Large Cap ($10B-$200B)", "Mid Cap ($2B-$10B)", "Small Cap (<$2B)"],
410
+ default=["Mega Cap (>$200B)", "Large Cap ($10B-$200B)"]
411
+ )
412
+
413
+ sector_filter = st.multiselect(
414
+ "Sectors:",
415
+ ["Technology", "Healthcare", "Consumer Cyclical", "Financial Services",
416
+ "Communication Services", "Industrials", "Consumer Defensive", "Energy",
417
+ "Basic Materials", "Real Estate", "Utilities"],
418
+ default=["Technology", "Healthcare", "Financial Services"]
419
+ )
420
+
421
+ # Analysis weights
422
+ st.subheader("Analysis Weights")
423
+ technical_weight = st.slider("Technical Analysis Weight", 0, 100, 33)
424
+ fundamental_weight = st.slider("Fundamental Analysis Weight", 0, 100, 33)
425
+ risk_weight = st.slider("Risk Assessment Weight", 0, 100, 34)
426
+
427
+ # Normalize weights to sum to 100
428
+ total_weight = technical_weight + fundamental_weight + risk_weight
429
+ if total_weight > 0:
430
+ technical_weight = int((technical_weight / total_weight) * 100)
431
+ fundamental_weight = int((fundamental_weight / total_weight) * 100)
432
+ risk_weight = 100 - technical_weight - fundamental_weight
433
+
434
+ st.caption(f"Weights: Technical ({technical_weight}%), Fundamental ({fundamental_weight}%), Risk ({risk_weight}%)")
435
+
436
+ # Run analysis button
437
+ st.header("System Control")
438
+ run_button = st.button("Run Full Analysis", type="primary")
439
+
440
+ # Additional options
441
+ export_format = st.selectbox(
442
+ "Export Results Format:",
443
+ ["PDF Report", "Excel Spreadsheet", "JSON Data", "CSV Data"]
444
+ )
445
+
446
+ st.download_button(
447
+ label="Download Results",
448
+ data="", # This would be filled with actual data
449
+ file_name="stock_analysis_results.pdf",
450
+ disabled=not 'result' in st.session_state,
451
+ help="Run analysis first to enable download"
452
+ )
453
+
454
+ # About section
455
+ st.markdown("---")
456
+ st.header("About")
457
+ st.write("""
458
+ This multi-agent system uses 5 specialized agents to analyze stock market data
459
+ and identify the top 5 investable stocks based on your preferences. The system integrates
460
+ data from Yahoo Finance, Alpha Vantage, and Financial Modeling Prep APIs.
461
+ """)
462
+
463
+ st.caption("© 2025 Stock AI Analysis | Version 1.0.2")
464
+
465
+ # If the run button is clicked or we have existing results
466
+ if run_button:
467
+ with st.spinner("Agents are working on your analysis..."):
468
+ # Execute the crew with the selected period
469
+ # In practice, you would pass these parameters to your crew
470
+ analysis_params = {
471
+ "period": selected_period,
472
+ "market_cap_filter": market_cap_filter,
473
+ "sector_filter": sector_filter,
474
+ "weights": {
475
+ "technical": technical_weight / 100,
476
+ "fundamental": fundamental_weight / 100,
477
+ "risk": risk_weight / 100
478
+ }
479
+ }
480
+
481
+ # For demonstration, we'll simulate a delay
482
+ import time
483
+ progress_bar = st.progress(0)
484
+ status_text = st.empty()
485
+
486
+ # Simulate the analysis progress
487
+ steps = ["Collecting market data...",
488
+ "Performing technical analysis...",
489
+ "Analyzing fundamentals...",
490
+ "Assessing risks...",
491
+ "Generating final recommendations..."]
492
+
493
+ for i, step in enumerate(steps):
494
+ progress_bar.progress((i) / len(steps))
495
+ status_text.text(step)
496
+ time.sleep(0.5) # Simulate processing time
497
+
498
+ progress_bar.progress(1.0)
499
+ status_text.text("Analysis complete!")
500
+ time.sleep(0.5)
501
+ status_text.empty()
502
+ progress_bar.empty()
503
+
504
+ # In a real implementation, you'd run the actual analysis:
505
+ # result = stock_analysis_crew.kickoff(parameters=analysis_params)
506
+
507
+ # For demonstration, we'll create mock results
508
+ from datetime import datetime
509
+ mock_result = {
510
+ "top_stocks": [
511
+ {"symbol": "AAPL", "name": "Apple Inc.", "technical_score": 8.7, "fundamental_score": 9.1, "risk_score": 3.2,
512
+ "composite_score": 8.9, "recommendation": "Strong Buy", "target_price": 230.45},
513
+ {"symbol": "MSFT", "name": "Microsoft Corp.", "technical_score": 9.2, "fundamental_score": 8.9, "risk_score": 2.8,
514
+ "composite_score": 8.8, "recommendation": "Strong Buy", "target_price": 428.50},
515
+ {"symbol": "GOOGL", "name": "Alphabet Inc.", "technical_score": 8.5, "fundamental_score": 8.7, "risk_score": 3.4,
516
+ "composite_score": 8.3, "recommendation": "Buy", "target_price": 187.75},
517
+ {"symbol": "NVDA", "name": "NVIDIA Corp.", "technical_score": 9.4, "fundamental_score": 8.2, "risk_score": 4.6,
518
+ "composite_score": 8.0, "recommendation": "Buy", "target_price": 950.20},
519
+ {"symbol": "AMZN", "name": "Amazon.com Inc.", "technical_score": 7.9, "fundamental_score": 8.5, "risk_score": 3.8,
520
+ "composite_score": 7.8, "recommendation": "Buy", "target_price": 196.30}
521
+ ],
522
+ "analysis_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
523
+ "market_outlook": "Cautiously bullish with potential volatility due to upcoming economic data.",
524
+ "sector_performance": {
525
+ "Technology": 12.4,
526
+ "Healthcare": 8.7,
527
+ "Financial Services": 6.5,
528
+ "Consumer Cyclical": 5.2,
529
+ "Communication Services": 7.8,
530
+ "Industrials": 4.3,
531
+ "Energy": -2.1,
532
+ "Consumer Defensive": 3.2,
533
+ "Real Estate": -1.5,
534
+ "Utilities": 1.8,
535
+ "Basic Materials": 2.4
536
+ }
537
+ }
538
+
539
+ # Save result to session state
540
+ st.session_state.result = mock_result
541
+
542
+ # Display results if available
543
+ if 'result' in st.session_state:
544
+ result = st.session_state.result
545
+
546
+ # Top recommendations section
547
+ st.markdown('<div class="sub-header">Top 5 Investable Stocks</div>', unsafe_allow_html=True)
548
+ st.write(f"Analysis completed on: {result['analysis_date']}")
549
+
550
+ # Market outlook card
551
+ st.markdown(f"""
552
+ <div class="card">
553
+ <h3>Market Outlook</h3>
554
+ <p>{result['market_outlook']}</p>
555
+ </div>
556
+ """, unsafe_allow_html=True)
557
+
558
+ # Create top stocks table with visual indicators
559
+ top_stocks_df = pd.DataFrame(result["top_stocks"])
560
+
561
+ # Create styled dataframe
562
+ def color_scores(val):
563
+ if isinstance(val, float):
564
+ if val >= 8.5:
565
+ return f'background-color: rgba(76, 175, 80, 0.2); color: #1e5631; font-weight: bold'
566
+ elif val >= 7.0:
567
+ return f'background-color: rgba(255, 235, 59, 0.2); color: #8c6d1f'
568
+ elif val <= 4.0 and 'risk' in col.lower(): # Low risk is good
569
+ return f'background-color: rgba(76, 175, 80, 0.2); color: #1e5631; font-weight: bold'
570
+ elif val >= 5.0 and 'risk' in col.lower(): # High risk is bad
571
+ return f'background-color: rgba(244, 67, 54, 0.2); color: #a52121'
572
+ return ''
573
+
574
+ styled_df = top_stocks_df.style.applymap(color_scores)
575
+
576
+ # Display stock cards in columns
577
+ st.subheader("Top Stock Recommendations")
578
+ cols = st.columns(5)
579
+
580
+ for i, stock in enumerate(result["top_stocks"]):
581
+ with cols[i]:
582
+ st.markdown(f"""
583
+ <div style="border-radius: 10px; border: 1px solid #ddd; padding: 16px; height: 100%;">
584
+ <h3 style="margin-top: 0;">{stock['symbol']}</h3>
585
+ <p style="color: #666; font-size: 0.9rem; margin-bottom: 15px;">{stock['name']}</p>
586
+ <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
587
+ <span style="font-weight: bold; color: {'#4CAF50' if stock['recommendation'] == 'Strong Buy' else '#FFC107'}">
588
+ {stock['recommendation']}
589
+ </span>
590
+ <span style="font-weight: bold;">${stock['target_price']}</span>
591
+ </div>
592
+ <hr style="margin: 10px 0;">
593
+ <div style="margin-bottom: 5px;">
594
+ <span style="font-size: 0.8rem; color: #666;">TECHNICAL</span>
595
+ <div style="background-color: #eee; border-radius: 5px; height: 8px; margin-top: 3px;">
596
+ <div style="background-color: #4CAF50; width: {stock['technical_score']*10}%; height: 100%; border-radius: 5px;"></div>
597
+ </div>
598
+ </div>
599
+ <div style="margin-bottom: 5px;">
600
+ <span style="font-size: 0.8rem; color: #666;">FUNDAMENTAL</span>
601
+ <div style="background-color: #eee; border-radius: 5px; height: 8px; margin-top: 3px;">
602
+ <div style="background-color: #2196F3; width: {stock['fundamental_score']*10}%; height: 100%; border-radius: 5px;"></div>
603
+ </div>
604
+ </div>
605
+ <div style="margin-bottom: 5px;">
606
+ <span style="font-size: 0.8rem; color: #666;">RISK (LOWER IS BETTER)</span>
607
+ <div style="background-color: #eee; border-radius: 5px; height: 8px; margin-top: 3px;">
608
+ <div style="background-color: {'#F44336' if stock['risk_score'] > 5 else '#4CAF50'}; width: {stock['risk_score']*10}%; height: 100%; border-radius: 5px;"></div>
609
+ </div>
610
+ </div>
611
+ </div>
612
+ """, unsafe_allow_html=True)
613
+
614
+ # Performance visualization section
615
+ st.markdown('<div class="sub-header">Performance Analysis</div>', unsafe_allow_html=True)
616
+
617
+ # Tabs for different visualizations
618
+ tabs = st.tabs(['Stock Comparison', 'Technical Analysis', 'Fundamental Metrics', 'Risk Assessment', 'Sector Performance'])
619
+
620
+ with tabs[0]:
621
+ # Create columns
622
+ col1, col2 = st.columns([3, 2])
623
+
624
+ with col1:
625
+ # Radar chart for multi-dimensional comparison
626
+ st.subheader("Multi-factor Comparison")
627
+
628
+ # Sample data for radar chart
629
+ radar_data = {
630
+ 'Metric': ['Technical Score', 'Fundamental Score', 'Growth Potential', 'Value Rating', 'Momentum'],
631
+ }
632
+
633
+ for stock in result["top_stocks"]:
634
+ # Simulate different metrics for variety
635
+ radar_data[stock['symbol']] = [
636
+ stock['technical_score'],
637
+ stock['fundamental_score'],
638
+ 7.5 + random.uniform(-1.5, 1.5), # Simulated growth potential
639
+ 8.0 + random.uniform(-2.0, 1.0), # Simulated value rating
640
+ 7.2 + random.uniform(-1.0, 2.0) # Simulated momentum
641
+ ]
642
+
643
+ radar_df = pd.DataFrame(radar_data)
644
+
645
+ # Plot radar chart using Plotly
646
+ fig = go.Figure()
647
+
648
+ for stock in result["top_stocks"]:
649
+ fig.add_trace(go.Scatterpolar(
650
+ r=radar_df[stock['symbol']],
651
+ theta=radar_df['Metric'],
652
+ fill='toself',
653
+ name=stock['symbol']
654
+ ))
655
+
656
+ fig.update_layout(
657
+ polar=dict(
658
+ radialaxis=dict(
659
+ visible=True,
660
+ range=[0, 10]
661
+ )),
662
+ showlegend=True,
663
+ height=450
664
+ )
665
+
666
+ st.plotly_chart(fig, use_container_width=True)
667
+
668
+ with col2:
669
+ # Composite score comparison
670
+ st.subheader("Composite Score Rankings")
671
+
672
+ # Create dataframe for bar chart
673
+ composite_df = pd.DataFrame([
674
+ {'Stock': stock['symbol'], 'Score': stock['composite_score']}
675
+ for stock in result["top_stocks"]
676
+ ])
677
+
678
+ # Sort by score
679
+ composite_df = composite_df.sort_values('Score', ascending=False)
680
+
681
+ # Create the bar chart with Plotly
682
+ fig = px.bar(
683
+ composite_df,
684
+ x='Stock',
685
+ y='Score',
686
+ color='Score',
687
+ color_continuous_scale='Viridis',
688
+ text='Score'
689
+ )
690
+
691
+ fig.update_traces(texttemplate='%{text:.1f}', textposition='outside')
692
+ fig.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
693
+ fig.update_layout(height=400)
694
+
695
+ st.plotly_chart(fig, use_container_width=True)
696
+
697
+ with tabs[1]:
698
+ st.subheader("Technical Analysis Insights")
699
+
700
+ # Create columns
701
+ col1, col2 = st.columns([1, 1])
702
+
703
+ with col1:
704
+ # Example of price chart with technical indicators
705
+ st.markdown("### AAPL - Price Chart with Technical Indicators")
706
+
707
+ # In a real implementation, you would use actual price data
708
+ # Here, we'll generate synthetic data for visualization
709
+ date_range = pd.date_range(end=pd.Timestamp.today(), periods=90)
710
+ base_price = 180
711
+ price_data = [base_price]
712
+
713
+ # Generate synthetic price movement
714
+ for i in range(1, 90):
715
+ change = price_data[-1] * np.random.normal(0.0005, 0.012)
716
+ price_data.append(price_data[-1] + change)
717
+
718
+ # Create dataframe
719
+ tech_df = pd.DataFrame({
720
+ 'Date': date_range,
721
+ 'Close': price_data
722
+ })
723
+
724
+ # Calculate MA
725
+ tech_df['MA_50'] = tech_df['Close'].rolling(window=20).mean()
726
+ tech_df['MA_200'] = tech_df['Close'].rolling(window=50).mean()
727
+
728
+ # Create Plotly figure
729
+ fig = go.Figure()
730
+
731
+ # Add price line
732
+ fig.add_trace(go.Scatter(
733
+ x=tech_df['Date'],
734
+ y=tech_df['Close'],
735
+ mode='lines',
736
+ name='AAPL Price',
737
+ line=dict(color='#1E88E5', width=2)
738
+ ))
739
+
740
+ # Add moving averages
741
+ fig.add_trace(go.Scatter(
742
+ x=tech_df['Date'],
743
+ y=tech_df['MA_50'],
744
+ mode='lines',
745
+ name='50-day MA',
746
+ line=dict(color='#FFA000', width=1.5)
747
+ ))
748
+
749
+ fig.add_trace(go.Scatter(
750
+ x=tech_df['Date'],
751
+ y=tech_df['MA_200'],
752
+ mode='lines',
753
+ name='200-day MA',
754
+ line=dict(color='#D81B60', width=1.5)
755
+ ))
756
+
757
+ # Update layout
758
+ fig.update_layout(
759
+ title='AAPL Price with Moving Averages',
760
+ xaxis_title='Date',
761
+ yaxis_title='Price (USD)',
762
+ legend=dict(x=0, y=1, traceorder='normal'),
763
+ height=400
764
+ )
765
+
766
+ st.plotly_chart(fig, use_container_width=True)
767
+
768
+ with col2:
769
+ # Example of technical indicators comparison
770
+ st.markdown("### Technical Indicators Comparison")
771
+
772
+ # Create dataframe for tech indicators
773
+ tech_indicators = pd.DataFrame({
774
+ 'Stock': [stock['symbol'] for stock in result["top_stocks"]],
775
+ 'RSI': [60.2, 52.7, 58.1, 67.3, 49.8], # Example values
776
+ 'MACD': [1.2, 0.8, -0.3, 2.1, 0.5], # Example values
777
+ 'Bollinger': [1.2, 0.7, 0.9, 1.5, 0.3], # Example values
778
+ 'ADX': [28.3, 22.1, 19.8, 32.5, 21.3] # Example values
779
+ })
780
+
781
+ fig = px.parallel_coordinates(
782
+ tech_indicators,
783
+ color="RSI",
784
+ labels={"Stock": "Stock Ticker",
785
+ "RSI": "RSI (14)",
786
+ "MACD": "MACD Signal",
787
+ "Bollinger": "Bollinger Position",
788
+ "ADX": "ADX (14)"},
789
+ color_continuous_scale=px.colors.sequential.Viridis,
790
+ color_continuous_midpoint=50
791
+ )
792
+
793
+ fig.update_layout(height=400)
794
+ st.plotly_chart(fig, use_container_width=True)
795
+
796
+ # Technical metrics explanation
797
+ with st.expander("Technical Indicators Explained"):
798
+ st.markdown("""
799
+ - **RSI (Relative Strength Index)**: Measures momentum, with values over 70 indicating overbought conditions and under 30 indicating oversold conditions.
800
+ - **MACD (Moving Average Convergence Divergence)**: Shows the relationship between two moving averages, with positive values indicating bullish momentum.
801
+ - **Bollinger Position**: Where price is within Bollinger Bands, with values near 1 indicating price near upper band.
802
+ - **ADX (Average Directional Index)**: Measures trend strength, with values over 25 indicating a strong trend.
803
+ """)
804
+
805
+ with tabs[2]:
806
+ st.subheader("Fundamental Analysis Insights")
807
+
808
+ # Create columns
809
+ col1, col2 = st.columns([1, 1])
810
+
811
+ with col1:
812
+ # Valuation metrics comparison
813
+ st.markdown("### Valuation Metrics")
814
+
815
+ # Create dataframe for valuation metrics
816
+ valuation_df = pd.DataFrame({
817
+ 'Stock': [stock['symbol'] for stock in result["top_stocks"]],
818
+ 'P/E Ratio': [28.5, 35.2, 25.7, 42.8, 30.1], # Example values
819
+ 'EV/EBITDA': [18.2, 22.1, 16.8, 28.3, 19.5], # Example values
820
+ 'P/S Ratio': [7.2, 12.8, 6.5, 14.2, 3.8], # Example values
821
+ 'P/B Ratio': [12.5, 15.3, 5.8, 20.1, 9.2] # Example values
822
+ })
823
+
824
+ # Melt the dataframe for easier plotting
825
+ valuation_melted = pd.melt(
826
+ valuation_df,
827
+ id_vars=['Stock'],
828
+ var_name='Metric',
829
+ value_name='Value'
830
+ )
831
+
832
+ # Create the grouped bar chart
833
+ fig = px.bar(
834
+ valuation_melted,
835
+ x='Stock',
836
+ y='Value',
837
+ color='Metric',
838
+ barmode='group',
839
+ title='Valuation Metrics Comparison'
840
+ )
841
+
842
+ fig.update_layout(height=400)
843
+ st.plotly_chart(fig, use_container_width=True)
844
+
845
+ with col2:
846
+ # Growth metrics
847
+ st.markdown("### Growth Metrics (YoY %)")
848
+
849
+ # Create dataframe for growth metrics
850
+ growth_df = pd.DataFrame({
851
+ 'Stock': [stock['symbol'] for stock in result["top_stocks"]],
852
+ 'Revenue Growth': [12.5, 18.2, 15.7, 25.8, 20.1], # Example values
853
+ 'EPS Growth': [15.2, 22.1, 12.8, 32.3, 19.5], # Example values
854
+ 'Dividend Growth': [5.2, 8.8, 3.5, 0.0, 2.8], # Example values
855
+ 'FCF Growth': [10.5, 15.3, 9.8, 20.1, 12.2] # Example values
856
+ })
857
+
858
+ # Melt the dataframe for easier plotting
859
+ growth_melted = pd.melt(
860
+ growth_df,
861
+ id_vars=['Stock'],
862
+ var_name='Metric',
863
+ value_name='Growth (%)'
864
+ )
865
+
866
+ # Create the grouped bar chart
867
+ fig = px.bar(
868
+ growth_melted,
869
+ x='Stock',
870
+ y='Growth (%)',
871
+ color='Metric',
872
+ barmode='group',
873
+ title='Year-over-Year Growth Metrics'
874
+ )
875
+
876
+ fig.update_layout(height=400)
877
+ st.plotly_chart(fig, use_container_width=True)
878
+
879
+ # Financial health metrics
880
+ st.markdown("### Financial Health Overview")
881
+
882
+ # Create columns for metrics
883
+ metric_cols = st.columns(5)
884
+
885
+ # Sample financial health data for each stock
886
+ financial_health = [
887
+ {"Debt/Equity": 0.42, "Current Ratio": 2.1, "ROE": 35.2, "Profit Margin": 25.3, "Dividend Yield": 0.8},
888
+ {"Debt/Equity": 0.15, "Current Ratio": 2.7, "ROE": 42.8, "Profit Margin": 33.5, "Dividend Yield": 1.2},
889
+ {"Debt/Equity": 0.28, "Current Ratio": 1.9, "ROE": 30.1, "Profit Margin": 22.7, "Dividend Yield": 0.6},
890
+ {"Debt/Equity": 0.08, "Current Ratio": 3.2, "ROE": 52.3, "Profit Margin": 30.2, "Dividend Yield": 0.2},
891
+ {"Debt/Equity": 0.35, "Current Ratio": 2.5, "ROE": 33.8, "Profit Margin": 20.1, "Dividend Yield": 1.0}
892
+ ]
893
+
894
+ for i, stock in enumerate(result["top_stocks"]):
895
+ health = financial_health[i]
896
+ with metric_cols[i]:
897
+ st.markdown(f"**{stock['symbol']}**")
898
+
899
+ # Use delta indicators to show good/bad metrics
900
+ st.metric("Debt/Equity", f"{health['Debt/Equity']:.2f}",
901
+ delta="-0.05" if health['Debt/Equity'] < 0.3 else "0.03",
902
+ delta_color="normal")
903
+
904
+ st.metric("Current Ratio", f"{health['Current Ratio']:.1f}",
905
+ delta="0.2" if health['Current Ratio'] > 2.0 else "-0.1",
906
+ delta_color="normal")
907
+
908
+ st.metric("ROE %", f"{health['ROE']:.1f}%",
909
+ delta="3.2%" if health['ROE'] > 30 else "-1.5%",
910
+ delta_color="normal")
911
+
912
+ st.metric("Profit Margin %", f"{health['Profit Margin']:.1f}%",
913
+ delta="1.8%" if health['Profit Margin'] > 25 else "-0.7%",
914
+ delta_color="normal")
915
+
916
+ st.metric("Dividend Yield %", f"{health['Dividend Yield']:.1f}%",
917
+ delta="0.1%" if health['Dividend Yield'] > 0.5 else "0%",
918
+ delta_color="normal")
919
+
920
+ with tabs[3]:
921
+ st.subheader("Risk Assessment Insights")
922
+
923
+ # Create columns
924
+ col1, col2 = st.columns([1, 1])
925
+
926
+ with col1:
927
+ # Volatility comparison
928
+ st.markdown("### Volatility Metrics")
929
+
930
+ # Risk metrics data
931
+ risk_df = pd.DataFrame({
932
+ 'Stock': [stock['symbol'] for stock in result["top_stocks"]],
933
+ 'Beta': [1.15, 0.95, 1.08, 1.42, 1.23], # Example values
934
+ 'Vol (30D)': [25.2, 18.7, 22.3, 35.2, 28.1], # Example values
935
+ 'Vol (90D)': [22.5, 16.8, 20.5, 32.7, 26.3], # Example values
936
+ 'Max Drawdown': [18.5, 12.3, 15.7, 25.2, 20.1] # Example values
937
+ })
938
+
939
+ # Create scatter plot
940
+ fig = px.scatter(
941
+ risk_df,
942
+ x='Beta',
943
+ y='Vol (30D)',
944
+ size='Max Drawdown',
945
+ color='Stock',
946
+ hover_name='Stock',
947
+ size_max=25,
948
+ title='Risk Profile: Beta vs Volatility'
949
+ )
950
+
951
+ fig.update_layout(
952
+ xaxis_title='Beta (vs S&P 500)',
953
+ yaxis_title='30-Day Volatility (%)',
954
+ height=400
955
+ )
956
+
957
+ st.plotly_chart(fig, use_container_width=True)
958
+
959
+ with col2:
960
+ # Risk-reward scatter
961
+ st.markdown("### Risk-Reward Analysis")
962
+
963
+ # Risk-reward data
964
+ risk_reward_df = pd.DataFrame({
965
+ 'Stock': [stock['symbol'] for stock in result["top_stocks"]],
966
+ 'Expected Return (%)': [12.5, 15.2, 11.7, 18.3, 13.5], # Example values
967
+ 'Risk Score': [s['risk_score'] for s in result["top_stocks"]],
968
+ 'Sharpe Ratio': [1.8, 2.2, 1.5, 1.2, 1.7] # Example values
969
+ })
970
+
971
+ # Create scatter plot
972
+ fig = px.scatter(
973
+ risk_reward_df,
974
+ x='Risk Score',
975
+ y='Expected Return (%)',
976
+ size='Sharpe Ratio',
977
+ color='Stock',
978
+ hover_name='Stock',
979
+ size_max=25,
980
+ title='Risk-Reward Analysis'
981
+ )
982
+
983
+ fig.update_layout(
984
+ xaxis_title='Risk Score (Lower is Better)',
985
+ yaxis_title='Expected Annual Return (%)',
986
+ height=400
987
+ )
988
+
989
+ st.plotly_chart(fig, use_container_width=True)
990
+
991
+ # Risk breakdown table
992
+ st.markdown("### Detailed Risk Breakdown")
993
+
994
+ # Risk breakdown data
995
+ risk_breakdown = pd.DataFrame({
996
+ 'Stock': [stock['symbol'] for stock in result["top_stocks"]],
997
+ 'Market Risk': ['Medium', 'Low', 'Medium', 'High', 'Medium'],
998
+ 'Sector Risk': ['Medium', 'Low', 'Low', 'High', 'Medium'],
999
+ 'Company Risk': ['Low', 'Low', 'Medium', 'Medium', 'Medium'],
1000
+ 'Liquidity Risk': ['Low', 'Low', 'Low', 'Medium', 'Low'],
1001
+ 'Volatility': ['Medium', 'Low', 'Medium', 'High', 'Medium'],
1002
+ 'Correlation w/Market': ['High', 'Medium', 'High', 'High', 'High']
1003
+ })
1004
+
1005
+ # Style the dataframe
1006
+ def highlight_risk(val):
1007
+ if val == 'High':
1008
+ return 'background-color: rgba(244, 67, 54, 0.2); color: #a52121'
1009
+ elif val == 'Low':
1010
+ return 'background-color: rgba(76, 175, 80, 0.2); color: #1e5631'
1011
+ return 'background-color: rgba(255, 235, 59, 0.2); color: #8c6d1f'
1012
+
1013
+ styled_risk = risk_breakdown.style.applymap(highlight_risk, subset=[
1014
+ 'Market Risk', 'Sector Risk', 'Company Risk', 'Liquidity Risk',
1015
+ 'Volatility', 'Correlation w/Market'
1016
+ ])
1017
+
1018
+ st.dataframe(styled_risk, use_container_width=True)
1019
+
1020
+ # Risk explanation
1021
+ with st.expander("Risk Metrics Explained"):
1022
+ st.markdown("""
1023
+ - **Beta**: Measures volatility relative to the overall market. A beta > 1 indicates higher volatility than the market.
1024
+ - **Volatility (Vol)**: Standard deviation of returns, indicating price fluctuation magnitude.
1025
+ - **Max Drawdown**: Largest percentage drop from peak to trough, indicating worst-case historical loss.
1026
+ - **Sharpe Ratio**: Risk-adjusted return metric. Higher values indicate better risk-adjusted performance.
1027
+ - **Market Risk**: Risk related to overall market movements affecting the stock.
1028
+ - **Sector Risk**: Risk related to the specific industry sector's performance.
1029
+ - **Company Risk**: Risk specific to the company's operations, management, and financials.
1030
+ - **Liquidity Risk**: Risk related to how easily shares can be bought or sold without affecting price.
1031
+ """)
1032
+
1033
+ with tabs[4]:
1034
+ st.subheader("Sector Performance")
1035
+
1036
+ # Sector performance data
1037
+ sector_df = pd.DataFrame({
1038
+ 'Sector': list(result['sector_performance'].keys()),
1039
+ 'Performance (%)': list(result['sector_performance'].values())
1040
+ })
1041
+
1042
+ # Sort by performance
1043
+ sector_df = sector_df.sort_values('Performance (%)', ascending=False)
1044
+
1045
+ # Create columns
1046
+ col1, col2 = st.columns([3, 2])
1047
+
1048
+ with col1:
1049
+ # Create a horizontal bar chart
1050
+ fig = px.bar(
1051
+ sector_df,
1052
+ y='Sector',
1053
+ x='Performance (%)',
1054
+ orientation='h',
1055
+ color='Performance (%)',
1056
+ color_continuous_scale='RdBu',
1057
+ color_continuous_midpoint=0,
1058
+ title='Sector Performance (YTD)',
1059
+ text='Performance (%)'
1060
+ )
1061
+
1062
+ fig.update_traces(texttemplate='%{text:.1f}%', textposition='outside')
1063
+ fig.update_layout(height=500)
1064
+
1065
+ st.plotly_chart(fig, use_container_width=True)
1066
+
1067
+ with col2:
1068
+ # Sector allocation of recommended stocks
1069
+ st.markdown("### Recommended Portfolio Sector Allocation")
1070
+
1071
+ # Sample sector allocation data
1072
+ sector_allocation = {
1073
+ 'Technology': 60,
1074
+ 'Consumer Cyclical': 20,
1075
+ 'Communication Services': 20
1076
+ }
1077
+
1078
+ # Create pie chart
1079
+ fig = px.pie(
1080
+ names=list(sector_allocation.keys()),
1081
+ values=list(sector_allocation.values()),
1082
+ title='Sector Allocation',
1083
+ hole=0.4
1084
+ )
1085
+
1086
+ fig.update_traces(textposition='inside', textinfo='percent+label')
1087
+ fig.update_layout(height=400)
1088
+
1089
+ st.plotly_chart(fig, use_container_width=True)
1090
+
1091
+ # Sector outlook
1092
+ st.markdown("### Sector Outlook")
1093
+ st.markdown("""
1094
+ - **Technology**: Strong outlook driven by AI adoption and cloud growth
1095
+ - **Consumer Cyclical**: Moderate outlook with potential pressure from interest rates
1096
+ - **Communication Services**: Positive outlook with increasing digital ad spending
1097
+ """)
1098
+
1099
+ # Detailed analysis and recommendations section
1100
+ st.markdown('<div class="sub-header">Detailed Analysis & Recommendations</div>', unsafe_allow_html=True)
1101
+
1102
+ # Create an expander for each stock
1103
+ for stock in result["top_stocks"]:
1104
+ with st.expander(f"{stock['symbol']} - {stock['name']} | {stock['recommendation']}"):
1105
+ # Create tabs within the expander
1106
+ stock_tabs = st.tabs(['Investment Thesis', 'Technical Analysis', 'Fundamental Analysis', 'Risk Assessment'])
1107
+
1108
+ with stock_tabs[0]:
1109
+ st.markdown(f"### Investment Thesis for {stock['symbol']}")
1110
+ st.markdown(f"""
1111
+ **Target Price:** ${stock['target_price']} ({"+" if stock['target_price'] > 200 else ""}{((stock['target_price']/200)-1)*100:.1f}% upside)
1112
+
1113
+ **Recommendation:** {stock['recommendation']}
1114
+
1115
+ **Time Horizon:** 12-18 months
1116
+
1117
+ **Thesis Summary:**
1118
+ {stock['name']} presents a compelling investment opportunity based on its strong technical momentum, solid fundamental growth metrics, and reasonable risk profile. The company is well-positioned to benefit from ongoing digital transformation trends and expanding profit margins.
1119
+
1120
+ **Key Catalysts:**
1121
+ - Continued expansion in service revenue streams
1122
+ - Margin improvement from supply chain optimization
1123
+ - New product launches expected in Q3 2025
1124
+ - Potential for increased shareholder returns via buybacks
1125
+
1126
+ **Position Sizing:**
1127
+ Recommended position size of 4-6% in a diversified portfolio, with potential to add on pullbacks to key support levels.
1128
+ """)
1129
+
1130
+ with stock_tabs[1]:
1131
+ st.markdown(f"### Technical Analysis for {stock['symbol']}")
1132
+
1133
+ # Technical metrics with visual indicators
1134
+ st.markdown("#### Technical Indicators")
1135
+
1136
+ # Create columns for technical metrics
1137
+ tech_cols = st.columns(5)
1138
+
1139
+ # Sample technical metrics
1140
+ tech_metrics = [
1141
+ {"label": "Trend", "value": "Bullish", "detail": "Above major MAs"},
1142
+ {"label": "RSI(14)", "value": "62.3", "detail": "Positive momentum"},
1143
+ {"label": "MACD", "value": "Positive", "detail": "Recent crossover"},
1144
+ {"label": "Vol Trend", "value": "Increasing", "detail": "Above average"},
1145
+ {"label": "Pattern", "value": "Cup & Handle", "detail": "Bullish formation"}
1146
+ ]
1147
+
1148
+ for i, metric in enumerate(tech_metrics):
1149
+ with tech_cols[i]:
1150
+ st.markdown(f"""
1151
+ <div style="text-align: center; padding: 10px; border: 1px solid #ddd; border-radius: 5px;">
1152
+ <div style="font-size: 0.9rem; color: #666;">{metric['label']}</div>
1153
+ <div style="font-size: 1.3rem; font-weight: bold; margin: 5px 0;">{metric['value']}</div>
1154
+ <div style="font-size: 0.8rem; color: #666;">{metric['detail']}</div>
1155
+ </div>
1156
+ """, unsafe_allow_html=True)
1157
+
1158
+ # Technical analysis summary
1159
+ st.markdown("""
1160
+ #### Technical Analysis Summary
1161
+
1162
+ The stock is displaying strong bullish momentum with prices trading above both the 50-day and 200-day moving averages. Recent price action has formed a cup and handle pattern, suggesting potential for further upside movement. Volume has been increasing on up days, confirming the bullish bias.
1163
+
1164
+ **Support Levels:**
1165
+ - Primary: $192.50 (50-day MA)
1166
+ - Secondary: $187.80 (previous resistance turned support)
1167
+ - Tertiary: $180.00 (psychological level)
1168
+
1169
+ **Resistance Levels:**
1170
+ - Primary: $212.75 (recent high)
1171
+ - Secondary: $225.00 (psychological level)
1172
+ - Tertiary: $231.25 (all-time high)
1173
+
1174
+ **Entry Strategy:**
1175
+ Consider entering on pullbacks to the $192-195 range with a stop loss below $187.
1176
+ """)
1177
+
1178
+ with stock_tabs[2]:
1179
+ st.markdown(f"### Fundamental Analysis for {stock['symbol']}")
1180
+
1181
+ # Create columns
1182
+ fund_col1, fund_col2 = st.columns([1, 1])
1183
+
1184
+ with fund_col1:
1185
+ # Financial metrics table
1186
+ st.markdown("#### Key Financial Metrics")
1187
+
1188
+ # Sample financial metrics
1189
+ financials = {
1190
+ "Metric": ["Revenue (TTM)", "Revenue Growth (YoY)", "EPS (TTM)", "EPS Growth (YoY)", "Profit Margin", "Operating Margin", "ROE", "ROA", "ROIC", "Debt/Equity"],
1191
+ "Value": ["$394.2B", "15.2%", "$6.42", "18.7%", "25.3%", "32.1%", "35.2%", "18.7%", "27.5%", "0.42"],
1192
+ "Industry Avg": ["$215.7B", "12.5%", "$3.85", "10.2%", "19.8%", "25.3%", "28.7%", "15.2%", "21.3%", "0.55"]
1193
+ }
1194
+
1195
+ financials_df = pd.DataFrame(financials)
1196
+
1197
+ # Function to highlight where company is better than industry
1198
+ def highlight_better(row):
1199
+ # For metrics where higher is better
1200
+ higher_better = ["Revenue (TTM)", "Revenue Growth (YoY)", "EPS (TTM)", "EPS Growth (YoY)",
1201
+ "Profit Margin", "Operating Margin", "ROE", "ROA", "ROIC"]
1202
+ # For metrics where lower is better
1203
+ lower_better = ["Debt/Equity"]
1204
+
1205
+ if row.name not in [0, 1]: # Skip header rows
1206
+ metric = row["Metric"]
1207
+
1208
+ # Extract numeric values for comparison
1209
+ try:
1210
+ # Remove non-numeric characters and convert to float
1211
+ val_str = row["Value"].replace('$', '').replace('B', '').replace('%', '')
1212
+ avg_str = row["Industry Avg"].replace('$', '').replace('B', '').replace('%', '')
1213
+ val = float(val_str)
1214
+ avg = float(avg_str)
1215
+
1216
+ if metric in higher_better and val > avg:
1217
+ return ['', 'background-color: rgba(76, 175, 80, 0.2)', '']
1218
+ elif metric in lower_better and val < avg:
1219
+ return ['', 'background-color: rgba(76, 175, 80, 0.2)', '']
1220
+ except:
1221
+ pass
1222
+ return ['', '', '']
1223
+
1224
+ st.dataframe(financials_df.style.apply(highlight_better, axis=1), use_container_width=True)
1225
+
1226
+ with fund_col2:
1227
+ # Valuation metrics table
1228
+ st.markdown("#### Valuation Metrics")
1229
+
1230
+ # Sample valuation metrics
1231
+ valuation = {
1232
+ "Metric": ["P/E Ratio", "Forward P/E", "PEG Ratio", "P/S Ratio", "P/B Ratio", "EV/EBITDA", "EV/Revenue", "Dividend Yield", "FCF Yield", "Earnings Yield"],
1233
+ "Value": ["28.5", "24.2", "1.52", "7.2", "12.5", "18.2", "6.8", "0.8%", "3.2%", "3.5%"],
1234
+ "5Y Average": ["32.7", "27.5", "1.75", "8.4", "14.2", "20.1", "7.5", "0.7%", "2.8%", "3.1%"]
1235
+ }
1236
+
1237
+ valuation_df = pd.DataFrame(valuation)
1238
+
1239
+ # Function to highlight where current is better than 5Y avg
1240
+ def highlight_better_valuation(row):
1241
+ # For metrics where lower is better
1242
+ lower_better = ["P/E Ratio", "Forward P/E", "PEG Ratio", "P/S Ratio", "P/B Ratio", "EV/EBITDA", "EV/Revenue"]
1243
+ # For metrics where higher is better
1244
+ higher_better = ["Dividend Yield", "FCF Yield", "Earnings Yield"]
1245
+
1246
+ if row.name not in [0, 1]: # Skip header rows
1247
+ metric = row["Metric"]
1248
+
1249
+ # Extract numeric values for comparison
1250
+ try:
1251
+ # Remove non-numeric characters and convert to float
1252
+ val_str = row["Value"].replace('%', '')
1253
+ avg_str = row["5Y Average"].replace('%', '')
1254
+ val = float(val_str)
1255
+ avg = float(avg_str)
1256
+
1257
+ if metric in lower_better and val < avg:
1258
+ return ['', 'background-color: rgba(76, 175, 80, 0.2)', '']
1259
+ elif metric in higher_better and val > avg:
1260
+ return ['', 'background-color: rgba(76, 175, 80, 0.2)', '']
1261
+ except:
1262
+ pass
1263
+ return ['', '', '']
1264
+
1265
+ st.dataframe(valuation_df.style.apply(highlight_better_valuation, axis=1), use_container_width=True)
1266
+
1267
+ # Fundamental analysis summary
1268
+ st.markdown("""
1269
+ #### Fundamental Analysis Summary
1270
+
1271
+ The company demonstrates strong financial health with revenue and earnings growth exceeding industry averages. Profit margins are expanding due to operational efficiencies and economies of scale. The balance sheet remains strong with manageable debt levels and significant cash reserves.
1272
+
1273
+ **Growth Drivers:**
1274
+ - Expansion of services ecosystem creating higher-margin revenue streams
1275
+ - International market penetration, particularly in emerging markets
1276
+ - New product categories showing promising adoption rates
1277
+ - Strategic acquisitions enhancing technological capabilities
1278
+
1279
+ **Valuation Assessment:**
1280
+ While the stock trades at a premium to the broader market on a P/E basis, it appears reasonably valued relative to its growth rate and historical averages. The PEG ratio of 1.52 suggests fair value considering the company's growth prospects.
1281
+ """)
1282
+
1283
+ with stock_tabs[3]:
1284
+ st.markdown(f"### Risk Assessment for {stock['symbol']}")
1285
+
1286
+ # Risk radar chart
1287
+ st.markdown("#### Risk Profile")
1288
+
1289
+ # Sample risk data for radar chart
1290
+ risk_categories = ['Market Risk', 'Sector Risk', 'Valuation Risk', 'Financial Risk', 'Competition Risk', 'Regulatory Risk']
1291
+ risk_values = [5, 4, 6, 3, 5, 4] # 1-10 scale where lower is better
1292
+
1293
+ # Create radar chart
1294
+ fig = go.Figure()
1295
+
1296
+ fig.add_trace(go.Scatterpolar(
1297
+ r=risk_values,
1298
+ theta=risk_categories,
1299
+ fill='toself',
1300
+ name=stock['symbol']
1301
+ ))
1302
+
1303
+ fig.update_layout(
1304
+ polar=dict(
1305
+ radialaxis=dict(
1306
+ visible=True,
1307
+ range=[0, 10]
1308
+ )
1309
+ ),
1310
+ showlegend=False
1311
+ )
1312
+
1313
+ st.plotly_chart(fig, use_container_width=True)
1314
+
1315
+ # Risk factors
1316
+ st.markdown("#### Key Risk Factors")
1317
+
1318
+ # Create two columns for risks
1319
+ risk_col1, risk_col2 = st.columns([1, 1])
1320
+
1321
+ with risk_col1:
1322
+ st.markdown("""
1323
+ **Market & Macroeconomic Risks:**
1324
+ - Sensitivity to broader market corrections
1325
+ - Potential impact from rising interest rates
1326
+ - Currency fluctuation effects on international revenue
1327
+
1328
+ **Competition & Industry Risks:**
1329
+ - Increasing competition in core markets
1330
+ - Rapid technological changes requiring constant innovation
1331
+ - Margin pressure from emerging low-cost competitors
1332
+ """)
1333
+
1334
+ with risk_col2:
1335
+ st.markdown("""
1336
+ **Company-Specific Risks:**
1337
+ - Product cycle dependencies
1338
+ - Key personnel dependencies
1339
+ - Supply chain vulnerabilities
1340
+
1341
+ **Regulatory & Other Risks:**
1342
+ - Potential antitrust scrutiny
1343
+ - Data privacy regulation changes
1344
+ - Intellectual property challenges
1345
+ """)
1346
+
1347
+ # Risk mitigation
1348
+ st.markdown("""
1349
+ #### Risk Mitigation Strategies
1350
+
1351
+ **Position Sizing:**
1352
+ Limit position to 4-6% of portfolio to manage stock-specific risk exposure.
1353
+
1354
+ **Entry Strategy:**
1355
+ Consider dollar-cost averaging or scaling in on technical pullbacks rather than establishing full position at once.
1356
+
1357
+ **Hedging Considerations:**
1358
+ For larger positions, consider protective puts or collar strategies during periods of elevated volatility or ahead of key events.
1359
+
1360
+ **Exit Strategy:**
1361
+ Set a stop-loss at $187 (approximately 8% below current levels) to limit downside risk.
1362
+ """)
1363
+
1364
+ # Historical performance and backtesting section
1365
+ st.markdown('<div class="sub-header">Historical Performance & Backtesting</div>', unsafe_allow_html=True)
1366
+
1367
+ # Generate sample historical performance data
1368
+ dates = pd.date_range(end=pd.Timestamp.today(), periods=252) # Approximately 1 year of trading days
1369
+
1370
+ # Create sample portfolio and benchmark returns
1371
+ np.random.seed(42) # For reproducibility
1372
+
1373
+ # Generate correlated returns (portfolio and S&P 500)
1374
+ correlation = 0.8
1375
+ volatility_portfolio = 0.012
1376
+ volatility_sp500 = 0.010
1377
+
1378
+ # Generate correlated random returns
1379
+ returns_portfolio = np.random.normal(0.0005, volatility_portfolio, len(dates))
1380
+ returns_sp500 = np.random.normal(0.0004, volatility_sp500, len(dates))
1381
+
1382
+ # Add correlation
1383
+ returns_sp500 = correlation * returns_portfolio + np.sqrt(1 - correlation**2) * returns_sp500
1384
+
1385
+ # Create price series
1386
+ portfolio_series = 100 * (1 + returns_portfolio).cumprod()
1387
+ sp500_series = 100 * (1 + returns_sp500).cumprod()
1388
+
1389
+ # Create dataframe
1390
+ performance_df = pd.DataFrame({
1391
+ 'Date': dates,
1392
+ 'Portfolio': portfolio_series,
1393
+ 'S&P 500': sp500_series
1394
+ })
1395
+
1396
+ # Create columns
1397
+ perf_col1, perf_col2 = st.columns([3, 2])
1398
+
1399
+ with perf_col1:
1400
+ # Performance chart
1401
+ st.subheader("Strategy Backtest Performance")
1402
+
1403
+ # Create line chart
1404
+ fig = px.line(
1405
+ performance_df,
1406
+ x='Date',
1407
+ y=['Portfolio', 'S&P 500'],
1408
+ title='Backtest Performance vs S&P 500 (1 Year)',
1409
+ labels={'value': 'Value ($)', 'variable': 'Series'}
1410
+ )
1411
+
1412
+ fig.update_layout(hovermode='x unified')
1413
+
1414
+ st.plotly_chart(fig, use_container_width=True)
1415
+
1416
+ with perf_col2:
1417
+ # Performance metrics
1418
+ st.subheader("Performance Metrics")
1419
+
1420
+ # Calculate sample performance metrics
1421
+ portfolio_return = (portfolio_series[-1] / portfolio_series[0] - 1) * 100
1422
+ sp500_return = (sp500_series[-1] / sp500_series[0] - 1) * 100
1423
+
1424
+ # Annualized volatility
1425
+ portfolio_vol = np.std(returns_portfolio) * np.sqrt(252) * 100
1426
+ sp500_vol = np.std(returns_sp500) * np.sqrt(252) * 100
1427
+
1428
+ # Sharpe ratio (assuming risk-free rate of 2%)
1429
+ portfolio_sharpe = (portfolio_return - 2) / portfolio_vol
1430
+ sp500_sharpe = (sp500_return - 2) / sp500_vol
1431
+
1432
+ # Create metrics table
1433
+ metrics_data = {
1434
+ 'Metric': ['Total Return (%)', 'Annualized Volatility (%)', 'Sharpe Ratio', 'Max Drawdown (%)', 'Beta', 'Alpha (%)'],
1435
+ 'Portfolio': [f"{portfolio_return:.2f}%", f"{portfolio_vol:.2f}%", f"{portfolio_sharpe:.2f}", "12.5%", "0.95", "5.2%"],
1436
+ 'S&P 500': [f"{sp500_return:.2f}%", f"{sp500_vol:.2f}%", f"{sp500_sharpe:.2f}", "14.8%", "1.00", "0.0%"]
1437
+ }
1438
+
1439
+ metrics_df = pd.DataFrame(metrics_data)
1440
+
1441
+ # Style the dataframe
1442
+ def highlight_better_performance(df):
1443
+ styles = pd.DataFrame('', index=df.index, columns=df.columns)
1444
+
1445
+ # Compare metrics
1446
+ for i in range(len(df)):
1447
+ metric = df.iloc[i, 0]
1448
+
1449
+ # For metrics where higher is better
1450
+ if metric in ['Total Return (%)', 'Sharpe Ratio', 'Alpha (%)']:
1451
+ if float(df.iloc[i, 1].replace('%', '')) > float(df.iloc[i, 2].replace('%', '')):
1452
+ styles.iloc[i, 1] = 'background-color: rgba(76, 175, 80, 0.2); color: #1e5631'
1453
+ else:
1454
+ styles.iloc[i, 2] = 'background-color: rgba(76, 175, 80, 0.2); color: #1e5631'
1455
+
1456
+ # For metrics where lower is better
1457
+ elif metric in ['Annualized Volatility (%)', 'Max Drawdown (%)']:
1458
+ if float(df.iloc[i, 1].replace('%', '')) < float(df.iloc[i, 2].replace('%', '')):
1459
+ styles.iloc[i, 1] = 'background-color: rgba(76, 175, 80, 0.2); color: #1e5631'
1460
+ else:
1461
+ styles.iloc[i, 2] = 'background-color: rgba(76, 175, 80, 0.2); color: #1e5631'
1462
+
1463
+ return styles
1464
+
1465
+ st.dataframe(metrics_df.style.apply(highlight_better_performance, axis=None), use_container_width=True)
1466
+
1467
+ # Performance summary
1468
+ st.markdown("""
1469
+ #### Backtest Summary
1470
+
1471
+ The recommended portfolio strategy has demonstrated superior risk-adjusted returns compared to the S&P 500 benchmark. Key strengths include:
1472
+
1473
+ - Higher total return with lower volatility
1474
+ - Improved Sharpe ratio indicating better risk-adjusted performance
1475
+ - Lower maximum drawdown suggesting better downside protection
1476
+ - Positive alpha indicating value added by the selection strategy
1477
+
1478
+ Past performance is not indicative of future results, but the strategy has shown robustness across different market conditions.
1479
+ """)
1480
+
1481
+ # If no analysis has been run yet, show the welcome screen
1482
+ else:
1483
+ st.markdown("""
1484
+ <div style="text-align: center; padding: 2rem;">
1485
+ <img src="https://img.icons8.com/fluency/240/000000/investment-portfolio.png" width="120"/>
1486
+ <h2 style="margin-top: 1rem;">Welcome to the Multi-Agent Stock Analysis System</h2>
1487
+ <p style="font-size: 1.2rem; margin: 1rem 0 2rem 0;">Configure your analysis parameters in the sidebar and click "Run Full Analysis" to get started.</p>
1488
+ </div>
1489
+ """, unsafe_allow_html=True)
1490
+
1491
+ # Features overview
1492
+ st.subheader("System Features")
1493
+
1494
+ features = [
1495
+ {
1496
+ "icon": "📊",
1497
+ "title": "Multi-agent Analysis",
1498
+ "description": "Leverages 5 specialized AI agents working together to provide comprehensive stock analysis."
1499
+ },
1500
+ {
1501
+ "icon": "🧠",
1502
+ "title": "Technical Analysis",
1503
+ "description": "Evaluates price patterns, momentum indicators, and chart formations to identify market trends."
1504
+ },
1505
+ {
1506
+ "icon": "💼",
1507
+ "title": "Fundamental Analysis",
1508
+ "description": "Assesses company financials, growth metrics, and valuation to determine intrinsic worth."
1509
+ },
1510
+ {
1511
+ "icon": "⚖️",
1512
+ "title": "Risk Assessment",
1513
+ "description": "Measures volatility, drawdowns, and various risk factors to optimize risk-adjusted returns."
1514
+ },
1515
+ {
1516
+ "icon": "📈",
1517
+ "title": "Portfolio Recommendations",
1518
+ "description": "Synthesizes all analyses to identify the most promising investment opportunities."
1519
+ },
1520
+ {
1521
+ "icon": "📱",
1522
+ "title": "Interactive Visualizations",
1523
+ "description": "Provides rich, interactive charts and graphs to understand complex market dynamics."
1524
+ }
1525
+ ]
1526
+
1527
+ # Create columns for features
1528
+ cols = st.columns(3)
1529
+
1530
+ for i, feature in enumerate(features):
1531
+ with cols[i % 3]:
1532
+ st.markdown(f"""
1533
+ <div style="border: 1px solid #ddd; border-radius: 10px; padding: 1.5rem; margin-bottom: 1rem; height: 200px;">
1534
+ <div style="font-size: 2rem; margin-bottom: 0.5rem;">{feature['icon']}</div>
1535
+ <h3 style="margin-top: 0;">{feature['title']}</h3>
1536
+ <p>{feature['description']}</p>
1537
+ </div>
1538
+ """, unsafe_allow_html=True)
1539
+
1540
+ # Getting started section
1541
+ st.subheader("Getting Started")
1542
+
1543
+ st.markdown("""
1544
+ 1. **Configure Analysis Parameters**: Use the sidebar to select your preferred time period, stock filters, and analysis weights.
1545
+
1546
+ 2. **Run Analysis**: Click the "Run Full Analysis" button to start the AI agents' analysis process.
1547
+
1548
+ 3. **Review Results**: Explore the comprehensive analysis across multiple tabs, from high-level recommendations to detailed stock-specific insights.
1549
+
1550
+ 4. **Export Findings**: Download the analysis results in your preferred format for future reference or sharing.
1551
+ """)
1552
+
1553
+ # Footer
1554
+ st.markdown("""
1555
+ <div style="margin-top: 4rem; padding-top: 1rem; border-top: 1px solid #ddd; text-align: center; color: #666; font-size: 0.8rem;">
1556
+ Multi-Agent Stock Analysis System powered by CrewAI and Google Gemini 1.5<br>
1557
+ Disclaimer: This tool is for informational purposes only and does not constitute investment advice.
1558
+ </div>
1559
+ """, unsafe_allow_html=True)
1560
+
1561
+
1562
+ # Import statements that should be at the top of your file
1563
+
1564
+
1565
+ if __name__ == "__main__":
1566
+ main()
requirements.txt ADDED
Binary file (9.64 kB). View file