恢复下单界面并排布局,品种推荐数据库缓存与 SSE 推送。
期货下单与持仓监控左右并排,推荐按资金过滤存库,后台刷新并通过 EventSource 推送。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+73
-5
@@ -5,10 +5,11 @@ import json
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable
|
||||
|
||||
from flask import flash, jsonify, redirect, render_template, request, url_for
|
||||
from flask import flash, jsonify, redirect, render_template, request, url_for, Response, stream_with_context
|
||||
|
||||
from contract_specs import calc_position_metrics, get_contract_spec
|
||||
from fee_specs import calc_fee_breakdown
|
||||
from kline_stream import sse_format
|
||||
from position_sizing import (
|
||||
MODE_FIXED,
|
||||
MODE_RISK,
|
||||
@@ -16,7 +17,8 @@ from position_sizing import (
|
||||
calc_order_tick_metrics,
|
||||
normalize_sizing_mode,
|
||||
)
|
||||
from product_recommend import list_product_recommendations
|
||||
from recommend_store import load_recommend_cache, refresh_recommend_cache
|
||||
from recommend_stream import recommend_hub, start_recommend_worker
|
||||
from risk.account_risk_lib import (
|
||||
assert_can_open,
|
||||
get_risk_status,
|
||||
@@ -300,6 +302,7 @@ def install_trading(app, *, login_required, get_db, get_setting, set_setting, fe
|
||||
).fetchone()["n"]
|
||||
conn.commit()
|
||||
sizing = get_sizing_mode(get_setting)
|
||||
rec_cache = load_recommend_cache(conn)
|
||||
return render_template(
|
||||
"trade.html",
|
||||
trading_mode=mode,
|
||||
@@ -314,6 +317,8 @@ def install_trading(app, *, login_required, get_db, get_setting, set_setting, fe
|
||||
sizing_mode=sizing,
|
||||
sizing_mode_label="以损定仓" if sizing == MODE_RISK else "固定张数",
|
||||
risk_percent=get_risk_percent(get_setting),
|
||||
recommend_rows=rec_cache.get("rows") or [],
|
||||
recommend_updated_at=rec_cache.get("updated_at"),
|
||||
)
|
||||
finally:
|
||||
conn.close()
|
||||
@@ -626,10 +631,61 @@ def install_trading(app, *, login_required, get_db, get_setting, set_setting, fe
|
||||
@app.route("/api/recommend/list")
|
||||
@login_required
|
||||
def api_recommend_list():
|
||||
"""只读数据库缓存,不在请求时拉行情。"""
|
||||
conn = get_db()
|
||||
capital = _capital(conn)
|
||||
conn.close()
|
||||
return jsonify({"ok": True, "capital": capital, "rows": list_product_recommendations(capital, _main_price)})
|
||||
try:
|
||||
payload = load_recommend_cache(conn)
|
||||
return jsonify({"ok": True, **payload})
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
@app.route("/api/recommend/stream")
|
||||
@login_required
|
||||
def api_recommend_stream():
|
||||
from queue import Empty
|
||||
|
||||
def generate():
|
||||
q = recommend_hub.subscribe()
|
||||
try:
|
||||
conn = get_db()
|
||||
try:
|
||||
payload = load_recommend_cache(conn)
|
||||
finally:
|
||||
conn.close()
|
||||
yield sse_format("recommend", {"ok": True, **payload})
|
||||
while True:
|
||||
try:
|
||||
msg = q.get(timeout=25)
|
||||
yield sse_format(msg["event"], msg["data"])
|
||||
except Empty:
|
||||
yield ": heartbeat\n\n"
|
||||
finally:
|
||||
recommend_hub.unsubscribe(q)
|
||||
|
||||
return Response(
|
||||
stream_with_context(generate()),
|
||||
mimetype="text/event-stream",
|
||||
headers={
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive",
|
||||
"X-Accel-Buffering": "no",
|
||||
},
|
||||
)
|
||||
|
||||
@app.route("/api/recommend/refresh", methods=["POST"])
|
||||
@login_required
|
||||
def api_recommend_refresh():
|
||||
"""手动触发一次后台刷新(仍写入数据库)。"""
|
||||
conn = get_db()
|
||||
try:
|
||||
init_strategy_tables(conn)
|
||||
capital = _capital(conn)
|
||||
rows = refresh_recommend_cache(conn, capital, _main_price)
|
||||
payload = load_recommend_cache(conn)
|
||||
recommend_hub.broadcast("recommend", {"ok": True, **payload})
|
||||
return jsonify({"ok": True, "count": len(rows), **payload})
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
@app.route("/api/strategy/trend/preview", methods=["POST"])
|
||||
@login_required
|
||||
@@ -946,3 +1002,15 @@ def install_trading(app, *, login_required, get_db, get_setting, set_setting, fe
|
||||
reduce_cooloff_after_journal(conn, trading_day=trading_day_label())
|
||||
|
||||
app._risk_review_hook = hook_review_mood
|
||||
|
||||
from db_conn import DB_PATH
|
||||
|
||||
def _init_tables(conn):
|
||||
init_strategy_tables(conn)
|
||||
|
||||
start_recommend_worker(
|
||||
db_path=DB_PATH,
|
||||
get_capital_fn=_capital,
|
||||
price_fn=_main_price,
|
||||
init_tables_fn=_init_tables,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user