import numpy as np import pandas as pd def add_technical_indicators(df: pd.DataFrame) -> pd.DataFrame: df = df.copy() # RSI delta = df["Close"].diff() gain = delta.where(delta > 0, 0).rolling(window=14).mean() loss = -delta.where(delta < 0, 0).rolling(window=14).mean() rs = gain / loss df["RSI"] = 100 - (100 / (1 + rs)) # MACD exp1 = df["Close"].ewm(span=12, adjust=False).mean() exp2 = df["Close"].ewm(span=26, adjust=False).mean() df["MACD"] = exp1 - exp2 # Simple 50-day MA df["MA50"] = df["Close"].rolling(window=50).mean() # Log Volume df["Log_Volume"] = np.log(df["Volume"] + 1) df = df.dropna() return df def classify_signal(predicted_change: float, asset_type: str = "stock") -> str: """ predicted_change: percentage change predicted by model asset_type: 'stock' or 'crypto' """ # Crypto → larger natural volatility if asset_type == "crypto": if predicted_change > 3.0: return "STRONG BUY" if predicted_change > 0.8: return "BUY" if predicted_change < -3.0: return "STRONG SELL" if predicted_change < -0.8: return "SELL" return "HOLD" # Stock → tighter thresholds if predicted_change > 1.5: return "STRONG BUY" if predicted_change > 0.3: return "BUY" if predicted_change < -1.5: return "STRONG SELL" if predicted_change < -0.3: return "SELL" return "HOLD" def classify_volatility(df: pd.DataFrame, asset_type: str = "stock") -> str: returns = df["Close"].pct_change().dropna() vol = returns.std() # Crypto volatility bands if asset_type == "crypto": if vol < 0.02: return "Low" if vol < 0.05: return "Medium" return "High" # Stock volatility bands if vol < 0.008: return "Low" if vol < 0.02: return "Medium" return "High"