import logging import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware # Patch curl_cffi to use safari TLS fingerprint instead of chrome. # curl_cffi's chrome impersonation triggers BoringSSL SSL_ERROR_SYSCALL on # some networks; safari works reliably. This must happen before any import # that creates a curl_cffi Session (yfinance, openbb). import curl_cffi.requests as _cffi_requests _orig_session_init = _cffi_requests.Session.__init__ def _patched_session_init(self, *args, **kwargs): if kwargs.get("impersonate") == "chrome": kwargs["impersonate"] = "safari" _orig_session_init(self, *args, **kwargs) _cffi_requests.Session.__init__ = _patched_session_init from openbb import obb from config import settings # Register optional provider credentials with OpenBB if settings.fred_api_key: obb.user.credentials.fred_api_key = settings.fred_api_key from routes import router from routes_sentiment import router as sentiment_router from routes_macro import router as macro_router from routes_technical import router as technical_router from routes_quantitative import router as quantitative_router from routes_calendar import router as calendar_router from routes_market import router as market_router logging.basicConfig( level=settings.log_level.upper(), format="%(asctime)s %(levelname)s %(name)s: %(message)s", ) app = FastAPI( title="OpenBB Investment Analysis API", version="0.1.0", description="REST API for stock data and rule-based investment analysis, powered by OpenBB SDK.", ) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=False, allow_methods=["GET", "POST"], allow_headers=["Content-Type", "Authorization"], ) app.include_router(router) app.include_router(sentiment_router) app.include_router(macro_router) app.include_router(technical_router) app.include_router(quantitative_router) app.include_router(calendar_router) app.include_router(market_router) @app.get("/health", response_model=dict[str, str]) async def health() -> dict[str, str]: return {"status": "ok"} if __name__ == "__main__": uvicorn.run( "main:app", host=settings.host, port=settings.port, reload=settings.debug, )