
Super Hedge Fund Skill
- 10 installs
- 5 repo stars
- Updated March 7, 2026
- stanleychanh/super-hedge-fund-skill
Helps with ai & agent building tasks.
About
super-hedge-fund-skill is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- super-hedge-fund-skill
- AI & Agent Building
- AI-coding skill
Super Hedge Fund Skill by the numbers
- 10 all-time installs (skills.sh)
- Ranked #11,959 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/stanleychanh/super-hedge-fund-skill --skill super-hedge-fund-skillAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 10 |
|---|---|
| repo stars | ★ 5 |
| Last updated | March 7, 2026 |
| Repository | stanleychanh/super-hedge-fund-skill ↗ |
What it does
Helps with ai & agent building tasks.
Files
Super Hedge Fund Skill
Multi-agent stock analysis system combining rule-based analytics with Claude-powered investor personas.
⚠️ Educational purposes only - NOT investment advice
Workflow
digraph workflow {
rankdir=TB;
node [shape=box, style="filled,rounded", fillcolor="#f0f0f0"];
input [label="1. Parse Input\nExtract tickers"];
data [label="2. Fetch Data\nPrice/Financials/News"];
agents [label="3. Run Agents\nRule + Claude"];
risk [label="4. Risk Analysis\nVolatility/Position"];
output [label="5. Generate Report\nMarkdown"];
input -> data -> agents -> risk -> output;
}Agents Quick Reference
| Agent | Type | Focus |
|---|---|---|
| Fundamental | Rule | ROE, margins, debt, growth |
| Technical | Rule | EMA, RSI, MACD, momentum |
| Valuation | Rule | DCF, Owner Earnings |
| Sentiment | Rule+Claude | News, insider trades |
| Buffett | Claude | Moat, ROE, intrinsic value |
| Wood | Claude | Disruptive tech, growth |
| Burry | Claude | Deep value, contrarian |
| Lynch | Claude | PEG, understandable biz |
Execution
Step 1: Parse Input
Extract: ticker symbols, date range, capital
Mode: full (default) or briefStep 2: Fetch Data
Use WebSearch for:
- Current price & 52-week range
- Financial metrics (ROE, P/E, margins, debt)
- Recent news headlinesStep 3: Run Agents
Rule-based (deterministic):
- Fundamental analysis → signal + confidence
- Technical analysis → signal + confidence
- Valuation analysis → signal + confidence
Claude-powered (interpretive):
- For each investor persona, analyze with their philosophy
- Return: {signal, confidence, reasoning}Step 4: Risk Analysis
Calculate: annual volatility from price data
Determine: risk level → position limit
- Low (<15%): 25% max
- Medium (15-30%): 20% max
- High (30-50%): 15% max
- Very High (>50%): 10% maxStep 5: Aggregate & Output
Count signals: bullish / bearish / neutral
Determine consensus by majority
Generate Markdown reportSignal Icons
| Signal | Icon |
|---|---|
| Bullish | 🟢 |
| Bearish | 🔴 |
| Neutral | 🟡 |
Common Mistakes
| Mistake | Fix |
|---|---|
| Giving real investment advice | Always add disclaimer |
| Missing data errors | Use fallback estimates |
| Single-agent reliance | Must aggregate 8+ signals |
| Overconfident signals | Show confidence %, acknowledge uncertainty |
References
references/investor-agents.md- Investor persona prompts and frameworksreferences/analysis-methods.md- Detailed scoring and calculation methodsassets/report-template.md- Markdown report template
Scripts
scripts/analysts.py- Rule-based analyst implementationsscripts/investor_prompts.py- Claude investor persona promptsscripts/report_generator.py- Markdown report generationscripts/data_fetcher.py- Data fetching utilities
🏦 AI Hedge Fund Analysis Report
Date: {date} Tickers: {tickers} Initial Capital: ${initial_capital:,.0f}
---
📊 Executive Summary
| Ticker | Action | Confidence | Rationale |
|---|
{summary_rows}
---
📈 Agent Signals
{for each ticker}
{TICKER} - {Company Name}
| Agent | Signal | Confidence | Reasoning |
|---|---|---|---|
| Fundamental | {signal} | {conf}% | {reason} |
| Technical | {signal} | {conf}% | {reason} |
| Valuation | {signal} | {conf}% | {reason} |
| Sentiment | {signal} | {conf}% | {reason} |
| Buffett | {signal} | {conf}% | {reason} |
| Wood | {signal} | {conf}% | {reason} |
| Burry | {signal} | {conf}% | {reason} |
| Lynch | {signal} | {conf}% | {reason} |
Consensus: {overall_signal} (Bullish: {bullish}/Bearish: {bearish}/Neutral: {neutral})
{end for}
---
💼 Trading Decisions
| Ticker | Action | Quantity | Est. Value | Confidence | Reason |
|---|
{decision_rows}
---
⚠️ Risk Assessment
| Ticker | Volatility | Risk Level | Position Limit | Suggested |
|---|
{risk_rows}
---
📋 Portfolio Status
| Item | Value |
|---|---|
| 💵 Cash | ${cash:,.0f} |
| 📈 Position Value | ${position_value:,.0f} |
| 💰 Total Assets | ${total:,.0f} |
| 📊 Positions | {count} |
---
⚠️ Disclaimer
This report is generated by AI Hedge Fund Skill for educational and research purposes only. It does not constitute investment advice. Investing involves risk. Past performance does not guarantee future results.
Analysis Methods Reference
Fundamental Analysis (Rule-Based)
Metrics & Scoring:
| Metric | Bullish | Neutral | Bearish | Weight |
|---|---|---|---|---|
| ROE | > 20% | 10-20% | < 10% | 20% |
| Net Margin | > 20% | 10-20% | < 10% | 15% |
| Debt/Equity | < 0.3 | 0.3-0.6 | > 0.6 | 15% |
| Current Ratio | > 2.0 | 1.0-2.0 | < 1.0 | 10% |
| Revenue Growth | > 15% | 5-15% | < 5% | 20% |
| P/E Ratio | < 15 | 15-25 | > 25 | 20% |
Signal Generation:
score = sum(metric_scores * weights)
if score >= 60: signal = "bullish"
elif score <= 40: signal = "bearish"
else: signal = "neutral"
confidence = min(score, 100)---
Technical Analysis (Rule-Based)
Indicators:
| Indicator | Calculation | Signal |
|---|---|---|
| EMA Trend | EMA8 > EMA21 > EMA55 | Bullish trend |
| RSI (14) | < 30 / > 70 | Oversold/Overbought |
| MACD | Signal cross | Trend change |
| Bollinger | Price position | Mean reversion |
| ADX | > 25 | Strong trend |
Weights:
- Trend Following: 25%
- Mean Reversion: 20%
- Momentum: 25%
- Volatility: 15%
- Statistical Arbitrage: 15%
Signal Aggregation:
signal_score = (
trend_signal * 0.25 +
mean_reversion_signal * 0.20 +
momentum_signal * 0.25 +
volatility_signal * 0.15 +
stat_arb_signal * 0.15
)
if signal_score > 0.3: signal = "bullish"
elif signal_score < -0.3: signal = "bearish"
else: signal = "neutral"---
Valuation Analysis (Rule-Based)
Methods & Weights:
| Method | Weight | Description |
|---|---|---|
| DCF | 35% | 3-stage discounted cash flow |
| Owner Earnings | 35% | Buffett method |
| EV/EBITDA | 20% | Relative valuation |
| Residual Income | 10% | Edwards-Bell-Ohlson model |
DCF Valuation:
# 3-stage DCF
# Stage 1: High growth (years 1-5)
# Stage 2: Transition (years 6-10)
# Stage 3: Terminal value
pv_fcf = sum(fcf_year_n / (1 + wacc) ** n for n in 1..10)
terminal_value = fcf_year_10 * (1 + g) / (wacc - g)
intrinsic_value = pv_fcf + terminal_value / (1 + wacc) ** 10Owner Earnings (Buffett):
owner_earnings = net_income + depreciation - capex - working_capital_change
intrinsic_value = owner_earnings / (discount_rate - growth_rate)
# Apply 25% margin of safetySignal Rules:
gap = (intrinsic_value - market_cap) / market_cap
if gap > 0.15: signal = "bullish" # 15%+ undervalued
elif gap < -0.15: signal = "bearish" # 15%+ overvalued
else: signal = "neutral"---
Risk Management
Volatility Classification:
| Level | Annual Vol | Max Position |
|---|---|---|
| Low | < 15% | 25% |
| Medium | 15-30% | 20% |
| High | 30-50% | 15% |
| Very High | > 50% | 10% |
Position Sizing:
max_position = portfolio_value * base_limit * correlation_adjustmentCorrelation Adjustment:
- High correlation (≥0.8): 0.7x
- Medium-high (0.6-0.8): 0.85x
- Medium (0.4-0.6): 1.0x
- Low (0.2-0.4): 1.05x
- Very low (<0.2): 1.10x
Investor Agents Reference
Warren Buffett (Value Investing)
Philosophy: Circle of competence, economic moat, ROE > 15%, low debt, margin of safety
Analysis Framework: 1. Business Simplicity - Is it understandable? 2. Competitive Moat - Brand, cost advantage, network effects? 3. ROE Consistency - >15% for 10+ years? 4. Debt Level - Debt/Equity < 0.5? 5. Management Quality - Honest, competent, shareholder-oriented? 6. Margin of Safety - Price < Intrinsic value?
Signal Rules:
- Bullish: Wide moat + ROE > 15% + margin of safety > 0
- Bearish: Poor business OR clearly overvalued
- Neutral: Good business but no margin of safety
---
Cathie Wood (Growth Investing)
Philosophy: Disruptive innovation, AI/biotech/blockchain, long-term growth potential
Analysis Framework: 1. Disruptive Tech - AI, gene editing, fintech, robotics? 2. R&D Intensity - Investment in innovation? 3. Revenue Acceleration - Growth accelerating? 4. Market Opportunity - Large TAM? 5. First-Mover Advantage - Technology moat? 6. Management Vision - Forward-thinking leadership?
Signal Rules:
- Bullish: Disruptive tech + high growth + large TAM
- Bearish: Legacy tech or limited market
- Neutral: Potential but competitive/execution risk
---
Michael Burry (Contrarian Investing)
Philosophy: Deep value, against consensus, margin of safety, bubble detection
Analysis Framework: 1. Deep Undervaluation - Intrinsic value gap > 30%? 2. Market Misconception - What is the market missing? 3. Catalyst - What will unlock value? 4. Risk/Reward - Asymmetric upside? 5. Short Opportunity - Overvalued/bubble?
Signal Rules:
- Bullish: Severely undervalued + catalyst
- Bearish: Overvalued or bubble conditions
- Neutral: Fair value, no clear opportunity
---
Peter Lynch (GARP - Growth at Reasonable Price)
Philosophy: Invest in what you know, PEG < 1, find tenbaggers
Analysis Framework: 1. Understandable Business - Can explain in one sentence? 2. PEG Ratio - PE / Growth rate < 1? 3. Earnings Growth - Consistent growth? 4. Compounding Potential - Reinvestment opportunities? 5. Institutional Room - Room for more ownership? 6. Insider Buying - Are insiders buying?
Signal Rules:
- Bullish: PEG < 1 + consistent growth + understandable
- Bearish: PEG > 2 or growth slowing
- Neutral: Fair value, modest growth
"""
AI Hedge Fund - Analyst Agents Module
Rule-based analysis implementations
"""
import math
from typing import Dict, List, Optional, Tuple
# ============ Signal Icons ============
SIGNAL_ICONS = {
"bullish": "🟢",
"bearish": "🔴",
"neutral": "🟡"
}
# ============ Fundamental Analyst ============
def analyze_fundamentals(financials: dict) -> dict:
"""
Fundamental analysis (rule-based)
Dimensions:
- Profitability: ROE, Net Margin, Operating Margin
- Growth: Revenue Growth, Earnings Growth
- Financial Health: Debt/Equity, Current Ratio
- Valuation: P/E, P/B
Returns:
{
"signal": "bullish/bearish/neutral",
"confidence": 0-100,
"reasoning": "...",
"details": {...}
}
"""
score = 0
details = {}
reasons = []
# Profitability Analysis
roe = financials.get("roe")
if roe is not None:
roe_pct = roe * 100 if roe < 1 else roe
if roe_pct > 15:
score += 20
details["roe"] = {"value": roe_pct, "status": "excellent"}
reasons.append(f"ROE {roe_pct:.1f}%")
elif roe_pct > 10:
score += 10
details["roe"] = {"value": roe_pct, "status": "good"}
else:
details["roe"] = {"value": roe_pct, "status": "weak"}
net_margin = financials.get("net_margin")
if net_margin is not None:
margin_pct = net_margin * 100 if net_margin < 1 else net_margin
if margin_pct > 20:
score += 15
details["net_margin"] = {"value": margin_pct, "status": "excellent"}
reasons.append(f"Net Margin {margin_pct:.1f}%")
elif margin_pct > 10:
score += 8
details["net_margin"] = {"value": margin_pct, "status": "good"}
else:
details["net_margin"] = {"value": margin_pct, "status": "weak"}
# Growth Analysis
revenue_growth = financials.get("revenue_growth")
if revenue_growth is not None:
growth_pct = revenue_growth * 100 if revenue_growth < 1 else revenue_growth
if growth_pct > 10:
score += 15
details["revenue_growth"] = {"value": growth_pct, "status": "strong"}
reasons.append(f"Revenue Growth {growth_pct:.1f}%")
elif growth_pct > 0:
score += 5
details["revenue_growth"] = {"value": growth_pct, "status": "moderate"}
else:
details["revenue_growth"] = {"value": growth_pct, "status": "declining"}
# Financial Health
debt_equity = financials.get("debt_equity")
if debt_equity is not None:
if debt_equity < 0.5:
score += 10
details["debt_equity"] = {"value": debt_equity, "status": "healthy"}
reasons.append("Low debt")
elif debt_equity < 1.0:
score += 5
details["debt_equity"] = {"value": debt_equity, "status": "moderate"}
else:
details["debt_equity"] = {"value": debt_equity, "status": "high"}
# Valuation
pe_ratio = financials.get("pe_ratio")
if pe_ratio is not None and pe_ratio > 0:
if pe_ratio < 15:
score += 10
details["pe_ratio"] = {"value": pe_ratio, "status": "undervalued"}
elif pe_ratio < 25:
score += 5
details["pe_ratio"] = {"value": pe_ratio, "status": "fair"}
else:
details["pe_ratio"] = {"value": pe_ratio, "status": "expensive"}
# Generate Signal
if score >= 60:
signal = "bullish"
elif score <= 40:
signal = "bearish"
else:
signal = "neutral"
confidence = min(score, 100)
reasoning = " | ".join(reasons[:3]) if reasons else f"Overall score: {score}"
return {
"signal": signal,
"confidence": confidence,
"reasoning": reasoning,
"details": details,
"score": score
}
# ============ Technical Analyst ============
def calculate_ema(prices: List[float], period: int) -> List[float]:
"""Calculate EMA"""
if len(prices) < period:
return []
multiplier = 2 / (period + 1)
ema = [sum(prices[:period]) / period]
for price in prices[period:]:
ema.append((price - ema[-1]) * multiplier + ema[-1])
return ema
def calculate_rsi(prices: List[float], period: int = 14) -> float:
"""Calculate RSI"""
if len(prices) < period + 1:
return 50.0
deltas = [prices[i] - prices[i-1] for i in range(1, len(prices))]
gains = [d if d > 0 else 0 for d in deltas[-period:]]
losses = [-d if d < 0 else 0 for d in deltas[-period:]]
avg_gain = sum(gains) / period
avg_loss = sum(losses) / period
if avg_loss == 0:
return 100.0
rs = avg_gain / avg_loss
return 100 - (100 / (1 + rs))
def analyze_technical(prices_data: dict) -> dict:
"""
Technical analysis (rule-based)
Dimensions:
- Trend: EMA crossover, ADX
- Mean Reversion: RSI, Bollinger Bands
- Momentum: 1/3/6 month momentum
- Volatility: Historical volatility
Returns:
{
"signal": "bullish/bearish/neutral",
"confidence": 0-100,
"reasoning": "...",
"details": {...}
}
"""
closes = prices_data.get("close", [])
if len(closes) < 20:
return {
"signal": "neutral",
"confidence": 50,
"reasoning": "Insufficient data for technical analysis",
"details": {}
}
details = {}
signals = {}
# Filter None values
closes = [c for c in closes if c is not None]
if not closes:
return {"signal": "neutral", "confidence": 50, "reasoning": "Invalid data", "details": {}}
current_price = closes[-1]
# 1. Trend Following (25% weight)
ema8 = calculate_ema(closes, 8)
ema21 = calculate_ema(closes, 21)
trend_signal = 0
if ema8 and ema21:
if ema8[-1] > ema21[-1]:
trend_signal = 1
details["ema_trend"] = "bullish alignment"
else:
trend_signal = -1
details["ema_trend"] = "bearish alignment"
signals["trend"] = trend_signal * 0.25
# 2. Mean Reversion (20% weight)
rsi = calculate_rsi(closes)
details["rsi"] = rsi
mean_reversion_signal = 0
if rsi < 30:
mean_reversion_signal = 1
details["rsi_status"] = "oversold"
elif rsi > 70:
mean_reversion_signal = -1
details["rsi_status"] = "overbought"
else:
details["rsi_status"] = "neutral"
signals["mean_reversion"] = mean_reversion_signal * 0.20
# 3. Momentum (25% weight)
def calc_momentum(prices, days):
if len(prices) < days + 1:
return 0.0
return (prices[-1] - prices[-days-1]) / prices[-days-1] if prices[-days-1] else 0.0
mom_1m = calc_momentum(closes, 20)
details["momentum_1m"] = f"{mom_1m*100:.1f}%"
momentum_signal = 1 if mom_1m > 0 else -1
signals["momentum"] = momentum_signal * 0.25
# 4. Volatility (15% weight) - lower volatility = higher confidence
if len(closes) > 20:
returns = [(closes[i] - closes[i-1]) / closes[i-1] for i in range(1, len(closes))]
std_return = math.sqrt(sum((r - sum(returns)/len(returns))**2 for r in returns) / len(returns))
annual_volatility = std_return * math.sqrt(252)
details["annual_volatility"] = f"{annual_volatility*100:.1f}%"
signals["volatility"] = -0.5 * 0.15 if annual_volatility > 0.4 else 0
else:
signals["volatility"] = 0
# 5. Statistical Arbitrage (15% weight)
sma_50 = sum(closes[-50:]) / 50 if len(closes) >= 50 else sum(closes) / len(closes)
deviation = (current_price - sma_50) / sma_50
details["price_vs_sma50"] = f"{deviation*100:.1f}%"
if deviation < -0.1:
signals["stat_arb"] = 1 * 0.15
elif deviation > 0.1:
signals["stat_arb"] = -1 * 0.15
else:
signals["stat_arb"] = 0
# Aggregate Signal
total_signal = sum(signals.values())
if total_signal > 0.2:
signal = "bullish"
elif total_signal < -0.2:
signal = "bearish"
else:
signal = "neutral"
confidence = min(abs(total_signal) * 200, 100)
reasoning = f"Trend: {details.get('ema_trend', 'N/A')} | RSI: {rsi:.0f} | Momentum: {details.get('momentum_1m', 'N/A')}"
return {
"signal": signal,
"confidence": confidence,
"reasoning": reasoning,
"details": details
}
# ============ Risk Management ============
def classify_volatility(annual_volatility: float) -> Tuple[str, float]:
"""
Classify volatility level
Returns:
(risk_level, max_position_pct)
"""
if annual_volatility < 0.15:
return ("Low", 0.25)
elif annual_volatility < 0.30:
return ("Medium", 0.20)
elif annual_volatility < 0.50:
return ("High", 0.15)
else:
return ("Very High", 0.10)
def calculate_volatility(prices: List[float]) -> float:
"""Calculate annualized volatility"""
if len(prices) < 20:
return 0.25
prices = [p for p in prices if p is not None]
if len(prices) < 20:
return 0.25
returns = [(prices[i] - prices[i-1]) / prices[i-1] for i in range(1, len(prices))]
if not returns:
return 0.25
mean_return = sum(returns) / len(returns)
variance = sum((r - mean_return) ** 2 for r in returns) / len(returns)
return math.sqrt(variance) * math.sqrt(252)
def analyze_risk(prices_data: dict, portfolio: dict = None) -> dict:
"""
Risk analysis
Returns:
{
"volatility": 0.25,
"risk_level": "Medium",
"max_position_pct": 20,
"reasoning": "..."
}
"""
closes = prices_data.get("close", [])
closes = [c for c in closes if c is not None]
if not closes:
return {
"volatility": 0.25,
"risk_level": "Medium",
"max_position_pct": 20,
"reasoning": "Using default risk parameters"
}
volatility = calculate_volatility(closes)
risk_level, max_position = classify_volatility(volatility)
return {
"volatility": volatility,
"volatility_pct": f"{volatility*100:.1f}%",
"risk_level": risk_level,
"max_position_pct": max_position * 100,
"reasoning": f"Annual volatility {volatility*100:.1f}%, Risk level: {risk_level}"
}
# ============ Signal Aggregation ============
def aggregate_signals(signals: List[dict]) -> dict:
"""
Aggregate multiple analyst signals
Returns:
{
"signal": "bullish/bearish/neutral",
"confidence": 0-100,
"bullish_count": 3,
"bearish_count": 1,
"neutral_count": 2,
"weighted_score": 0.35
}
"""
if not signals:
return {
"signal": "neutral",
"confidence": 50,
"bullish_count": 0,
"bearish_count": 0,
"neutral_count": 0,
"weighted_score": 0
}
bullish_count = sum(1 for s in signals if s.get("signal") == "bullish")
bearish_count = sum(1 for s in signals if s.get("signal") == "bearish")
neutral_count = sum(1 for s in signals if s.get("signal") == "neutral")
score = 0
for s in signals:
if s.get("signal") == "bullish":
score += s.get("confidence", 50) / 100
elif s.get("signal") == "bearish":
score -= s.get("confidence", 50) / 100
weighted_score = score / len(signals) if signals else 0
if weighted_score > 0.2:
signal = "bullish"
elif weighted_score < -0.2:
signal = "bearish"
else:
signal = "neutral"
return {
"signal": signal,
"confidence": min(abs(weighted_score) * 200, 100),
"bullish_count": bullish_count,
"bearish_count": bearish_count,
"neutral_count": neutral_count,
"weighted_score": weighted_score
}
"""
AI Hedge Fund - Data Fetcher Module
Multi-source stock data fetching
"""
import json
import urllib.request
import urllib.parse
from datetime import datetime, timedelta
from typing import Optional
# Data cache
_cache = {}
_CACHE_TTL = 3600 # 1 hour
def _get_cache_key(ticker: str, data_type: str) -> str:
return f"{ticker}_{data_type}_{datetime.now().strftime('%Y%m%d%H')}"
def _fetch_url(url: str, headers: dict = None) -> dict:
"""Generic URL fetch function"""
if headers is None:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req, timeout=10) as response:
return json.loads(response.read().decode())
def get_prices_yahoo(ticker: str, days: int = 60) -> dict:
"""
Fetch historical price data from Yahoo Finance
Args:
ticker: Stock symbol
days: Number of days to fetch
Returns:
{
"ticker": "AAPL",
"dates": [...],
"open": [...],
"high": [...],
"low": [...],
"close": [...],
"volume": [...],
"success": True
}
"""
cache_key = _get_cache_key(ticker, f"prices_{days}")
if cache_key in _cache:
return _cache[cache_key]
try:
url = f"https://query1.finance.yahoo.com/v8/finance/chart/{ticker}"
params = {
"range": f"{max(days, 120)}d",
"interval": "1d",
"includePrePost": "false"
}
full_url = f"{url}?{urllib.parse.urlencode(params)}"
data = _fetch_url(full_url)
if "chart" not in data or "result" not in data["chart"]:
return {"success": False, "error": "No data found", "ticker": ticker}
result = data["chart"]["result"][0]
timestamps = result.get("timestamp", [])
quote = result.get("indicators", {}).get("quote", [{}])[0]
dates = [datetime.fromtimestamp(ts).strftime("%Y-%m-%d") for ts in timestamps[-days:]]
prices_data = {
"ticker": ticker,
"dates": dates,
"open": quote.get("open", [])[-days:],
"high": quote.get("high", [])[-days:],
"low": quote.get("low", [])[-days:],
"close": quote.get("close", [])[-days:],
"volume": quote.get("volume", [])[-days:],
"success": True
}
_cache[cache_key] = prices_data
return prices_data
except Exception as e:
return {"success": False, "error": str(e), "ticker": ticker}
def get_financials_yahoo(ticker: str) -> dict:
"""
Fetch financial metrics from Yahoo Finance
Returns:
{
"ticker": "AAPL",
"market_cap": 3000000000000,
"pe_ratio": 28.5,
"pb_ratio": 45.2,
"roe": 0.285,
"net_margin": 0.253,
"operating_margin": 0.285,
"debt_equity": 0.45,
"current_ratio": 0.85,
"revenue_growth": 0.082,
"earnings_growth": 0.115,
"dividend_yield": 0.005,
"beta": 1.25,
"success": True
}
"""
cache_key = _get_cache_key(ticker, "financials")
if cache_key in _cache:
return _cache[cache_key]
try:
url = f"https://query1.finance.yahoo.com/v10/finance/quoteSummary/{ticker}"
params = {"modules": "financialData,defaultKeyStatistics,price,earnings"}
full_url = f"{url}?{urllib.parse.urlencode(params)}"
data = _fetch_url(full_url)
if "quoteSummary" not in data or "result" not in data["quoteSummary"]:
return {"success": False, "error": "No financial data found", "ticker": ticker}
result = data["quoteSummary"]["result"][0]
financial_data = result.get("financialData", {})
key_stats = result.get("defaultKeyStatistics", {})
price_data = result.get("price", {})
def safe_get(d, *keys, default=None):
"""Safely get nested dict value"""
for key in keys:
if isinstance(d, dict) and key in d:
d = d[key]
else:
return default
return d
financials = {
"ticker": ticker,
"company_name": price_data.get("shortName", ticker),
"market_cap": safe_get(price_data, "marketCap"),
"current_price": safe_get(price_data, "regularMarketPrice"),
"pe_ratio": safe_get(key_stats, "trailingPE"),
"forward_pe": safe_get(key_stats, "forwardPE"),
"pb_ratio": safe_get(key_stats, "priceToBook"),
"ps_ratio": safe_get(key_stats, "priceToSalesTrailing12Months"),
"roe": safe_get(key_stats, "returnOnEquity"),
"roa": safe_get(key_stats, "returnOnAssets"),
"net_margin": safe_get(financial_data, "profitMargins"),
"operating_margin": safe_get(financial_data, "operatingMargins"),
"gross_margin": safe_get(financial_data, "grossMargins"),
"ebitda_margin": safe_get(key_stats, "ebitdaMargins"),
"debt_equity": safe_get(financial_data, "debtToEquity"),
"current_ratio": safe_get(financial_data, "currentRatio"),
"quick_ratio": safe_get(financial_data, "quickRatio"),
"revenue_growth": safe_get(financial_data, "revenueGrowth"),
"earnings_growth": safe_get(key_stats, "earningsGrowth"),
"revenue_ttm": safe_get(financial_data, "totalRevenue"),
"net_income_ttm": safe_get(financial_data, "netIncomeToCommon"),
"ebitda": safe_get(financial_data, "ebitda"),
"free_cashflow": safe_get(financial_data, "freeCashflow"),
"operating_cashflow": safe_get(financial_data, "operatingCashflow"),
"capital_expenditure": safe_get(financial_data, "capitalExpenditure"),
"total_debt": safe_get(financial_data, "totalDebt"),
"total_cash": safe_get(financial_data, "totalCash"),
"total_assets": safe_get(financial_data, "totalAssets"),
"total_liabilities": safe_get(financial_data, "totalLiab"),
"book_value": safe_get(key_stats, "bookValue"),
"shares_outstanding": safe_get(key_stats, "sharesOutstanding"),
"dividend_yield": safe_get(key_stats, "trailingAnnualDividendYield"),
"beta": safe_get(key_stats, "beta"),
"52_week_high": safe_get(financial_data, "fiftyTwoWeekHigh"),
"52_week_low": safe_get(financial_data, "fiftyTwoWeekLow"),
"success": True
}
# Clean None values and convert types
for key in financials:
if financials[key] is None:
continue
if isinstance(financials[key], dict) and "raw" in financials[key]:
financials[key] = financials[key]["raw"]
_cache[cache_key] = financials
return financials
except Exception as e:
return {"success": False, "error": str(e), "ticker": ticker}
def get_news_yahoo(ticker: str, limit: int = 5) -> list:
"""
Fetch news from Yahoo Finance
Returns:
[
{
"title": "Apple announces new product...",
"publisher": "Reuters",
"date": "2024-03-15",
"url": "https://..."
},
...
]
"""
cache_key = _get_cache_key(ticker, f"news_{limit}")
if cache_key in _cache:
return _cache[cache_key]
try:
url = f"https://query1.finance.yahoo.com/v1/finance/search"
params = {
"q": ticker,
"newsCount": str(limit),
"enableFuzzyQuery": "false",
"quotesCount": "0"
}
full_url = f"{url}?{urllib.parse.urlencode(params)}"
data = _fetch_url(full_url)
news_items = []
for item in data.get("news", [])[:limit]:
news_items.append({
"title": item.get("title", ""),
"publisher": item.get("publisher", ""),
"date": datetime.fromtimestamp(item.get("providerPublishTime", 0)).strftime("%Y-%m-%d"),
"url": item.get("link", ""),
"summary": item.get("summary", "")
})
_cache[cache_key] = news_items
return news_items
except Exception as e:
return []
def get_insider_trades_yahoo(ticker: str, limit: int = 10) -> list:
"""
Fetch insider trading data (simplified version)
Returns:
[
{
"insider": "Tim Cook",
"position": "CEO",
"transaction_type": "Sell",
"shares": 10000,
"date": "2024-03-01",
"price": 175.50
},
...
]
"""
# Yahoo Finance doesn't directly provide insider trading data
# Returns empty list; actual implementation may need other data sources
return []
def get_all_data(ticker: str, days: int = 60) -> dict:
"""
Fetch all data for a ticker
Returns:
{
"ticker": "AAPL",
"prices": {...},
"financials": {...},
"news": [...],
"insider_trades": [...],
"success": True
}
"""
prices = get_prices_yahoo(ticker, days)
financials = get_financials_yahoo(ticker)
news = get_news_yahoo(ticker)
insider_trades = get_insider_trades_yahoo(ticker)
success = prices.get("success", False) and financials.get("success", False)
return {
"ticker": ticker,
"prices": prices,
"financials": financials,
"news": news,
"insider_trades": insider_trades,
"success": success
}
if __name__ == "__main__":
# Test
print("Testing data fetcher...")
# Test price data
prices = get_prices_yahoo("AAPL", 60)
print(f"Prices for AAPL: {len(prices.get('dates', []))} days")
# Test financial data
financials = get_financials_yahoo("AAPL")
print(f"Financials for AAPL: P/E = {financials.get('pe_ratio', 'N/A')}")
# Test news
news = get_news_yahoo("AAPL", 3)
print(f"News for AAPL: {len(news)} articles")
for n in news:
print(f" - {n['title']}")
"""
AI Hedge Fund - Investor Agent Prompts
Claude-powered investor persona prompts
"""
# ============ Warren Buffett Agent ============
WARREN_BUFFETT_SYSTEM = """You are Warren Buffett, CEO of Berkshire Hathaway and the world's most famous value investor.
Your Investment Philosophy:
1. Circle of Competence - Only invest in businesses you fully understand
2. Economic Moat - Seek companies with durable competitive advantages
3. Margin of Safety - Buy at a significant discount to intrinsic value
4. Quality Management - Look for honest, competent, shareholder-oriented leaders
5. Long-term Holding - "Our favorite holding period is forever"
Your Analysis Framework:
- Is the business simple and understandable?
- Does it have a wide and durable moat (brand, cost advantage, network effects)?
- Is ROE consistently above 15%?
- Is debt reasonable (Debt/Equity < 0.5)?
- Is management honest and capable?
- Is there sufficient margin of safety vs intrinsic value?
Decision Rules:
- Bullish: Excellent business + ROE > 15% + margin of safety > 0
- Bearish: Poor business quality OR clearly overvalued
- Neutral: Good business but no margin of safety
Base your decision ONLY on provided data. Do not fabricate information."""
WARREN_BUFFETT_PROMPT = """Ticker: {ticker}
## Financial Data
{financial_data}
## Price Summary
{price_summary}
## Analysis Request
Based on the above data and your investment philosophy, analyze this stock.
Return JSON format (no markdown code blocks):
{{"signal": "bullish" or "bearish" or "neutral", "confidence": 0-100, "reasoning": "Brief reason (max 120 chars)"}}"""
# ============ Cathie Wood Agent ============
CATHIE_WOOD_SYSTEM = """You are Cathie Wood (Cathie D. Wood), founder of ARK Invest and a leading growth investor.
Your Investment Philosophy:
1. Disruptive Innovation - Focus on AI, gene editing, blockchain, robotics
2. Long-term Growth - Seek companies with 5-10x potential over 5 years
3. Technology Convergence - Look for multi-sector innovation opportunities
4. Valuation Flexibility - Willing to pay premium for high growth
5. Thematic Investing - Start from technology trends, then find winners
Your Analysis Framework:
- Is it in disruptive technology (AI, biotech, fintech, energy storage)?
- Is R&D investment sufficient?
- Is revenue growth accelerating?
- Is the market opportunity massive (large TAM)?
- Is there a first-mover advantage or technology moat?
- Does management have vision and execution capability?
Decision Rules:
- Bullish: Disruptive tech + high growth + large TAM
- Bearish: Legacy technology or limited market
- Neutral: Potential but competitive/execution risk
Base your decision ONLY on provided data. Do not fabricate information."""
CATHIE_WOOD_PROMPT = """Ticker: {ticker}
## Financial Data
{financial_data}
## Price Summary
{price_summary}
## Analysis Request
Based on the above data and your investment philosophy, analyze this stock. Focus on innovation potential and long-term growth.
Return JSON format (no markdown code blocks):
{{"signal": "bullish" or "bearish" or "neutral", "confidence": 0-100, "reasoning": "Brief reason (max 120 chars)"}}"""
# ============ Michael Burry Agent ============
MICHAEL_BURRY_SYSTEM = """You are Michael Burry, the contrarian investor featured in "The Big Short."
Your Investment Philosophy:
1. Deep Value - Seek severely undervalued assets
2. Contrarian Thinking - Willing to bet against consensus
3. Safety Margin - Extremely focused on downside protection
4. Deep Research - Don't rely on surface data, dig deeper
5. Bubble Detection - Skilled at identifying market excesses
Your Analysis Framework:
- Is the asset severely undervalued (intrinsic value gap > 30%)?
- What is the market missing or misunderstanding?
- What is the catalyst to unlock value?
- What is the risk/reward ratio?
- If overvalued, should it be shorted?
Decision Rules:
- Bullish: Severely undervalued + clear catalyst
- Bearish: Overvalued or bubble conditions
- Neutral: Fair value, no clear opportunity
Base your decision ONLY on provided data. Do not fabricate information."""
MICHAEL_BURRY_PROMPT = """Ticker: {ticker}
## Financial Data
{financial_data}
## Price Summary
{price_summary}
## Analysis Request
Based on the above data and your investment philosophy, analyze this stock. Focus on valuation gap vs intrinsic value.
Return JSON format (no markdown code blocks):
{{"signal": "bullish" or "bearish" or "neutral", "confidence": 0-100, "reasoning": "Brief reason (max 120 chars)"}}"""
# ============ Peter Lynch Agent ============
PETER_LYNCH_SYSTEM = """You are Peter Lynch, former manager of Fidelity Magellan Fund and pioneer of GARP (Growth at Reasonable Price) investing.
Your Investment Philosophy:
1. Invest in What You Know - Discover opportunities in daily life
2. GARP Strategy - Buy growth at reasonable price (PEG < 1)
3. Small-cap Focus - "Tenbaggers" often come from smaller companies
4. Simple & Understandable - Can explain the business in one sentence
5. Hold Winners - Let winners run, sell losers
Your Analysis Framework:
- Is the business simple and understandable?
- Is PEG ratio reasonable (PE / Growth rate < 1)?
- Are revenue and earnings consistently growing?
- Is there compounding potential?
- Is there room for more institutional ownership?
- Are insiders buying?
Decision Rules:
- Bullish: PEG < 1 + consistent growth + understandable
- Bearish: PEG > 2 or growth slowing
- Neutral: Fair value, modest growth
Base your decision ONLY on provided data. Do not fabricate information."""
PETER_LYNCH_PROMPT = """Ticker: {ticker}
## Financial Data
{financial_data}
## Price Summary
{price_summary}
## Analysis Request
Based on the above data and your investment philosophy, analyze this stock. Focus on PEG ratio and growth potential.
Return JSON format (no markdown code blocks):
{{"signal": "bullish" or "bearish" or "neutral", "confidence": 0-100, "reasoning": "Brief reason (max 120 chars)"}}"""
# ============ News Sentiment Prompt ============
NEWS_SENTIMENT_SYSTEM = """You are a professional financial news sentiment analyst.
Your Task:
1. Analyze news headlines' sentiment impact on specific stocks
2. Distinguish between company-level impact vs short-term price impact
3. Consider news timeliness and importance
Sentiment Classification:
- positive: Positive impact on stock price
- negative: Negative impact on stock price
- neutral: Minimal or unclear impact
Confidence:
- 0-30: Uncertain, weak impact
- 31-60: Some directional bias
- 61-80: Fairly confident
- 81-100: Very confident"""
NEWS_SENTIMENT_PROMPT = """Ticker: {ticker}
Analyze the sentiment impact of these news headlines on the stock:
{news_headlines}
Return JSON format (no markdown code blocks):
{{
"sentiments": [
{{"headline": "Headline 1", "sentiment": "positive/negative/neutral", "confidence": 0-100}},
...
],
"overall_sentiment": "bullish/bearish/neutral",
"overall_confidence": 0-100,
"reasoning": "Combined reasoning"
}}"""
# ============ Portfolio Manager Prompt ============
PORTFOLIO_MANAGER_SYSTEM = """You are a professional portfolio manager.
Your Responsibilities:
1. Synthesize multiple analyst signals into final trading decisions
2. Strictly follow risk management constraints
3. Consider portfolio diversification and correlation
4. Be conservative when uncertain
Decision Principles:
- Consider all analyst signals, but weight by quality
- Strictly adhere to position limits
- Higher confidence signals get priority
- Consider overall portfolio risk
Action Types:
- buy: Purchase shares
- sell: Sell existing long position
- short: Short sell
- cover: Cover short position
- hold: No action"""
PORTFOLIO_MANAGER_PROMPT = """## Analyst Signals Summary
{analyst_signals}
## Risk Limits
{risk_limits}
## Current Portfolio
{current_portfolio}
## Allowed Actions
{allowed_actions}
## Decision Request
Based on the above information, make trading decisions for each stock.
Return JSON format (no markdown code blocks):
{{
"decisions": {{
"TICKER": {{
"action": "buy|sell|short|cover|hold",
"quantity": 100,
"confidence": 0-100,
"reasoning": "Brief reason (max 100 chars)"
}}
}},
"portfolio_summary": {{
"bullish_count": 2,
"bearish_count": 1,
"neutral_count": 1,
"strategy_notes": "Portfolio strategy notes"
}}
}}"""
# ============ Helper Functions ============
def format_financial_data_for_prompt(financials: dict) -> str:
"""Format financial data for prompt"""
lines = []
if financials.get("current_price"):
lines.append(f"Current Price: ${financials['current_price']:.2f}")
if financials.get("market_cap"):
lines.append(f"Market Cap: ${financials['market_cap']/1e9:.1f}B")
if financials.get("pe_ratio"):
lines.append(f"P/E: {financials['pe_ratio']:.1f}")
if financials.get("pb_ratio"):
lines.append(f"P/B: {financials['pb_ratio']:.1f}")
if financials.get("roe"):
roe_val = financials['roe'] * 100 if financials['roe'] < 1 else financials['roe']
lines.append(f"ROE: {roe_val:.1f}%")
if financials.get("net_margin"):
margin = financials['net_margin'] * 100 if financials['net_margin'] < 1 else financials['net_margin']
lines.append(f"Net Margin: {margin:.1f}%")
if financials.get("debt_equity"):
lines.append(f"Debt/Equity: {financials['debt_equity']:.2f}")
if financials.get("revenue_growth"):
growth = financials['revenue_growth'] * 100 if financials['revenue_growth'] < 1 else financials['revenue_growth']
lines.append(f"Revenue Growth: {growth:.1f}%")
if financials.get("earnings_growth"):
eg = financials['earnings_growth'] * 100 if financials['earnings_growth'] < 1 else financials['earnings_growth']
lines.append(f"Earnings Growth: {eg:.1f}%")
if financials.get("free_cashflow"):
lines.append(f"Free Cash Flow: ${financials['free_cashflow']/1e9:.1f}B")
return "\n".join(lines)
def format_price_summary_for_prompt(prices_data: dict) -> str:
"""Format price summary for prompt"""
closes = [c for c in prices_data.get("close", []) if c is not None]
if not closes:
return "Insufficient price data"
current = closes[-1]
high_52w = max(closes)
low_52w = min(closes)
lines = [
f"Current Price: ${current:.2f}",
f"52-Week High: ${high_52w:.2f}",
f"52-Week Low: ${low_52w:.2f}",
f"From High: {(current/high_52w-1)*100:.1f}%",
f"From Low: {(current/low_52w-1)*100:.1f}%"
]
return "\n".join(lines)
def get_investor_prompt(investor_name: str, ticker: str, financials: dict, prices_data: dict) -> Tuple:
"""
Get investor agent prompt
Returns:
(system_prompt, user_prompt)
"""
investor_prompts = {
"warren_buffett": (WARREN_BUFFETT_SYSTEM, WARREN_BUFFETT_PROMPT),
"cathie_wood": (CATHIE_WOOD_SYSTEM, CATHIE_WOOD_PROMPT),
"michael_burry": (MICHAEL_BURRY_SYSTEM, MICHAEL_BURRY_PROMPT),
"peter_lynch": (PETER_LYNCH_SYSTEM, PETER_LYNCH_PROMPT)
}
if investor_name not in investor_prompts:
return None, None
system_prompt, prompt_template = investor_prompts[investor_name]
financial_data = format_financial_data_for_prompt(financials)
price_summary = format_price_summary_for_prompt(prices_data)
user_prompt = prompt_template.format(
ticker=ticker,
financial_data=financial_data,
price_summary=price_summary
)
return system_prompt, user_prompt
# Investor Configuration
INVESTORS = {
"warren_buffett": {
"name": "Warren Buffett",
"style": "Value Investing",
"focus": "Moat, ROE, Intrinsic Value",
"icon": "🧠"
},
"cathie_wood": {
"name": "Cathie Wood",
"style": "Growth Investing",
"focus": "Disruptive Tech, Innovation",
"icon": "🚀"
},
"michael_burry": {
"name": "Michael Burry",
"style": "Contrarian Investing",
"focus": "Deep Value, Short Opportunities",
"icon": "📉"
},
"peter_lynch": {
"name": "Peter Lynch",
"style": "GARP",
"focus": "PEG, Understandable Business",
"icon": "📊"
}
}
"""
AI Hedge Fund - Report Generator Module
Generates Markdown format analysis reports
"""
from datetime import datetime
from typing import Dict, List, Any
# ============ Signal Icon Mappings ============
SIGNAL_ICONS = {
"bullish": "🟢",
"bearish": "🔴",
"neutral": "🟡"
}
SIGNAL_LABELS = {
"bullish": "Bullish",
"bearish": "Bearish",
"neutral": "Neutral"
}
ACTION_ICONS = {
"buy": "🟢",
"sell": "🔴",
"short": "🔻",
"cover": "🔺",
"hold": "🟡"
}
ACTION_LABELS = {
"buy": "Buy",
"sell": "Sell",
"short": "Short",
"cover": "Cover",
"hold": "Hold"
}
RISK_ICONS = {
"Low": "🟢",
"Medium": "🟡",
"High": "🔴",
"Very High": "⚠️"
}
def generate_report(
tickers: List[str],
analysis_results: Dict[str, Dict],
decisions: Dict[str, Dict],
portfolio: Dict,
mode: str = "full"
) -> str:
"""
Generate complete analysis report
Args:
tickers: List of ticker symbols
analysis_results: Analysis results for each ticker
decisions: Trading decisions
portfolio: Portfolio state
mode: "full" or "brief"
Returns:
Markdown format report
"""
now = datetime.now()
report = f"""# 🏦 AI Hedge Fund Analysis Report
**Date**: {now.strftime("%Y-%m-%d %H:%M")}
**Tickers**: {", ".join(tickers)}
**Initial Capital**: ${portfolio.get("initial_capital", 100000):,.0f}
---
"""
# Executive Summary
report += generate_executive_summary(tickers, analysis_results, decisions)
report += "\n---\n\n"
if mode == "full":
# Agent Signals Summary
report += "## 📈 Agent Signals\n\n"
for ticker in tickers:
if ticker in analysis_results:
report += generate_ticker_analysis(ticker, analysis_results[ticker])
report += "\n"
report += "---\n\n"
# Trading Decisions
report += "## 💼 Trading Decisions\n\n"
report += generate_decisions_table(tickers, decisions, analysis_results)
report += "\n\n"
# Risk Assessment
report += "### ⚠️ Risk Assessment\n\n"
report += generate_risk_table(tickers, analysis_results)
report += "\n\n"
# Portfolio Status
report += "---\n\n"
report += "## 📋 Portfolio Status\n\n"
report += generate_portfolio_summary(portfolio)
report += "\n\n"
# Disclaimer
report += """---
## ⚠️ Disclaimer
This report is generated by AI Hedge Fund Skill for **educational and research purposes only**.
It does not constitute investment advice. Investing involves risk. Past performance does not guarantee future results.
"""
return report
def generate_executive_summary(
tickers: List[str],
analysis_results: Dict[str, Dict],
decisions: Dict[str, Dict]
) -> str:
"""Generate executive summary"""
summary = "## 📊 Executive Summary\n\n"
summary += "| Ticker | Action | Confidence | Rationale |\n"
summary += "|--------|--------|------------|----------|\n"
for ticker in tickers:
if ticker in decisions:
decision = decisions[ticker]
action = decision.get("action", "hold")
confidence = decision.get("confidence", 50)
reasoning = decision.get("reasoning", "N/A")
action_icon = ACTION_ICONS.get(action, "🟡")
action_label = ACTION_LABELS.get(action, "Hold")
summary += f"| {ticker} | {action_icon} {action_label} | {confidence}% | {reasoning[:30]}... |\n"
else:
summary += f"| {ticker} | 🟡 Hold | - | No data |\n"
return summary
def generate_ticker_analysis(ticker: str, analysis: Dict) -> str:
"""Generate single ticker analysis details"""
result = f"### {ticker}"
if analysis.get("company_name"):
result += f" - {analysis['company_name']}"
result += "\n\n"
# Agent signals table
result += "| Agent | Signal | Confidence | Reasoning |\n"
result += "|-------|--------|------------|----------|\n"
# Rule-based analysts
analysts = [
("Fundamental", analysis.get("fundamentals")),
("Technical", analysis.get("technical")),
("Valuation", analysis.get("valuation")),
("Sentiment", analysis.get("sentiment")),
]
# Investor personas
for investor_id, investor_info in analysis.get("investors", {}).items():
investor_name = investor_info.get("name", investor_id)
analysts.append((investor_name, investor_info))
bullish_count = 0
bearish_count = 0
neutral_count = 0
for analyst_name, analyst_data in analysts:
if analyst_data is None:
continue
signal = analyst_data.get("signal", "neutral")
confidence = analyst_data.get("confidence", 50)
reasoning = analyst_data.get("reasoning", "-")
if len(str(reasoning)) > 50:
reasoning = str(reasoning)[:50] + "..."
icon = SIGNAL_ICONS.get(signal, "🟡")
result += f"| {analyst_name} | {icon} {SIGNAL_LABELS.get(signal, signal)} | {confidence}% | {reasoning} |\n"
if signal == "bullish":
bullish_count += 1
elif signal == "bearish":
bearish_count += 1
else:
neutral_count += 1
# Overall signal
result += "\n"
overall_signal = "bullish" if bullish_count > bearish_count else "bearish" if bearish_count > bullish_count else "neutral"
overall_icon = SIGNAL_ICONS.get(overall_signal, "🟡")
overall_label = SIGNAL_LABELS.get(overall_signal, "Neutral")
result += f"**Consensus**: {overall_icon} **{overall_label}** "
result += f"(Bullish: {bullish_count} / Bearish: {bearish_count} / Neutral: {neutral_count})\n"
return result
def generate_decisions_table(
tickers: List[str],
decisions: Dict[str, Dict],
analysis_results: Dict[str, Dict]
) -> str:
"""Generate trading decisions table"""
result = "### Recommended Trades\n\n"
result += "| Ticker | Action | Quantity | Est. Value | Confidence | Reason |\n"
result += "|--------|--------|----------|------------|------------|--------|\n"
for ticker in tickers:
if ticker in decisions:
decision = decisions[ticker]
action = decision.get("action", "hold")
quantity = decision.get("quantity", 0)
confidence = decision.get("confidence", 50)
reasoning = decision.get("reasoning", "-")
# Get current price
price = analysis_results.get(ticker, {}).get("financials", {}).get("current_price", 0)
amount = quantity * price if price else 0
action_icon = ACTION_ICONS.get(action, "🟡")
action_label = ACTION_LABELS.get(action, "Hold")
result += f"| {ticker} | {action_icon} {action_label} | {quantity} shares | ${amount:,.0f} | {confidence}% | {reasoning[:20]}... |\n"
else:
result += f"| {ticker} | 🟡 Hold | 0 shares | - | - | No data |\n"
return result
def generate_risk_table(tickers: List[str], analysis_results: Dict[str, Dict]) -> str:
"""Generate risk assessment table"""
result = "| Ticker | Annual Volatility | Risk Level | Position Limit | Suggested |\n"
result += "|--------|-------------------|------------|-----------------|----------|\n"
for ticker in tickers:
risk_data = analysis_results.get(ticker, {}).get("risk", {})
volatility = risk_data.get("volatility_pct", "N/A")
risk_level = risk_data.get("risk_level", "Medium")
max_position = risk_data.get("max_position_pct", 20)
risk_icon = RISK_ICONS.get(risk_level, "🟡")
result += f"| {ticker} | {volatility} | {risk_icon} {risk_level} | {max_position:.0f}% | {max_position * 0.8:.0f}% |\n"
return result
def generate_portfolio_summary(portfolio: Dict) -> str:
"""Generate portfolio summary"""
cash = portfolio.get("cash", 0)
position_value = portfolio.get("position_value", 0)
total_value = portfolio.get("total_value", cash + position_value)
position_count = portfolio.get("position_count", 0)
result = "| Item | Value |\n"
result += "|------|-------|\n"
result += f"| 💵 Cash | ${cash:,.0f} |\n"
result += f"| 📈 Position Value | ${position_value:,.0f} |\n"
result += f"| 💰 Total Assets | ${total_value:,.0f} |\n"
result += f"| 📊 Positions | {position_count} |\n"
return result
def generate_signal_summary(
ticker: str,
fundamentals: Dict,
technical: Dict,
valuation: Dict,
sentiment: Dict,
investors: List[Dict]
) -> Dict:
"""
Generate signal summary
Returns:
{
"bullish_count": 3,
"bearish_count": 1,
"neutral_count": 2,
"weighted_score": 0.35,
"dominant_signal": "bullish"
}
"""
signals = []
# Add analyst signals
for analysis in [fundamentals, technical, valuation, sentiment]:
if analysis and "signal" in analysis:
signals.append(analysis)
for investor in investors:
if investor and "signal" in investor:
signals.append(investor)
if not signals:
return {
"bullish_count": 0,
"bearish_count": 0,
"neutral_count": 0,
"weighted_score": 0,
"dominant_signal": "neutral"
}
bullish_count = sum(1 for s in signals if s.get("signal") == "bullish")
bearish_count = sum(1 for s in signals if s.get("signal") == "bearish")
neutral_count = sum(1 for s in signals if s.get("signal") == "neutral")
# Weighted score
score = 0
for s in signals:
confidence = s.get("confidence", 50) / 100
if s.get("signal") == "bullish":
score += confidence
elif s.get("signal") == "bearish":
score -= confidence
weighted_score = score / len(signals) if signals else 0
# Dominant signal
if weighted_score > 0.1:
dominant_signal = "bullish"
elif weighted_score < -0.1:
dominant_signal = "bearish"
else:
dominant_signal = "neutral"
return {
"bullish_count": bullish_count,
"bearish_count": bearish_count,
"neutral_count": neutral_count,
"weighted_score": weighted_score,
"dominant_signal": dominant_signal
}