mirror of
https://github.com/shawnkim1997/All-in-one-Financial-Analysis.git
synced 2026-08-15 11:28:08 +00:00
Complete migration from Streamlit to Next.js 14 App Router + FastAPI backend. Frontend (Next.js 14): - 10 pages: Overview, Research, Valuation, Technical, Markets, Earnings, News, Portfolio, Filings, Settings - Terminal Noir dark theme with custom Tailwind config - TradingView Lightweight Charts for candlestick/volume - Valuation: DCF, Sensitivity Matrix, Monte Carlo, Tornado, Reverse DCF - Financial Statements table with YoY growth badges and margin rows - SEC EDGAR inline filing viewer with section tabs - News split-view with iframe article embedding - Technical Analysis with RSI, MACD, Bollinger, Fibonacci, Moving Averages - Earnings beat/miss visualization - AI Copilot chat panel with Gemini integration Backend (FastAPI): - 13 routers: market_data, financials, valuation, technical, earnings, insider, edgar, news, portfolio, analysis, chat, estimates, fx - Services: DCF engine, Monte Carlo simulation, sensitivity analysis, risk metrics, SEC parser, technical indicators - yfinance + yahooquery data sources with fallback pattern - SQLite caching layer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
89 lines
2.2 KiB
Python
89 lines
2.2 KiB
Python
"""Numeric safety utilities for the ATLAS Terminal backend.
|
|
|
|
Provides safe type-coercion helpers used across all services to handle
|
|
None, NaN, and non-numeric values gracefully without raising exceptions.
|
|
"""
|
|
|
|
from typing import Optional
|
|
|
|
import pandas as pd
|
|
|
|
|
|
def _safe_float(x: object) -> Optional[float]:
|
|
"""Convert *x* to ``float``, returning ``None`` for unconvertible values.
|
|
|
|
Handles ``None``, ``NaN`` (both Python ``float('nan')`` and pandas
|
|
``pd.NA``), and arbitrary objects whose ``float()`` conversion fails.
|
|
|
|
Parameters
|
|
----------
|
|
x:
|
|
Any value that might be numeric.
|
|
|
|
Returns
|
|
-------
|
|
Optional[float]
|
|
The float representation, or ``None`` if conversion is impossible.
|
|
"""
|
|
if x is None or (isinstance(x, float) and (x != x or pd.isna(x))):
|
|
return None
|
|
try:
|
|
return float(x)
|
|
except (TypeError, ValueError):
|
|
return None
|
|
|
|
|
|
def _na(x: object) -> object:
|
|
"""Return the string ``'N/A'`` for ``None``/``NaN``, otherwise *x* unchanged.
|
|
|
|
Useful when building display-ready dictionaries or DataFrames where
|
|
missing numeric values should appear as a human-readable sentinel.
|
|
|
|
Parameters
|
|
----------
|
|
x:
|
|
Any value.
|
|
|
|
Returns
|
|
-------
|
|
object
|
|
``'N/A'`` when *x* is ``None`` or ``NaN``; *x* otherwise.
|
|
"""
|
|
if x is None or (isinstance(x, float) and (pd.isna(x) or x != x)):
|
|
return "N/A"
|
|
return x
|
|
|
|
|
|
def _format_shares_display(shares: Optional[float]) -> str:
|
|
"""Format a share count for human-friendly display.
|
|
|
|
Examples
|
|
--------
|
|
>>> _format_shares_display(15_420_000_000)
|
|
'15.42B Shares'
|
|
>>> _format_shares_display(1_200_000)
|
|
'1.20M Shares'
|
|
>>> _format_shares_display(None)
|
|
'N/A'
|
|
|
|
Parameters
|
|
----------
|
|
shares:
|
|
Raw share count (absolute number, not in millions/billions).
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
A concise string such as ``'15.42B Shares'`` or ``'N/A'``.
|
|
"""
|
|
if shares is None or shares <= 0:
|
|
return "N/A"
|
|
s = float(shares)
|
|
if s >= 1e9:
|
|
return f"{s / 1e9:.2f}B Shares"
|
|
if s >= 1e6:
|
|
return f"{s / 1e6:.2f}M Shares"
|
|
if s >= 1e3:
|
|
return f"{s / 1e3:.2f}K Shares"
|
|
return f"{s:.0f} Shares"
|