Files
shawnkim1997andClaude Opus 4.6 ec2c5b37a2 feat: add 4-tier auto-valuation system for negative FCF companies + platform-wide improvements
Report page now auto-detects valuation tier based on company financials:
- Tier 1 (FCF > 0): Traditional DCF analysis
- Tier 2 (EBITDA > 0): EV/EBITDA relative valuation with Bear/Base/Bull scenarios
- Tier 3 (Rev Growth > 10%): P/S revenue-based valuation
- Tier 4 (all weak): P/B / NAV approach

Includes RelativeValuationSection, PathToProfitability components, margin trajectory
chart, and cash runway analysis. Also includes fixes across earnings, macro, screener,
technical, filings pages and backend routers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 22:22:03 +01:00

121 lines
4.3 KiB
Python

"""
ATLAS Terminal — FastAPI Backend
Unified entry point with PostgreSQL + SQLite support.
"""
import json
import math
import os
import logging
from contextlib import asynccontextmanager
from typing import Any
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
class _NanSafeEncoder(json.JSONEncoder):
"""Replace NaN/Inf with None so JSON serialization never crashes."""
def default(self, o: Any) -> Any:
return super().default(o)
def encode(self, o: Any) -> str:
return super().encode(_sanitize(o))
def _sanitize(obj: Any) -> Any:
if isinstance(obj, float):
if math.isnan(obj) or math.isinf(obj):
return None
return obj
if isinstance(obj, dict):
return {k: _sanitize(v) for k, v in obj.items()}
if isinstance(obj, (list, tuple)):
return [_sanitize(v) for v in obj]
return obj
class NanSafeJSONResponse(JSONResponse):
def render(self, content: Any) -> bytes:
return json.dumps(
_sanitize(content),
ensure_ascii=False,
separators=(",", ":"),
).encode("utf-8")
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Initialize database on startup, close on shutdown."""
from server.db.unified_repo import repo
await repo.init_db()
logger.info("ATLAS Terminal backend started.")
yield
await repo.close_db()
logger.info("ATLAS Terminal backend stopped.")
app = FastAPI(
title="ATLAS Terminal API",
description="Personal Bloomberg Terminal — Hybrid AI + Quantitative Analysis",
version="2.0.0",
lifespan=lifespan,
default_response_class=NanSafeJSONResponse,
)
# CORS — allow local frontend
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://localhost:3000",
"http://localhost:3001",
"http://127.0.0.1:3000",
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# --- Mount routers ---
from server.routers import edgar, analysis, valuation, market_data, news, crypto, fx, portfolio, technical, financials, estimates, earnings, insider, screener, markets, fmp, macro, dart, edinet, research, chat # noqa: E402
app.include_router(edgar.router, prefix="/api/edgar", tags=["SEC EDGAR"])
app.include_router(analysis.router, prefix="/api/analysis", tags=["AI Analysis"])
app.include_router(valuation.router, prefix="/api/valuation", tags=["Valuation"])
app.include_router(market_data.router, prefix="/api/market", tags=["Market Data"])
app.include_router(financials.router, prefix="/api/financials", tags=["Financials"])
app.include_router(estimates.router, prefix="/api/estimates", tags=["Estimates"])
app.include_router(news.router, prefix="/api/news", tags=["News"])
app.include_router(crypto.router, prefix="/api/crypto", tags=["Crypto"])
app.include_router(fx.router, prefix="/api/fx", tags=["FX"])
app.include_router(markets.router, prefix="/api/markets", tags=["Markets"])
app.include_router(portfolio.router, prefix="/api/portfolio", tags=["Portfolio"])
app.include_router(technical.router, prefix="/api/technical", tags=["Technical"])
app.include_router(earnings.router, prefix="/api/earnings", tags=["Earnings"])
app.include_router(insider.router, prefix="/api/insider", tags=["Insider Trading"])
app.include_router(screener.router, prefix="/api/screener", tags=["Screener"])
app.include_router(fmp.router, prefix="/api/fmp", tags=["FMP"])
app.include_router(macro.router, prefix="/api/macro", tags=["Macro"])
app.include_router(dart.router, prefix="/api/dart", tags=["DART"])
app.include_router(edinet.router, prefix="/api/edinet", tags=["EDINET"])
app.include_router(research.router, prefix="/api/research", tags=["Research"])
app.include_router(chat.router, prefix="/api/chat", tags=["Chat"])
@app.get("/health")
async def health_check():
"""Health check endpoint."""
db_type = "postgresql" if os.getenv("DATABASE_URL") else "sqlite"
return {"status": "ok", "db": db_type, "version": "2.0.0"}
@app.get("/api/health")
async def api_health_check():
"""Health check endpoint (via /api prefix for Next.js proxy)."""
db_type = "postgresql" if os.getenv("DATABASE_URL") else "sqlite"
return {"status": "ok", "db": db_type, "version": "2.0.0"}