Update app.py
Browse files
app.py
CHANGED
@@ -55,40 +55,108 @@ def calculate_basic_indicators(data: pd.DataFrame) -> pd.DataFrame:
|
|
55 |
return df.ffill().bfill()
|
56 |
|
57 |
@pxt.udf
|
58 |
-
def generate_analysis_prompt(data: str, analysis_type: str
|
|
|
|
|
59 |
"""Generate a structured prompt for AI analysis"""
|
60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
|
62 |
SUMMARY
|
63 |
-
Provide a clear 2-3 sentence executive summary
|
64 |
|
65 |
TECHNICAL ANALYSIS
|
66 |
-
|
|
|
67 |
• RSI Analysis: Current RSI level and implications
|
68 |
-
• MACD Analysis:
|
69 |
• Volume Analysis: Notable volume patterns and implications
|
|
|
70 |
|
71 |
MARKET CONTEXT
|
72 |
-
•
|
73 |
-
•
|
74 |
-
•
|
75 |
|
76 |
RISKS
|
77 |
-
•
|
78 |
-
•
|
79 |
-
•
|
80 |
|
81 |
OPPORTUNITIES
|
82 |
-
•
|
83 |
-
•
|
84 |
-
•
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
|
86 |
RECOMMENDATION
|
87 |
-
Provide
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
|
89 |
return [
|
90 |
{'role': 'system', 'content': system_prompt},
|
91 |
-
{'role': 'user', 'content': f'Analyze this market data
|
92 |
]
|
93 |
|
94 |
def parse_analysis_response(response: str) -> Dict[str, str]:
|
@@ -99,6 +167,7 @@ def parse_analysis_response(response: str) -> Dict[str, str]:
|
|
99 |
'MARKET CONTEXT': None,
|
100 |
'RISKS': None,
|
101 |
'OPPORTUNITIES': None,
|
|
|
102 |
'RECOMMENDATION': None
|
103 |
}
|
104 |
|
@@ -140,6 +209,7 @@ def parse_analysis_response(response: str) -> Dict[str, str]:
|
|
140 |
'MARKET CONTEXT': 'Market context information not available',
|
141 |
'RISKS': 'Risk assessment not available',
|
142 |
'OPPORTUNITIES': 'Opportunity analysis not available',
|
|
|
143 |
'RECOMMENDATION': 'Investment recommendation not available'
|
144 |
}
|
145 |
|
@@ -252,6 +322,26 @@ def process_outputs(ticker_symbol, analysis_type, time_horizon, risk_tolerance,
|
|
252 |
market_data = stock.history(period='1y')
|
253 |
if market_data.empty:
|
254 |
raise ValueError("No data found for the specified ticker symbol.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
|
256 |
technical_data = calculate_basic_indicators(market_data)
|
257 |
market_data_json = technical_data.to_json(date_format='iso')
|
@@ -263,7 +353,14 @@ def process_outputs(ticker_symbol, analysis_type, time_horizon, risk_tolerance,
|
|
263 |
'timestamp': datetime.now()
|
264 |
}])
|
265 |
|
266 |
-
data_table['prompt'] = generate_analysis_prompt(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
267 |
data_table['analysis'] = openai.chat_completions(
|
268 |
messages=data_table.prompt,
|
269 |
model='gpt-4o-mini-2024-07-18',
|
@@ -324,15 +421,17 @@ def process_outputs(ticker_symbol, analysis_type, time_horizon, risk_tolerance,
|
|
324 |
return (
|
325 |
json.dumps(company_info_data),
|
326 |
json.dumps(market_stats_data),
|
|
|
327 |
plot,
|
328 |
parsed_analysis['SUMMARY'],
|
329 |
parsed_analysis['TECHNICAL ANALYSIS'],
|
330 |
parsed_analysis['MARKET CONTEXT'],
|
331 |
parsed_analysis['RISKS'],
|
332 |
parsed_analysis['OPPORTUNITIES'],
|
|
|
333 |
parsed_analysis['RECOMMENDATION'],
|
334 |
technical_data_with_time,
|
335 |
-
raw_llm_output
|
336 |
)
|
337 |
|
338 |
except Exception as e:
|
@@ -342,6 +441,7 @@ def process_outputs(ticker_symbol, analysis_type, time_horizon, risk_tolerance,
|
|
342 |
empty_df = pd.DataFrame()
|
343 |
|
344 |
return (
|
|
|
345 |
empty_json,
|
346 |
empty_json,
|
347 |
None,
|
@@ -351,8 +451,9 @@ def process_outputs(ticker_symbol, analysis_type, time_horizon, risk_tolerance,
|
|
351 |
no_data_msg,
|
352 |
no_data_msg,
|
353 |
no_data_msg,
|
|
|
354 |
empty_df,
|
355 |
-
f"Error occurred: {str(e)}"
|
356 |
)
|
357 |
|
358 |
def create_interface() -> gr.Blocks:
|
@@ -472,6 +573,11 @@ def create_interface() -> gr.Blocks:
|
|
472 |
label="Market Statistics",
|
473 |
height=150
|
474 |
)
|
|
|
|
|
|
|
|
|
|
|
475 |
|
476 |
with gr.TabItem("📑 Historical Data"):
|
477 |
technical_data = gr.DataFrame(
|
@@ -544,6 +650,14 @@ def create_interface() -> gr.Blocks:
|
|
544 |
max_lines=7,
|
545 |
show_label=True
|
546 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
547 |
|
548 |
with gr.Row():
|
549 |
recommendation = gr.Textbox(
|
@@ -606,10 +720,10 @@ def create_interface() -> gr.Blocks:
|
|
606 |
investment_style, technical_depth
|
607 |
],
|
608 |
outputs=[
|
609 |
-
company_info, market_stats, plot_output,
|
610 |
summary, tech_analysis, market_context,
|
611 |
-
risks, opportunities, recommendation,
|
612 |
-
technical_data, raw_output
|
613 |
]
|
614 |
)
|
615 |
|
|
|
55 |
return df.ffill().bfill()
|
56 |
|
57 |
@pxt.udf
|
58 |
+
def generate_analysis_prompt(data: str, analysis_type: str, time_horizon: str,
|
59 |
+
risk_tolerance: str, investment_style: str,
|
60 |
+
technical_depth: str) -> list[dict]:
|
61 |
"""Generate a structured prompt for AI analysis"""
|
62 |
+
|
63 |
+
# Create specific guidance based on parameters
|
64 |
+
time_horizon_guidance = {
|
65 |
+
'short': 'Focus on short-term trading opportunities within 1-3 months. Emphasize technical signals and immediate catalysts.',
|
66 |
+
'medium': 'Balance short-term opportunities with medium-term trends over 3-12 months. Consider both technical and fundamental factors.',
|
67 |
+
'long': 'Prioritize long-term growth potential over 1+ years. Emphasize fundamental analysis and strategic positioning.'
|
68 |
+
}
|
69 |
+
|
70 |
+
risk_tolerance_guidance = {
|
71 |
+
'conservative': 'Prioritize capital preservation. Focus on stable, large-cap stocks with strong fundamentals. Suggest conservative options strategies like covered calls.',
|
72 |
+
'moderate': 'Balance growth opportunities with risk management. Consider mid-cap stocks and moderate options strategies.',
|
73 |
+
'aggressive': 'Seek high-growth opportunities. Include small-cap stocks and more aggressive options strategies in the analysis.'
|
74 |
+
}
|
75 |
+
|
76 |
+
investment_style_guidance = {
|
77 |
+
'value': 'Focus on valuation metrics, margin of safety, and undervalued opportunities.',
|
78 |
+
'growth': 'Emphasize revenue growth, market expansion, and future potential.',
|
79 |
+
'momentum': 'Focus on price trends, relative strength, and technical indicators.',
|
80 |
+
'balanced': 'Consider both value and growth factors, maintaining a balanced perspective.',
|
81 |
+
'income': 'Prioritize dividend yield, payout ratio, and income-generating options strategies.'
|
82 |
+
}
|
83 |
+
|
84 |
+
analysis_depth = {
|
85 |
+
'comprehensive': 'Provide detailed analysis across all categories.',
|
86 |
+
'quantitative': 'Focus on numerical metrics and statistical analysis.',
|
87 |
+
'technical': 'Emphasize technical analysis and chart patterns.'
|
88 |
+
}
|
89 |
+
|
90 |
+
technical_guidance = {
|
91 |
+
'basic': 'Focus on essential technical indicators (MA, RSI, MACD).',
|
92 |
+
'advanced': 'Include advanced technical analysis including Fibonacci levels, Elliott Wave patterns, and advanced options analysis.'
|
93 |
+
}
|
94 |
+
|
95 |
+
system_prompt = f'''You are a senior investment advisor and market analyst with decades of experience, holding CFA and CMT certifications. Provide analysis tailored to the following parameters:
|
96 |
+
|
97 |
+
TIME HORIZON: {time_horizon.upper()}
|
98 |
+
{time_horizon_guidance[time_horizon]}
|
99 |
+
|
100 |
+
RISK PROFILE: {risk_tolerance.upper()}
|
101 |
+
{risk_tolerance_guidance[risk_tolerance]}
|
102 |
+
|
103 |
+
INVESTMENT STYLE: {investment_style.upper()}
|
104 |
+
{investment_style_guidance[investment_style]}
|
105 |
+
|
106 |
+
ANALYSIS FOCUS: {analysis_type.upper()}
|
107 |
+
{analysis_depth[analysis_type]}
|
108 |
+
|
109 |
+
TECHNICAL DEPTH: {technical_depth.upper()}
|
110 |
+
{technical_guidance[technical_depth]}
|
111 |
+
|
112 |
+
Structure your response using EXACTLY the following format and sections:
|
113 |
|
114 |
SUMMARY
|
115 |
+
Provide a clear 2-3 sentence executive summary aligned with the specified time horizon ({time_horizon}) and risk tolerance ({risk_tolerance}).
|
116 |
|
117 |
TECHNICAL ANALYSIS
|
118 |
+
{technical_guidance[technical_depth]}
|
119 |
+
• Moving Averages: Analyze trends with emphasis on {time_horizon} timeframe
|
120 |
• RSI Analysis: Current RSI level and implications
|
121 |
+
• MACD Analysis: Signal trends relevant to {time_horizon} horizon
|
122 |
• Volume Analysis: Notable volume patterns and implications
|
123 |
+
{"• Advanced Patterns: Fibonacci levels, Elliott Wave analysis" if technical_depth == "advanced" else ""}
|
124 |
|
125 |
MARKET CONTEXT
|
126 |
+
• Sector Analysis: {"Long-term industry trends and positioning" if time_horizon == "long" else "Short-term sector momentum" if time_horizon == "short" else "Medium-term sector outlook"}
|
127 |
+
• {"Fundamental Drivers: Key growth catalysts" if investment_style == "growth" else "Value Metrics: Key valuation catalysts" if investment_style == "value" else "Market Dynamics: Key price catalysts"}
|
128 |
+
• Economic Impact: Factors relevant to {time_horizon} horizon
|
129 |
|
130 |
RISKS
|
131 |
+
• Identify and quantify risks specific to {risk_tolerance} risk tolerance
|
132 |
+
• Focus on {time_horizon} horizon risks
|
133 |
+
• {"Include volatility analysis" if technical_depth == "advanced" else ""}
|
134 |
|
135 |
OPPORTUNITIES
|
136 |
+
• Align opportunities with {investment_style} style
|
137 |
+
• Focus on {time_horizon} timeline
|
138 |
+
• Match risk/reward to {risk_tolerance} profile
|
139 |
+
|
140 |
+
OPTIONS STRATEGY
|
141 |
+
{"• Advanced Options Analysis: Complex strategies and volatility analysis" if technical_depth == "advanced" else "• Basic Options Strategies: Simple hedging and income generation"}
|
142 |
+
• Tailor strategies to {risk_tolerance} risk tolerance
|
143 |
+
• Focus on {time_horizon} expiration cycles
|
144 |
+
• Match strategies to {investment_style} style objectives
|
145 |
|
146 |
RECOMMENDATION
|
147 |
+
• Provide specific recommendations aligned with:
|
148 |
+
- {time_horizon.capitalize()} time horizon
|
149 |
+
- {risk_tolerance.capitalize()} risk tolerance
|
150 |
+
- {investment_style.capitalize()} investment style
|
151 |
+
• Include position sizing appropriate for risk level
|
152 |
+
• Specify entry, exit, and stop-loss levels
|
153 |
+
• {"Include advanced technical levels" if technical_depth == "advanced" else "Focus on key support/resistance levels"}
|
154 |
+
|
155 |
+
IMPORTANT: This analysis is for informational purposes only. All investments carry risk. Please consult with a licensed financial advisor before making investment decisions.'''
|
156 |
|
157 |
return [
|
158 |
{'role': 'system', 'content': system_prompt},
|
159 |
+
{'role': 'user', 'content': f'Analyze this market data considering the specified parameters:\n{data}'}
|
160 |
]
|
161 |
|
162 |
def parse_analysis_response(response: str) -> Dict[str, str]:
|
|
|
167 |
'MARKET CONTEXT': None,
|
168 |
'RISKS': None,
|
169 |
'OPPORTUNITIES': None,
|
170 |
+
'OPTIONS STRATEGY': None,
|
171 |
'RECOMMENDATION': None
|
172 |
}
|
173 |
|
|
|
209 |
'MARKET CONTEXT': 'Market context information not available',
|
210 |
'RISKS': 'Risk assessment not available',
|
211 |
'OPPORTUNITIES': 'Opportunity analysis not available',
|
212 |
+
'OPTIONS STRATEGY': 'Options trading analysis not available',
|
213 |
'RECOMMENDATION': 'Investment recommendation not available'
|
214 |
}
|
215 |
|
|
|
322 |
market_data = stock.history(period='1y')
|
323 |
if market_data.empty:
|
324 |
raise ValueError("No data found for the specified ticker symbol.")
|
325 |
+
options_data = stock.options # Get available expiration dates
|
326 |
+
|
327 |
+
if len(options_data) > 0:
|
328 |
+
nearest_expiry = options_data[0]
|
329 |
+
opt_chain = stock.option_chain(nearest_expiry)
|
330 |
+
options_info = {
|
331 |
+
'Nearest Expiry': nearest_expiry,
|
332 |
+
'Call Volume': int(opt_chain.calls['volume'].sum()),
|
333 |
+
'Put Volume': int(opt_chain.puts['volume'].sum()),
|
334 |
+
'Put/Call Ratio': float(opt_chain.puts['volume'].sum() / opt_chain.calls['volume'].sum()),
|
335 |
+
'Implied Volatility': float(opt_chain.calls['impliedVolatility'].mean())
|
336 |
+
}
|
337 |
+
else:
|
338 |
+
options_info = {
|
339 |
+
'Nearest Expiry': 'N/A',
|
340 |
+
'Call Volume': 0,
|
341 |
+
'Put Volume': 0,
|
342 |
+
'Put/Call Ratio': 0,
|
343 |
+
'Implied Volatility': 0
|
344 |
+
}
|
345 |
|
346 |
technical_data = calculate_basic_indicators(market_data)
|
347 |
market_data_json = technical_data.to_json(date_format='iso')
|
|
|
353 |
'timestamp': datetime.now()
|
354 |
}])
|
355 |
|
356 |
+
data_table['prompt'] = generate_analysis_prompt(
|
357 |
+
data_table.data,
|
358 |
+
analysis_type,
|
359 |
+
time_horizon,
|
360 |
+
risk_tolerance,
|
361 |
+
investment_style,
|
362 |
+
technical_depth
|
363 |
+
)
|
364 |
data_table['analysis'] = openai.chat_completions(
|
365 |
messages=data_table.prompt,
|
366 |
model='gpt-4o-mini-2024-07-18',
|
|
|
421 |
return (
|
422 |
json.dumps(company_info_data),
|
423 |
json.dumps(market_stats_data),
|
424 |
+
json.dumps(options_info), # Add options info to return values
|
425 |
plot,
|
426 |
parsed_analysis['SUMMARY'],
|
427 |
parsed_analysis['TECHNICAL ANALYSIS'],
|
428 |
parsed_analysis['MARKET CONTEXT'],
|
429 |
parsed_analysis['RISKS'],
|
430 |
parsed_analysis['OPPORTUNITIES'],
|
431 |
+
parsed_analysis['OPTIONS STRATEGY'], # Add options strategy
|
432 |
parsed_analysis['RECOMMENDATION'],
|
433 |
technical_data_with_time,
|
434 |
+
raw_llm_output
|
435 |
)
|
436 |
|
437 |
except Exception as e:
|
|
|
441 |
empty_df = pd.DataFrame()
|
442 |
|
443 |
return (
|
444 |
+
empty_json,
|
445 |
empty_json,
|
446 |
empty_json,
|
447 |
None,
|
|
|
451 |
no_data_msg,
|
452 |
no_data_msg,
|
453 |
no_data_msg,
|
454 |
+
no_data_msg,
|
455 |
empty_df,
|
456 |
+
f"Error occurred: {str(e)}"
|
457 |
)
|
458 |
|
459 |
def create_interface() -> gr.Blocks:
|
|
|
573 |
label="Market Statistics",
|
574 |
height=150
|
575 |
)
|
576 |
+
with gr.Column(scale=1):
|
577 |
+
options_info = gr.JSON(
|
578 |
+
label="Options Market Data",
|
579 |
+
height=150
|
580 |
+
)
|
581 |
|
582 |
with gr.TabItem("📑 Historical Data"):
|
583 |
technical_data = gr.DataFrame(
|
|
|
650 |
max_lines=7,
|
651 |
show_label=True
|
652 |
)
|
653 |
+
|
654 |
+
with gr.Row():
|
655 |
+
options_strategy = gr.Textbox(
|
656 |
+
label="Options Trading Strategy",
|
657 |
+
lines=8,
|
658 |
+
max_lines=10,
|
659 |
+
show_label=True
|
660 |
+
)
|
661 |
|
662 |
with gr.Row():
|
663 |
recommendation = gr.Textbox(
|
|
|
720 |
investment_style, technical_depth
|
721 |
],
|
722 |
outputs=[
|
723 |
+
company_info, market_stats, options_info, plot_output,
|
724 |
summary, tech_analysis, market_context,
|
725 |
+
risks, opportunities, options_strategy, recommendation,
|
726 |
+
technical_data, raw_output
|
727 |
]
|
728 |
)
|
729 |
|