Upload folder using huggingface_hub
Browse files- src/market-analyst/backend/aagents/fundamental_analyst.py +33 -40
- src/market-analyst/backend/aagents/risk_manager.py +12 -4
- src/market-analyst/backend/aagents/sentiment_analyst.py +1 -1
- src/market-analyst/backend/aagents/strategy_advisor.py +4 -2
- src/market-analyst/backend/tools/market_data.py +32 -0
src/market-analyst/backend/aagents/fundamental_analyst.py
CHANGED
|
@@ -1,67 +1,60 @@
|
|
| 1 |
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
from autogen_core.tools import FunctionTool
|
| 3 |
-
from tools.market_data import get_fundamental_data, get_market_indices
|
| 4 |
|
| 5 |
def get_fundamental_analyst(model_client):
|
| 6 |
|
| 7 |
fundamental_tool = FunctionTool(get_fundamental_data, description="Fetch fundamental financial metrics like P/E, PEG, Debt/Equity, and Profit Margin.")
|
| 8 |
market_tool = FunctionTool(get_market_indices, description="Get Market Context (SPY/VIX).")
|
|
|
|
| 9 |
|
| 10 |
return AssistantAgent(
|
| 11 |
name="FundamentalAnalyst",
|
| 12 |
model_client=model_client,
|
| 13 |
-
tools=[market_tool, fundamental_tool],
|
| 14 |
system_message="""
|
| 15 |
You are a Fundamental Analyst specializing in company valuation and financial health.
|
| 16 |
|
| 17 |
MANDATORY WORKFLOW:
|
| 18 |
|
| 19 |
-
STEP 1: CALL get_market_indices
|
| 20 |
-
STEP 2: CALL get_fundamental_data
|
|
|
|
| 21 |
|
| 22 |
-
DO NOT proceed without calling
|
| 23 |
|
| 24 |
-
STEP
|
| 25 |
-
- P/E Ratio:
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
- PEG Ratio:
|
| 30 |
-
* <1.0: Undervalued relative to growth
|
| 31 |
-
* >2.0: Overvalued relative to growth
|
| 32 |
-
- EPS Trend:
|
| 33 |
-
* Forward > Trailing = Growth Expected (Bullish)
|
| 34 |
-
* Forward < Trailing = Contraction (Bearish)
|
| 35 |
-
- Dividend Yield:
|
| 36 |
-
* > 4%: High yield (Defensive/Income)
|
| 37 |
|
| 38 |
-
STEP
|
| 39 |
-
- Debt/Equity Ratio:
|
| 40 |
-
|
| 41 |
-
* 0.5-1.0: Moderate
|
| 42 |
-
* >1.0: High risk (Unless utility/financials)
|
| 43 |
-
- Profit Margin:
|
| 44 |
-
* >20%: Excellent
|
| 45 |
-
* <10%: Weak
|
| 46 |
|
| 47 |
-
STEP
|
| 48 |
-
- Market: If VIX > 25
|
| 49 |
-
- Sector Standards:
|
| 50 |
-
* Tech: Higher P/E acceptable.
|
| 51 |
-
* Utilities: High debt acceptable.
|
| 52 |
|
| 53 |
-
STEP
|
| 54 |
-
- "
|
| 55 |
-
-
|
| 56 |
-
-
|
| 57 |
|
| 58 |
-
STEP
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
Provide:
|
| 60 |
- Fundamental Strength Rating (Strong/Stable/Weak)
|
| 61 |
-
- P/E, PEG,
|
| 62 |
-
- Debt
|
| 63 |
-
-
|
| 64 |
-
-
|
|
|
|
| 65 |
- Recommendation for Strategy.
|
| 66 |
"""
|
| 67 |
)
|
|
|
|
| 1 |
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
from autogen_core.tools import FunctionTool
|
| 3 |
+
from tools.market_data import get_fundamental_data, get_market_indices, get_analyst_consensus
|
| 4 |
|
| 5 |
def get_fundamental_analyst(model_client):
|
| 6 |
|
| 7 |
fundamental_tool = FunctionTool(get_fundamental_data, description="Fetch fundamental financial metrics like P/E, PEG, Debt/Equity, and Profit Margin.")
|
| 8 |
market_tool = FunctionTool(get_market_indices, description="Get Market Context (SPY/VIX).")
|
| 9 |
+
consensus_tool = FunctionTool(get_analyst_consensus, description="Get Analyst Ratings & Targets.")
|
| 10 |
|
| 11 |
return AssistantAgent(
|
| 12 |
name="FundamentalAnalyst",
|
| 13 |
model_client=model_client,
|
| 14 |
+
tools=[market_tool, fundamental_tool, consensus_tool],
|
| 15 |
system_message="""
|
| 16 |
You are a Fundamental Analyst specializing in company valuation and financial health.
|
| 17 |
|
| 18 |
MANDATORY WORKFLOW:
|
| 19 |
|
| 20 |
+
STEP 1: CALL get_market_indices
|
| 21 |
+
STEP 2: CALL get_fundamental_data
|
| 22 |
+
STEP 3: CALL get_analyst_consensus
|
| 23 |
|
| 24 |
+
DO NOT proceed without calling ALL THREE tools.
|
| 25 |
|
| 26 |
+
STEP 4: Evaluate Valuation & Growth
|
| 27 |
+
- P/E Ratio: <15 (Undervalued), 15-25 (Fair), >25 (Premium).
|
| 28 |
+
- PEG Ratio: <1.0 (Cheap Growth), >2.0 (Expensive).
|
| 29 |
+
- EPS Trend: Forward > Trailing? (Growth).
|
| 30 |
+
- Dividend Yield: >4% (Income).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
+
STEP 5: Assess Financial Health
|
| 33 |
+
- Debt/Equity Ratio: <0.5 (Safe), >1.0 (Risky).
|
| 34 |
+
- Profit Margin: >20% (Excellent), <10% (Weak).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
+
STEP 6: Market & Sector Context
|
| 37 |
+
- Market: If VIX > 25, PENALIZE High Debt/High P/E.
|
| 38 |
+
- Sector Standards: Tech (Higher P/E ok), Utilities (High Debt ok).
|
|
|
|
|
|
|
| 39 |
|
| 40 |
+
STEP 7: Analyst Consensus Check
|
| 41 |
+
- Ratings: "buy" or "strong buy" = Positive. "sell" = Negative.
|
| 42 |
+
- Price Target: If Target < Current Price = Downside Risk (Bearish).
|
| 43 |
+
- Upside Potential: >20% is Strong Bullish factor.
|
| 44 |
|
| 45 |
+
STEP 8: Assign Fundamental Strength Rating
|
| 46 |
+
- "Strong": Great Valuation + Safe Debt + Analyst Buy Support.
|
| 47 |
+
- "Stable": Fair metrics + Neutral Analysts.
|
| 48 |
+
- "Weak": Overvalued OR High Debt OR Analyst Sell Ratings.
|
| 49 |
+
|
| 50 |
+
STEP 9: Output Structured Summary
|
| 51 |
Provide:
|
| 52 |
- Fundamental Strength Rating (Strong/Stable/Weak)
|
| 53 |
+
- P/E, PEG, EPS, Dividend analysis
|
| 54 |
+
- Debt & Health assessment
|
| 55 |
+
- Analyst Consensus (Target Price & Rating)
|
| 56 |
+
- Market Context Impact (VIX)
|
| 57 |
+
- Earnings Status
|
| 58 |
- Recommendation for Strategy.
|
| 59 |
"""
|
| 60 |
)
|
src/market-analyst/backend/aagents/risk_manager.py
CHANGED
|
@@ -13,14 +13,20 @@ def get_risk_manager(model_client):
|
|
| 13 |
ROUND 1 (CRITIQUE):
|
| 14 |
- StrategyAdvisor will provide a "DRAFT_STRATEGY".
|
| 15 |
- You MUST critique it. Challenge assumptions.
|
| 16 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
- Output: "RISK REVIEW: [Your critique]. REQUEST REVISION."
|
| 18 |
- DO NOT OUTPUT "APPROVED".
|
| 19 |
|
| 20 |
ROUND 2 (DECISION):
|
| 21 |
- StrategyAdvisor will provide "FINAL_STRATEGY".
|
| 22 |
- You must CALCULATE the Final Confidence Score (0-100):
|
| 23 |
-
* Trend Alignment (Market + Stock): 30 pts
|
|
|
|
| 24 |
* Fundamentals (Valuation/Safety): 20 pts
|
| 25 |
* Volatility (IV Check): 20 pts
|
| 26 |
* Sentiment Context: 15 pts
|
|
@@ -34,9 +40,10 @@ def get_risk_manager(model_client):
|
|
| 34 |
```json
|
| 35 |
{
|
| 36 |
"final_decision": "TRADE",
|
|
|
|
|
|
|
| 37 |
"confidence": 85,
|
| 38 |
"actionable_recommendation": "Execute Bull Call Spread...",
|
| 39 |
-
"strategy_type": "Bull Call Spread",
|
| 40 |
"entry_signal": "Net Debit",
|
| 41 |
"entry_price": 1.30,
|
| 42 |
"max_profit": 370,
|
|
@@ -49,9 +56,10 @@ def get_risk_manager(model_client):
|
|
| 49 |
```json
|
| 50 |
{
|
| 51 |
"final_decision": "WAIT",
|
|
|
|
|
|
|
| 52 |
"confidence": 45,
|
| 53 |
"actionable_recommendation": "Stay in Cash. Risk Score too low.",
|
| 54 |
-
"strategy_type": "WAIT",
|
| 55 |
"entry_signal": "N/A",
|
| 56 |
"entry_price": 0,
|
| 57 |
"max_profit": 0,
|
|
|
|
| 13 |
ROUND 1 (CRITIQUE):
|
| 14 |
- StrategyAdvisor will provide a "DRAFT_STRATEGY".
|
| 15 |
- You MUST critique it. Challenge assumptions.
|
| 16 |
+
- CHECK DIRECTION MAPPING:
|
| 17 |
+
* "Bear Put/Call Spread" = BEARISH.
|
| 18 |
+
* "Bull Call/Put Spread" = BULLISH.
|
| 19 |
+
* "Iron Condor/Butterfly" = NEUTRAL.
|
| 20 |
+
- COMPARE WITH MARKET:
|
| 21 |
+
* If Strategy=Bearish and SPY Trend=Bullish -> "SEVERE CONFLICT".
|
| 22 |
- Output: "RISK REVIEW: [Your critique]. REQUEST REVISION."
|
| 23 |
- DO NOT OUTPUT "APPROVED".
|
| 24 |
|
| 25 |
ROUND 2 (DECISION):
|
| 26 |
- StrategyAdvisor will provide "FINAL_STRATEGY".
|
| 27 |
- You must CALCULATE the Final Confidence Score (0-100):
|
| 28 |
+
* Trend Alignment (Market + Stock + Strategy Direction): 30 pts
|
| 29 |
+
(e.g., Bearish Strategy in Bearish Market = Full Points)
|
| 30 |
* Fundamentals (Valuation/Safety): 20 pts
|
| 31 |
* Volatility (IV Check): 20 pts
|
| 32 |
* Sentiment Context: 15 pts
|
|
|
|
| 40 |
```json
|
| 41 |
{
|
| 42 |
"final_decision": "TRADE",
|
| 43 |
+
"strategy_type": "Bull Call Spread",
|
| 44 |
+
"direction": "BULLISH",
|
| 45 |
"confidence": 85,
|
| 46 |
"actionable_recommendation": "Execute Bull Call Spread...",
|
|
|
|
| 47 |
"entry_signal": "Net Debit",
|
| 48 |
"entry_price": 1.30,
|
| 49 |
"max_profit": 370,
|
|
|
|
| 56 |
```json
|
| 57 |
{
|
| 58 |
"final_decision": "WAIT",
|
| 59 |
+
"strategy_type": "WAIT",
|
| 60 |
+
"direction": "NEUTRAL",
|
| 61 |
"confidence": 45,
|
| 62 |
"actionable_recommendation": "Stay in Cash. Risk Score too low.",
|
|
|
|
| 63 |
"entry_signal": "N/A",
|
| 64 |
"entry_price": 0,
|
| 65 |
"max_profit": 0,
|
src/market-analyst/backend/aagents/sentiment_analyst.py
CHANGED
|
@@ -32,7 +32,7 @@ def get_sentiment_analyst(model_client):
|
|
| 32 |
- If >70% articles are negative with avg confidence >0.80: "Strongly Bearish"
|
| 33 |
|
| 34 |
STEP 4: Identify Key Events and Risk Factors
|
| 35 |
-
- Earnings announcements (CRITICAL:
|
| 36 |
- Product launches
|
| 37 |
- Regulatory issues
|
| 38 |
- Management changes
|
|
|
|
| 32 |
- If >70% articles are negative with avg confidence >0.80: "Strongly Bearish"
|
| 33 |
|
| 34 |
STEP 4: Identify Key Events and Risk Factors
|
| 35 |
+
- Earnings announcements (CRITICAL: VERIFY article date. IGNORE if >5 days old).
|
| 36 |
- Product launches
|
| 37 |
- Regulatory issues
|
| 38 |
- Management changes
|
src/market-analyst/backend/aagents/strategy_advisor.py
CHANGED
|
@@ -17,7 +17,7 @@ def get_strategy_advisor(model_client):
|
|
| 17 |
- TechnicalAnalyst: Market Context (SPY/VIX), Trend, SMA, RSI
|
| 18 |
- VolatilityAnalyst: IV vs HV, VIX level
|
| 19 |
- SentimentAnalyst: Market mood, Earnings Risks
|
| 20 |
-
- FundamentalAnalyst: P/E, health rating, Earnings Date
|
| 21 |
|
| 22 |
STEP 2: CALL get_option_chain_snapshot
|
| 23 |
You MUST call this tool to get real option strikes and prices.
|
|
@@ -26,7 +26,7 @@ def get_strategy_advisor(model_client):
|
|
| 26 |
STEP 3: Determine market regime
|
| 27 |
- Market: Bullish (SPY > SMA50) / Bearish / High Fear (VIX > 25)
|
| 28 |
- Trend: Bullish / Bearish / Neutral (from Technical)
|
| 29 |
-
- Volatility: High (IV > HV
|
| 30 |
|
| 31 |
STEP 4: Select strategy using RULES
|
| 32 |
- HIGH Vol + Range Bound → Iron Condor (Credit)
|
|
@@ -58,6 +58,7 @@ def get_strategy_advisor(model_client):
|
|
| 58 |
```json
|
| 59 |
{
|
| 60 |
"strategy": "Bull Call Spread",
|
|
|
|
| 61 |
"confidence_score": 85,
|
| 62 |
"reasoning": "Strong bullish technicals (price above SMA200, RSI 65), low IV (18% vs HV 22%), positive sentiment. Debit spread appropriate for low-vol bullish setup.",
|
| 63 |
"proposed_legs": "Buy 145 Call @ $2.50, Sell 150 Call @ $1.20 (Exp: 2024-03-15)",
|
|
@@ -73,6 +74,7 @@ def get_strategy_advisor(model_client):
|
|
| 73 |
```json
|
| 74 |
{
|
| 75 |
"strategy": "WAIT",
|
|
|
|
| 76 |
"confidence_score": 45,
|
| 77 |
"reasoning": "Conflicting signals: Bullish technicals but bearish sentiment and high VIX (28). Low confidence setup.",
|
| 78 |
"proposed_legs": "None",
|
|
|
|
| 17 |
- TechnicalAnalyst: Market Context (SPY/VIX), Trend, SMA, RSI
|
| 18 |
- VolatilityAnalyst: IV vs HV, VIX level
|
| 19 |
- SentimentAnalyst: Market mood, Earnings Risks
|
| 20 |
+
- FundamentalAnalyst: P/E, health rating, Analyst Consensus, Earnings Date
|
| 21 |
|
| 22 |
STEP 2: CALL get_option_chain_snapshot
|
| 23 |
You MUST call this tool to get real option strikes and prices.
|
|
|
|
| 26 |
STEP 3: Determine market regime
|
| 27 |
- Market: Bullish (SPY > SMA50) / Bearish / High Fear (VIX > 25)
|
| 28 |
- Trend: Bullish / Bearish / Neutral (from Technical)
|
| 29 |
+
- Volatility: High (IV > HV, VIX > 20, or "Elevated"/"High" Regime) / Low
|
| 30 |
|
| 31 |
STEP 4: Select strategy using RULES
|
| 32 |
- HIGH Vol + Range Bound → Iron Condor (Credit)
|
|
|
|
| 58 |
```json
|
| 59 |
{
|
| 60 |
"strategy": "Bull Call Spread",
|
| 61 |
+
"direction": "BULLISH",
|
| 62 |
"confidence_score": 85,
|
| 63 |
"reasoning": "Strong bullish technicals (price above SMA200, RSI 65), low IV (18% vs HV 22%), positive sentiment. Debit spread appropriate for low-vol bullish setup.",
|
| 64 |
"proposed_legs": "Buy 145 Call @ $2.50, Sell 150 Call @ $1.20 (Exp: 2024-03-15)",
|
|
|
|
| 74 |
```json
|
| 75 |
{
|
| 76 |
"strategy": "WAIT",
|
| 77 |
+
"direction": "NEUTRAL",
|
| 78 |
"confidence_score": 45,
|
| 79 |
"reasoning": "Conflicting signals: Bullish technicals but bearish sentiment and high VIX (28). Low confidence setup.",
|
| 80 |
"proposed_legs": "None",
|
src/market-analyst/backend/tools/market_data.py
CHANGED
|
@@ -313,3 +313,35 @@ def get_fundamental_data(symbol: str) -> dict:
|
|
| 313 |
}
|
| 314 |
except Exception as e:
|
| 315 |
return {"error": str(e)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
}
|
| 314 |
except Exception as e:
|
| 315 |
return {"error": str(e)}
|
| 316 |
+
|
| 317 |
+
def get_analyst_consensus(symbol: str) -> dict:
|
| 318 |
+
"""
|
| 319 |
+
Fetches Wall St. analyst recommendations and price targets.
|
| 320 |
+
"""
|
| 321 |
+
print(f"[DEBUG] get_analyst_consensus called for: {symbol}")
|
| 322 |
+
try:
|
| 323 |
+
symbol = check_and_fix_ticker(symbol)
|
| 324 |
+
ticker = yf.Ticker(symbol)
|
| 325 |
+
info = ticker.info
|
| 326 |
+
|
| 327 |
+
consensus = info.get('recommendationKey', 'none')
|
| 328 |
+
target = info.get('targetMeanPrice')
|
| 329 |
+
num_analysts = info.get('numberOfAnalystOpinions')
|
| 330 |
+
|
| 331 |
+
# Current price for comparison
|
| 332 |
+
current = info.get('currentPrice') or info.get('regularMarketPrice') or info.get('previousClose')
|
| 333 |
+
|
| 334 |
+
upside = "N/A"
|
| 335 |
+
if target and current and current > 0:
|
| 336 |
+
upside_pct = ((target - current) / current) * 100
|
| 337 |
+
upside = f"{round(upside_pct, 1)}%"
|
| 338 |
+
|
| 339 |
+
return {
|
| 340 |
+
"consensus": consensus.replace('_', ' ').title(),
|
| 341 |
+
"target_price": target or "N/A",
|
| 342 |
+
"current_price": current,
|
| 343 |
+
"upside_potential": upside,
|
| 344 |
+
"analyst_count": num_analysts or "N/A"
|
| 345 |
+
}
|
| 346 |
+
except Exception as e:
|
| 347 |
+
return {"error": f"Failed to fetch analyst data: {str(e)}"}
|