| """Data fetching and processing utilities for the financial dashboard.""" |
|
|
| import pandas as pd |
| from openbb import sdk |
|
|
|
|
| def load_stock_data(symbol: str) -> pd.DataFrame: |
| """Load historical stock price data.""" |
| df = sdk.equity.price.historical(symbol=symbol).to_dataframe() |
| return df |
|
|
|
|
| def load_company_profile(symbol: str): |
| """Load company profile information.""" |
| profile_response = sdk.equity.profile(symbol=symbol) |
| profile_info = profile_response.results[0] if hasattr(profile_response, 'results') and profile_response.results else None |
| return profile_info |
|
|
|
|
| def load_income_statement(symbol: str) -> pd.DataFrame: |
| """Load company income statement data.""" |
| income_stmt = sdk.equity.fundamental.income(symbol=symbol).to_dataframe() |
| return income_stmt |
|
|
|
|
| def calculate_technical_indicators(df: pd.DataFrame, period: int) -> pd.DataFrame: |
| """Calculate SMA, EMA, and RSI indicators.""" |
| df["SMA"] = df["close"].rolling(period).mean() |
| df["EMA"] = df["close"].ewm(span=period, adjust=False).mean() |
|
|
| |
| delta = df["close"].diff() |
| gain = delta.clip(lower=0) |
| loss = -1 * delta.clip(upper=0) |
| avg_gain = gain.rolling(period).mean() |
| avg_loss = loss.rolling(period).mean() |
| rs = avg_gain / avg_loss |
| df["RSI"] = 100 - (100 / (1 + rs)) |
|
|
| return df |
|
|
|
|
| def format_financial_value(value) -> str: |
| """Format financial values with appropriate units.""" |
| if pd.isna(value): |
| return "N/A" |
| if abs(value) >= 1e9: |
| return f"${value/1e9:.2f}B" |
| elif abs(value) >= 1e6: |
| return f"${value/1e6:.2f}M" |
| else: |
| return f"${value:.2f}" |
|
|
|
|
| def get_price_metrics(df: pd.DataFrame) -> dict: |
| """Calculate key price metrics.""" |
| current_price = df["close"].iloc[-1] |
| prev_close = df["close"].iloc[-2] if len(df) > 1 else df["close"].iloc[0] |
| price_change = current_price - prev_close |
| price_change_pct = (price_change / prev_close) * 100 if prev_close != 0 else 0 |
|
|
| return { |
| "current_price": current_price, |
| "price_change": price_change, |
| "price_change_pct": price_change_pct, |
| "high_52w": df['high'].max(), |
| "low_52w": df['low'].min(), |
| } |
|
|
|
|
| def get_profitability_metrics(income_data: pd.Series) -> dict: |
| """Calculate profitability metrics from income statement.""" |
| total_rev = income_data.get('total_revenue', 0) |
| gross_prof = income_data.get('gross_profit', 0) |
| net_inc = income_data.get('net_income', 0) |
| operating_inc = income_data.get('operating_income', 0) |
|
|
| metrics = {} |
|
|
| if total_rev and total_rev > 0: |
| metrics["gross_margin"] = (gross_prof / total_rev) * 100 if pd.notna(gross_prof) else 0 |
| metrics["net_margin"] = (net_inc / total_rev) * 100 if pd.notna(net_inc) else 0 |
| if operating_inc: |
| metrics["operating_margin"] = (operating_inc / total_rev) * 100 |
| else: |
| metrics = {"gross_margin": 0, "net_margin": 0} |
|
|
| return metrics |
|
|