-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
153 lines (130 loc) · 5.09 KB
/
Copy pathmain.py
File metadata and controls
153 lines (130 loc) · 5.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""Capital trading engine — FastAPI application entry point.
Mounts the API routers and, on startup, seeds the admin operator, starts the
live market-data streams and the paper-trading engine.
"""
import logging
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from fastapi import FastAPI
from sqlmodel import Session
from api.ai import router as ai_router
from api.backtest import router as backtest_router
from api.connections import router as connections_router
from api.costs import router as costs_router
from api.history import router as history_router
from api.lab import router as lab_router
from api.market import router as market_router
from api.market import ws_router as market_ws_router
from api.news import router as news_router
from api.orders import router as orders_router
from api.polymarket import router as polymarket_router
from api.portfolio import router as portfolio_router
from api.research import router as research_router
from api.settings import router as settings_router
from api.strategies import router as strategies_router
from api.system import router as system_router
from api.tokens import router as tokens_router
from api.users import router as users_router
from api.venues import router as venues_router
from auth.routes import router as auth_router
from auth.seed import seed_admin
from config import settings
from connections.seed import ensure_seed
from db import engine as db_engine
from logging_config import setup_logging
from marketdata.stream import StreamManager
from notify.telegram import TelegramNotifier
from ops.recovery import recover_on_boot
from strategies.builtin import all_strategies_with_instances, seed_allocations
from trading.engine import TradingEngine
from trading.executor_router import ExecutorRouter
setup_logging(settings.log_level)
log = logging.getLogger("capital")
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
"""Startup/shutdown hooks."""
try:
seed_admin()
except Exception: # noqa: BLE001 — never let seeding crash startup
log.exception("Admin seeding skipped (run `alembic upgrade head` first?)")
# Seed the connections graph with the bundled curated nodes/edges.
try:
with Session(db_engine) as session:
ensure_seed(session)
except Exception: # noqa: BLE001 — never let seeding crash startup
log.exception("Connections seeding skipped")
# Live market-data streams — self-healing Binance WebSocket consumers.
streams = StreamManager()
app.state.streams = streams
streams.start()
# Paper-trading engine — ticks the built-in strategies on a schedule.
def session_factory() -> Session:
return Session(db_engine)
# Boot recovery — reconcile open positions with Binance before trading.
try:
with session_factory() as session:
recover_on_boot(session)
except Exception: # noqa: BLE001 — recovery must not block startup
log.exception("Boot recovery skipped")
with session_factory() as session:
strategies = all_strategies_with_instances(session)
try:
seed_allocations(session_factory, strategies)
except Exception: # noqa: BLE001 — never let seeding crash startup
log.exception("Strategy allocation seeding skipped")
trading = TradingEngine(
session_factory=session_factory,
router=ExecutorRouter(),
strategies=strategies,
notifier=TelegramNotifier.from_settings(settings),
retention_candle_days=settings.retention_candle_days,
retention_equity_days=settings.retention_equity_days,
)
app.state.trading = trading
trading.start()
try:
yield
finally:
trading.stop()
await streams.stop()
app = FastAPI(
title=settings.app_name,
version=settings.version,
summary="Self-hosted automated Binance trading engine.",
lifespan=lifespan,
)
app.include_router(auth_router)
app.include_router(users_router)
app.include_router(market_router)
app.include_router(market_ws_router)
app.include_router(orders_router)
app.include_router(portfolio_router)
app.include_router(strategies_router)
app.include_router(backtest_router)
app.include_router(settings_router)
app.include_router(system_router)
app.include_router(history_router)
app.include_router(ai_router)
app.include_router(tokens_router)
app.include_router(venues_router)
app.include_router(news_router)
app.include_router(polymarket_router)
app.include_router(connections_router)
app.include_router(research_router)
app.include_router(lab_router)
app.include_router(costs_router)
@app.get("/health", tags=["system"])
def health() -> dict[str, str]:
"""Liveness probe — used by Docker, CI and the deploy script."""
return {
"status": "ok",
"service": "capital-engine",
"version": settings.version,
"environment": settings.environment,
}
def main() -> None:
"""Run the engine with uvicorn (``python main.py`` / container CMD)."""
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=False)
if __name__ == "__main__":
main()