File size: 5,174 Bytes
c90e00d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
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."""
# Calculate price changes
delta = prices.diff()
# Separate gains and losses
gain = delta.clip(lower=0)
loss = -delta.clip(upper=0)
# Calculate average gain and loss
avg_gain = gain.rolling(window=period).mean()
avg_loss = loss.rolling(window=period).mean()
# Calculate relative strength (RS)
rs = avg_gain / avg_loss
# Calculate RSI
rsi = 100 - (100 / (1 + rs))
return rsi
def calculate_macd(prices, fast=12, slow=26, signal=9):
"""Calculate Moving Average Convergence Divergence."""
# Calculate EMAs
ema_fast = prices.ewm(span=fast, adjust=False).mean()
ema_slow = prices.ewm(span=slow, adjust=False).mean()
# Calculate MACD line
macd_line = ema_fast - ema_slow
# Calculate signal line
signal_line = macd_line.ewm(span=signal, adjust=False).mean()
# Calculate histogram
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
# Calculate basic technical indicators
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'])
# Calculate MACD
macd = calculate_macd(hist['Close'])
hist['MACD_Line'] = macd['macd_line']
hist['MACD_Signal'] = macd['signal_line']
hist['MACD_Histogram'] = macd['histogram']
# Calculate Bollinger Bands
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)
# Get latest values
latest = hist.iloc[-1]
# Get fundamental data
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 = {}
# Collect technical data for all stocks
for ticker in tickers:
try:
# Get stock data
stock = yf.Ticker(ticker)
hist = stock.history(period="6mo")
if not hist.empty:
# Get comprehensive technical indicators without judgments
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)}
# Update state with technical analysis
state["technical_analysis"] = analysis_results
# Add message to communication
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
|