条件单列表改为中控后台并行缓存并以 SSE 推浏览器,下发仍走中控到实例。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -43,13 +43,13 @@ from lib.bridge_client_lib import (
|
||||
fetch_backup_file,
|
||||
fetch_backup_list,
|
||||
fetch_client_version,
|
||||
fetch_cond_orders,
|
||||
post_client_update,
|
||||
post_close_full,
|
||||
post_cond_cancel,
|
||||
post_cond_exit,
|
||||
pull_all_enabled,
|
||||
)
|
||||
from lib.cond_orders_cache_lib import cond_orders_store
|
||||
from lib.cash_sample_lib import record_cash_samples_from_overview
|
||||
from lib.db_lib import db_path as hub_db_path, init_db
|
||||
from lib.env_lib import apply_env_updates, env_get
|
||||
@@ -560,8 +560,13 @@ def start_stats_cache() -> None:
|
||||
stats_store.start()
|
||||
|
||||
|
||||
def start_cond_orders_cache() -> None:
|
||||
cond_orders_store.start()
|
||||
|
||||
|
||||
start_overview_cache()
|
||||
start_stats_cache()
|
||||
start_cond_orders_cache()
|
||||
|
||||
try:
|
||||
start_hub_backup_scheduler(
|
||||
@@ -690,49 +695,66 @@ def cond_orders_page():
|
||||
@app.route("/api/cond_orders/candidates")
|
||||
@login_required
|
||||
def api_cond_order_candidates():
|
||||
"""可选客户端:在线且无持仓、未被条件单锁定."""
|
||||
rows = pull_all_enabled()
|
||||
out = []
|
||||
for row in rows:
|
||||
snap = row.get("snapshot") if isinstance(row.get("snapshot"), dict) else {}
|
||||
brief = snap.get("positions_brief") or snap.get("positions") or []
|
||||
has_pos = isinstance(brief, list) and len(brief) > 0
|
||||
locked = bool(snap.get("cond_order_locked"))
|
||||
selectable = bool(row.get("online")) and not has_pos and not locked
|
||||
inst = snap.get("instance") if isinstance(snap.get("instance"), dict) else {}
|
||||
mode = str(inst.get("mode") or "").strip().lower()
|
||||
if mode not in ("sim", "live"):
|
||||
mode = ""
|
||||
out.append(
|
||||
{
|
||||
"id": row.get("id"),
|
||||
"name": row.get("name"),
|
||||
"online": bool(row.get("online")),
|
||||
"has_position": has_pos,
|
||||
"cond_order_locked": locked,
|
||||
"selectable": selectable,
|
||||
"mode": mode,
|
||||
"error": row.get("error") or "",
|
||||
}
|
||||
)
|
||||
return jsonify({"ok": True, "instances": out})
|
||||
"""可选客户端:读热缓存(总览快照推导),不现场拉实例."""
|
||||
force = (request.args.get("force") or "").strip().lower() in ("1", "true", "yes")
|
||||
if force:
|
||||
cond_orders_store.request_refresh()
|
||||
overview_store.request_refresh()
|
||||
snap = cond_orders_store.snapshot_dict()
|
||||
return jsonify(
|
||||
{
|
||||
"ok": True,
|
||||
"instances": snap.get("candidates") or [],
|
||||
"cond_version": snap.get("cond_version"),
|
||||
"updated_at": snap.get("updated_at"),
|
||||
"refreshing": snap.get("refreshing"),
|
||||
"from_cache": True,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@app.route("/api/cond_orders", methods=["GET"])
|
||||
@login_required
|
||||
def api_cond_orders_list():
|
||||
instances = list_instances(enabled_only=True)
|
||||
all_orders = []
|
||||
for inst in instances:
|
||||
data = fetch_cond_orders(inst)
|
||||
for o in data.get("orders") or []:
|
||||
if not isinstance(o, dict):
|
||||
continue
|
||||
item = dict(o)
|
||||
item["instance_id"] = inst.get("id")
|
||||
item["instance_name"] = inst.get("name")
|
||||
all_orders.append(item)
|
||||
return jsonify({"ok": True, "orders": all_orders})
|
||||
"""条件单列表只读热缓存;后台常驻并行从实例拉取."""
|
||||
force = (request.args.get("force") or "").strip().lower() in ("1", "true", "yes")
|
||||
if force:
|
||||
cond_orders_store.request_refresh()
|
||||
snap = cond_orders_store.snapshot_dict()
|
||||
return jsonify(
|
||||
{
|
||||
"ok": True,
|
||||
"orders": snap.get("orders") or [],
|
||||
"cond_version": snap.get("cond_version"),
|
||||
"updated_at": snap.get("updated_at"),
|
||||
"refreshing": snap.get("refreshing"),
|
||||
"from_cache": True,
|
||||
"poll_interval_sec": snap.get("poll_interval_sec"),
|
||||
"error": snap.get("error"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@app.route("/api/cond_orders/refresh", methods=["POST"])
|
||||
@login_required
|
||||
def api_cond_orders_refresh():
|
||||
cond_orders_store.request_refresh()
|
||||
overview_store.request_refresh()
|
||||
return jsonify({"ok": True, "msg": "已触发条件单后台刷新"})
|
||||
|
||||
|
||||
@app.route("/api/cond_orders/stream")
|
||||
@login_required
|
||||
def api_cond_orders_stream():
|
||||
return Response(
|
||||
stream_with_context(cond_orders_store.iter_sse()),
|
||||
mimetype="text/event-stream",
|
||||
headers={
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive",
|
||||
"X-Accel-Buffering": "no",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@app.route("/api/cond_orders", methods=["POST"])
|
||||
@@ -749,8 +771,9 @@ def api_cond_orders_create():
|
||||
if not instance_ids:
|
||||
return jsonify({"ok": False, "msg": "请选择客户端"})
|
||||
|
||||
# 再次按快照过滤有仓/锁定
|
||||
rows = {r.get("id"): r for r in pull_all_enabled()}
|
||||
# 再次按热缓存快照过滤有仓/锁定(下发本身仍 POST 到实例)
|
||||
ov = overview_store.snapshot_dict()
|
||||
rows = {r.get("id"): r for r in (ov.get("instances") or [])}
|
||||
allowed = []
|
||||
rejected = []
|
||||
for iid in instance_ids:
|
||||
@@ -792,6 +815,9 @@ def api_cond_orders_create():
|
||||
}
|
||||
results = dispatch_cond_order_to_ids(allowed, payload)
|
||||
ok_n = sum(1 for r in results if r.get("ok"))
|
||||
if ok_n > 0:
|
||||
cond_orders_store.request_refresh()
|
||||
overview_store.request_refresh()
|
||||
return jsonify(
|
||||
{
|
||||
"ok": ok_n > 0,
|
||||
@@ -813,7 +839,11 @@ def api_cond_orders_cancel(hub_order_id: str):
|
||||
inst = get_instance(int(iid))
|
||||
if not inst:
|
||||
return jsonify({"ok": False, "msg": "实例不存在"}), 404
|
||||
return jsonify(post_cond_cancel(inst, hub_order_id))
|
||||
result = post_cond_cancel(inst, hub_order_id)
|
||||
if isinstance(result, dict) and result.get("ok"):
|
||||
cond_orders_store.request_refresh()
|
||||
overview_store.request_refresh()
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@app.route("/api/cond_orders/<hub_order_id>/exit", methods=["POST"])
|
||||
@@ -831,7 +861,11 @@ def api_cond_orders_exit(hub_order_id: str):
|
||||
"profit_exit_enabled": data.get("profit_exit_enabled"),
|
||||
"profit_exit_mult": data.get("profit_exit_mult"),
|
||||
}
|
||||
return jsonify(post_cond_exit(inst, hub_order_id, payload))
|
||||
result = post_cond_exit(inst, hub_order_id, payload)
|
||||
if isinstance(result, dict) and result.get("ok"):
|
||||
cond_orders_store.request_refresh()
|
||||
overview_store.request_refresh()
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@app.route("/manifest.webmanifest")
|
||||
|
||||
Reference in New Issue
Block a user