@@ -11,11 +11,10 @@ from fastapi.responses import FileResponse, JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from app import __version__
|
||||
from app.api import analysis, auth as auth_api, backtest, data, ext_data, financials, indices, intraday, kline, market_recap, monitor_rules, alerts, overview, pipeline, rps, screener, settings as settings_api, signals, stock_analysis, strategy, watchlist
|
||||
from app.api import analysis, auth as auth_api, backtest, data, ext_data, financials, indices, kline, market_recap, alerts, overview, pipeline, rps, screener, settings as settings_api, signals, stock_analysis, strategy, watchlist
|
||||
from app.api.routes import router as core_router
|
||||
from app.config import settings
|
||||
from app.jobs import daily_pipeline
|
||||
from app.services.quote_service import QuoteService
|
||||
from app.tickflow import client as tf_client
|
||||
from app.tickflow.policy import detect_capabilities
|
||||
from app.tickflow.repository import DataStore, KlineRepository
|
||||
@@ -56,42 +55,14 @@ async def lifespan(app: FastAPI):
|
||||
app.state.capabilities = capset
|
||||
logger.info("ready; %d capabilities active", len(capset.all()))
|
||||
|
||||
# 全局行情服务
|
||||
qs = QuoteService()
|
||||
app.state.quote_service = qs
|
||||
qs.set_repo(repo)
|
||||
qs.boot_check()
|
||||
|
||||
# QuoteService 需要访问 strategy_monitor 等单例
|
||||
# 先创建 strategy_monitor,再注入 app.state
|
||||
from app.strategy.monitor import StrategyMonitorService
|
||||
strategy_monitor = StrategyMonitorService()
|
||||
app.state.strategy_monitor = strategy_monitor
|
||||
qs.set_app_state(app.state)
|
||||
|
||||
# 五档盘口 sealed 服务(真假涨停/跌停, 独立旁路线)
|
||||
from app.services.depth_service import DepthService
|
||||
depth_service = DepthService()
|
||||
depth_service.set_repo(repo)
|
||||
depth_service.set_app_state(app.state)
|
||||
app.state.depth_service = depth_service
|
||||
|
||||
# 启动调度器(若 enriched 数据为空,首次启动可手动 POST /api/pipeline/run)
|
||||
try:
|
||||
daily_pipeline.set_app_state(app.state) # 供 depth_finalize job 访问 depth_service
|
||||
scheduler = daily_pipeline.start_scheduler(repo, capset)
|
||||
app.state.scheduler = scheduler
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.warning("scheduler not started: %s", e)
|
||||
app.state.scheduler = None
|
||||
|
||||
# depth sealed: 启动补跑(当天文件不存在) + 盘中轮询(有能力时)
|
||||
try:
|
||||
depth_service.boot_check()
|
||||
depth_service.start_polling()
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.warning("depth_service init failed: %s", e)
|
||||
|
||||
# 扩展数据定时拉取
|
||||
from app.services.ext_pull import pull_scheduler
|
||||
pull_scheduler.start(store.data_dir)
|
||||
@@ -114,7 +85,6 @@ async def lifespan(app: FastAPI):
|
||||
|
||||
# 策略引擎
|
||||
from app.strategy.engine import StrategyEngine
|
||||
from app.strategy.monitor import StrategyMonitorService
|
||||
from app.services.screener import ScreenerService
|
||||
|
||||
_screener_svc = ScreenerService(repo)
|
||||
@@ -131,36 +101,6 @@ async def lifespan(app: FastAPI):
|
||||
app.state.strategy_engine = strategy_engine
|
||||
logger.info("strategy engine loaded: %d strategies", len(strategy_engine.list_strategies()))
|
||||
|
||||
# 通用监控规则引擎: 启动时 reload 规则到内存态 (修复重启后告警失效)
|
||||
from app.strategy.monitor import MonitorRuleEngine
|
||||
from app.strategy import monitor_rules as mr_store
|
||||
from app.services import preferences
|
||||
monitor_engine = MonitorRuleEngine()
|
||||
monitor_engine.set_strategy_engine(strategy_engine)
|
||||
monitor_engine.set_data_dir(store.data_dir)
|
||||
# 复用 ScreenerService 的历史窗口加载器 (三级缓存, 启动预计算命中 ~0ms),
|
||||
# 让声明 filter_history 的策略 (如反包) 也能在实时监控里跑选股 → 盘中触发通知。
|
||||
monitor_engine.set_history_loader(_screener_svc._load_enriched_history)
|
||||
|
||||
# 自动迁移: 把旧 strategy_monitor_ids 同步为 type=strategy 规则 (统一到监控页)
|
||||
try:
|
||||
if preferences.get_strategy_monitor_enabled():
|
||||
ids = preferences.get_strategy_monitor_ids()
|
||||
if ids:
|
||||
names = {s.id: s.name for s in strategy_engine.list_strategies()}
|
||||
mr_store.migrate_strategy_monitors(store.data_dir, ids, names)
|
||||
logger.info("strategy monitor migrated: %d strategies", len(ids))
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.warning("strategy monitor migration failed: %s", e)
|
||||
|
||||
try:
|
||||
rules = mr_store.load_all(store.data_dir)
|
||||
monitor_engine.set_rules(rules)
|
||||
logger.info("monitor engine loaded: %d rules", monitor_engine.rule_count)
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.warning("monitor engine load failed: %s", e)
|
||||
app.state.monitor_engine = monitor_engine
|
||||
|
||||
yield
|
||||
|
||||
if app.state.scheduler:
|
||||
@@ -171,12 +111,6 @@ async def lifespan(app: FastAPI):
|
||||
fsc = getattr(app.state, "financial_scheduler", None)
|
||||
if fsc:
|
||||
fsc.stop()
|
||||
qs = getattr(app.state, "quote_service", None)
|
||||
if qs:
|
||||
qs.stop()
|
||||
dsvc = getattr(app.state, "depth_service", None)
|
||||
if dsvc:
|
||||
dsvc.stop_polling()
|
||||
logger.info("shutdown")
|
||||
|
||||
|
||||
@@ -251,7 +185,6 @@ app.include_router(kline.router)
|
||||
app.include_router(watchlist.router)
|
||||
app.include_router(screener.router)
|
||||
app.include_router(backtest.router)
|
||||
app.include_router(intraday.router)
|
||||
app.include_router(indices.router)
|
||||
app.include_router(overview.router)
|
||||
app.include_router(analysis.router)
|
||||
@@ -264,7 +197,6 @@ app.include_router(market_recap.router)
|
||||
app.include_router(settings_api.router)
|
||||
app.include_router(strategy.router)
|
||||
app.include_router(signals.router)
|
||||
app.include_router(monitor_rules.router)
|
||||
app.include_router(alerts.router)
|
||||
app.include_router(rps.router)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user