refactor: 消费者切 SQLite 优先读取
切换策略: SQLite 优先 → 失败回退 JSON price_events (100%覆盖): - strategy_feedback.py: run() 优先 query_price_events() - system_health_check.py: 优先 query_price_events() + query_price_events_by_date() stock_sector_map (100%覆盖): - strategy_lifecycle.py: load_stock_sector_map() 优先 stock_sectors 表 market.json (85%覆盖): - strategy_lifecycle.py: load_market_context() 优先 query_latest_market() - market_insight.py: generate() 优先 query_latest_market() portfolio.json + watchlist.json (70%覆盖): - strategy_lifecycle.py: regenerate_all() 优先 query_holdings() + query_watchlist() - server.py: /api/portfolio, /api/watchlist, /api/overview, /api/market 优先 SQLite 所有改动保留 JSON 回退路径,SQLite 不可用时自动降级
This commit is contained in:
@@ -33,6 +33,20 @@ def _load_json(path, default=None):
|
||||
return {} if default is None else default
|
||||
|
||||
|
||||
def _load_from_db(query_func, json_path, default=None):
|
||||
"""优先从 SQLite 读取,失败回退 JSON"""
|
||||
try:
|
||||
from mofin_db import get_conn
|
||||
conn = get_conn()
|
||||
result = query_func(conn)
|
||||
conn.close()
|
||||
if result:
|
||||
return result
|
||||
except Exception:
|
||||
pass
|
||||
return _load_json(json_path, default)
|
||||
|
||||
|
||||
def _save_json(path, data):
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
@@ -49,46 +63,80 @@ def index():
|
||||
@app.route("/api/portfolio")
|
||||
def api_portfolio():
|
||||
"""持仓列表"""
|
||||
data = _load_json(DATA_DIR / "portfolio.json")
|
||||
return jsonify(data)
|
||||
try:
|
||||
from mofin_db import get_conn, query_holdings, query_portfolio_summary
|
||||
conn = get_conn()
|
||||
holdings = query_holdings(conn)
|
||||
summary = query_portfolio_summary(conn)
|
||||
conn.close()
|
||||
if holdings:
|
||||
data = dict(summary)
|
||||
data["holdings"] = holdings
|
||||
return jsonify(data)
|
||||
except Exception:
|
||||
pass
|
||||
return jsonify(_load_json(DATA_DIR / "portfolio.json"))
|
||||
|
||||
|
||||
@app.route("/api/watchlist")
|
||||
def api_watchlist():
|
||||
"""自选列表"""
|
||||
data = _load_json(DATA_DIR / "watchlist.json")
|
||||
return jsonify(data)
|
||||
try:
|
||||
from mofin_db import get_conn, query_watchlist
|
||||
conn = get_conn()
|
||||
stocks = query_watchlist(conn)
|
||||
conn.close()
|
||||
if stocks:
|
||||
return jsonify({"stocks": stocks})
|
||||
except Exception:
|
||||
pass
|
||||
return jsonify(_load_json(DATA_DIR / "watchlist.json"))
|
||||
|
||||
|
||||
@app.route("/api/overview")
|
||||
def api_overview():
|
||||
"""概览数据"""
|
||||
try:
|
||||
from mofin_db import get_conn, query_holdings, query_portfolio_summary, query_latest_market
|
||||
conn = get_conn()
|
||||
holdings = query_holdings(conn)
|
||||
summary = query_portfolio_summary(conn)
|
||||
market = query_latest_market(conn)
|
||||
conn.close()
|
||||
if holdings:
|
||||
total_assets = summary.get("total_assets", 0) or 0
|
||||
stock_value = summary.get("stock_value", 0) or 0
|
||||
cash = summary.get("cash", 0) or 0
|
||||
position_pct = summary.get("position_pct", 0) or 0
|
||||
total_pnl = summary.get("total_pnl", 0) or 0
|
||||
top_movers = sorted(
|
||||
[h for h in holdings if abs(h.get("change_pct", 0) or 0) >= 3],
|
||||
key=lambda x: abs(x.get("change_pct", 0) or 0), reverse=True)[:5]
|
||||
return jsonify({
|
||||
"total_assets": total_assets, "stock_value": stock_value,
|
||||
"cash": cash, "position_pct": position_pct, "total_pnl": total_pnl,
|
||||
"top_movers": top_movers, "market": market,
|
||||
"alerts": _load_json(DATA_DIR / "alerts.json", [])[:10],
|
||||
"updated_at": summary.get("updated_at", ""),
|
||||
})
|
||||
except Exception:
|
||||
pass
|
||||
portfolio = _load_json(DATA_DIR / "portfolio.json", [])
|
||||
market = _load_json(DATA_DIR / "market.json", {})
|
||||
alerts = _load_json(DATA_DIR / "alerts.json", [])
|
||||
|
||||
total_assets = portfolio.get("total_assets", 0)
|
||||
stock_value = portfolio.get("stock_value", 0)
|
||||
cash = portfolio.get("cash", 0)
|
||||
position_pct = portfolio.get("position_pct", 0)
|
||||
total_pnl = portfolio.get("total_pnl", 0)
|
||||
holdings = portfolio.get("holdings", [])
|
||||
|
||||
top_movers = sorted(
|
||||
[h for h in holdings if abs(h.get("change_pct", 0)) >= 3],
|
||||
key=lambda x: abs(x.get("change_pct", 0)),
|
||||
reverse=True,
|
||||
)[:5]
|
||||
|
||||
key=lambda x: abs(x.get("change_pct", 0)), reverse=True)[:5]
|
||||
return jsonify({
|
||||
"total_assets": total_assets,
|
||||
"stock_value": stock_value,
|
||||
"cash": cash,
|
||||
"position_pct": position_pct,
|
||||
"total_pnl": total_pnl,
|
||||
"top_movers": top_movers,
|
||||
"market": market,
|
||||
"alerts": alerts[:10],
|
||||
"total_assets": total_assets, "stock_value": stock_value,
|
||||
"cash": cash, "position_pct": position_pct, "total_pnl": total_pnl,
|
||||
"top_movers": top_movers, "market": market, "alerts": alerts[:10],
|
||||
"updated_at": portfolio.get("updated_at", ""),
|
||||
})
|
||||
|
||||
@@ -138,8 +186,16 @@ def api_stock(code):
|
||||
@app.route("/api/market")
|
||||
def api_market():
|
||||
"""市场观察"""
|
||||
data = _load_json(DATA_DIR / "market.json", {})
|
||||
return jsonify(data)
|
||||
try:
|
||||
from mofin_db import get_conn, query_latest_market
|
||||
conn = get_conn()
|
||||
data = query_latest_market(conn)
|
||||
conn.close()
|
||||
if data and data.get("sectors"):
|
||||
return jsonify(data)
|
||||
except Exception:
|
||||
pass
|
||||
return jsonify(_load_json(DATA_DIR / "market.json", {}))
|
||||
|
||||
|
||||
# ── 数据写入API(供 cron/update_data.py 调用) ──────────
|
||||
|
||||
Reference in New Issue
Block a user