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 |
|