|
import yfinance as yf |
|
import numpy as np |
|
import pandas as pd |
|
from typing import Dict, Any, List |
|
from .state import AgentState |
|
|
|
def calculate_rsi(prices, period=14): |
|
"""Calculate Relative Strength Index.""" |
|
|
|
delta = prices.diff() |
|
|
|
|
|
gain = delta.clip(lower=0) |
|
loss = -delta.clip(upper=0) |
|
|
|
|
|
avg_gain = gain.rolling(window=period).mean() |
|
avg_loss = loss.rolling(window=period).mean() |
|
|
|
|
|
rs = avg_gain / avg_loss |
|
|
|
|
|
rsi = 100 - (100 / (1 + rs)) |
|
|
|
return rsi |
|
|
|
def calculate_macd(prices, fast=12, slow=26, signal=9): |
|
"""Calculate Moving Average Convergence Divergence.""" |
|
|
|
ema_fast = prices.ewm(span=fast, adjust=False).mean() |
|
ema_slow = prices.ewm(span=slow, adjust=False).mean() |
|
|
|
|
|
macd_line = ema_fast - ema_slow |
|
|
|
|
|
signal_line = macd_line.ewm(span=signal, adjust=False).mean() |
|
|
|
|
|
histogram = macd_line - signal_line |
|
|
|
return { |
|
'macd_line': macd_line, |
|
'signal_line': signal_line, |
|
'histogram': histogram |
|
} |
|
|
|
def get_technical_indicators(ticker_obj, hist): |
|
"""Calculate technical indicators for a stock without making judgments.""" |
|
if hist.empty: |
|
return None |
|
|
|
|
|
hist['MA20'] = hist['Close'].rolling(window=20).mean() |
|
hist['MA50'] = hist['Close'].rolling(window=50).mean() |
|
hist['MA200'] = hist['Close'].rolling(window=200).mean() |
|
hist['RSI'] = calculate_rsi(hist['Close']) |
|
|
|
|
|
macd = calculate_macd(hist['Close']) |
|
hist['MACD_Line'] = macd['macd_line'] |
|
hist['MACD_Signal'] = macd['signal_line'] |
|
hist['MACD_Histogram'] = macd['histogram'] |
|
|
|
|
|
hist['BB_Middle'] = hist['Close'].rolling(window=20).mean() |
|
std = hist['Close'].rolling(window=20).std() |
|
hist['BB_Upper'] = hist['BB_Middle'] + (std * 2) |
|
hist['BB_Lower'] = hist['BB_Middle'] - (std * 2) |
|
|
|
|
|
latest = hist.iloc[-1] |
|
|
|
|
|
info = ticker_obj.info |
|
|
|
return { |
|
'current_price': latest['Close'], |
|
'technical_indicators': { |
|
'ma20': latest['MA20'], |
|
'ma50': latest['MA50'], |
|
'ma200': latest['MA200'], |
|
'rsi': latest['RSI'], |
|
'macd_line': latest['MACD_Line'], |
|
'macd_signal': latest['MACD_Signal'], |
|
'macd_histogram': latest['MACD_Histogram'], |
|
'bb_upper': latest['BB_Upper'], |
|
'bb_middle': latest['BB_Middle'], |
|
'bb_lower': latest['BB_Lower'], |
|
'volume': latest['Volume'] |
|
}, |
|
'fundamental_data': { |
|
'symbol': ticker_obj.ticker, |
|
'price': info.get('currentPrice'), |
|
'pe_ratio': info.get('trailingPE'), |
|
'peg_ratio': info.get('pegRatio'), |
|
'debt_to_equity': info.get('debtToEquity'), |
|
'forward_pe': info.get('forwardPE'), |
|
'beta': info.get('beta'), |
|
'return_on_equity': info.get('returnOnEquity'), |
|
'free_cash_flow': info.get('freeCashflow'), |
|
'revenue_growth': info.get('revenueGrowth'), |
|
'earnings_growth': info.get('earningsGrowth'), |
|
'dividend_yield': info.get('dividendYield'), |
|
'market_cap': info.get('marketCap'), |
|
'profit_margins': info.get('profitMargins'), |
|
'price_to_book': info.get('priceToBook') |
|
} |
|
} |
|
|
|
def technical_analyzer(state: AgentState) -> AgentState: |
|
"""Performs comprehensive technical analysis on portfolio assets.""" |
|
portfolio = state["portfolio_data"] |
|
|
|
tickers = list(portfolio.keys()) |
|
analysis_results = {} |
|
|
|
|
|
for ticker in tickers: |
|
try: |
|
|
|
stock = yf.Ticker(ticker) |
|
hist = stock.history(period="6mo") |
|
|
|
if not hist.empty: |
|
|
|
indicators = get_technical_indicators(stock, hist) |
|
|
|
if indicators: |
|
analysis_results[ticker] = indicators |
|
else: |
|
analysis_results[ticker] = {"error": "Failed to calculate indicators"} |
|
else: |
|
analysis_results[ticker] = {"error": "No historical data available"} |
|
|
|
except Exception as e: |
|
print(f"Error analyzing {ticker}: {str(e)}") |
|
analysis_results[ticker] = {"error": str(e)} |
|
|
|
|
|
state["technical_analysis"] = analysis_results |
|
|
|
|
|
state["messages"] = state.get("messages", []) + [{ |
|
"role": "ai", |
|
"content": f"[TechnicalAnalyzer] I've calculated technical indicators and gathered fundamental data for your portfolio stocks." |
|
}] |
|
|
|
return state |
|
|