diff --git a/app/db.py b/app/db.py index d2e76fe..804f722 100644 --- a/app/db.py +++ b/app/db.py @@ -398,6 +398,43 @@ def count_trades( return int(row["c"] if row else 0) +def trades_fingerprint( + conn: sqlite3.Connection, + account_id: Optional[int] = None, + machine_id: Optional[int] = None, +) -> str: + """列表/统计页轮询用:成交条数、最新 id/平仓时间、标注变化任一变即刷新。""" + clause, params = _trades_where(account_id, machine_id, hide_synthetic=True) + row = conn.execute( + f""" + SELECT COUNT(*) AS c, + COALESCE(MAX(t.id), 0) AS max_id, + COALESCE(MAX(t.close_time), 0) AS max_close, + COALESCE(MAX(t.open_time), 0) AS max_open, + SUM(CASE WHEN IFNULL(t.entry_style,'') != '' THEN 1 ELSE 0 END) AS annotated, + SUM(CASE WHEN IFNULL(t.review_issues,'') != '' THEN 1 ELSE 0 END) AS issues, + SUM(CASE WHEN t.close_time IS NULL OR t.close_time='' THEN 1 ELSE 0 END) AS open_n + FROM trades t + {clause} + """, + tuple(params), + ).fetchone() + if not row: + return "0" + return "|".join( + str(x) + for x in ( + int(row["c"] or 0), + int(row["max_id"] or 0), + round(float(row["max_close"] or 0), 3), + round(float(row["max_open"] or 0), 3), + int(row["annotated"] or 0), + int(row["issues"] or 0), + int(row["open_n"] or 0), + ) + ) + + def list_trades( conn: sqlite3.Connection, limit: int = 200, @@ -792,7 +829,7 @@ def trade_stats( "by_style": [ _finalize_group(by_style[k]) for k in style_order - if k in by_style and (by_style[k]["count"] or k in ENTRY_STYLES) + if k in by_style and by_style[k]["count"] ], } diff --git a/app/routes.py b/app/routes.py index de1d0f3..381d067 100644 --- a/app/routes.py +++ b/app/routes.py @@ -941,6 +941,20 @@ def register_routes(app: Flask) -> None: total_pages=total_pages, ) + @app.get("/api/records/fingerprint") + @login_required + def records_fingerprint(): + """复盘列表/统计页轮询:成交或标注变化时前端自动刷新。""" + u = current_user() + machine_raw = (request.args.get("machine_id") or "").strip() + account_id = None if u["role"] == "admin" else u.get("account_id") + _machines, machine_id = _resolve_machine_filter(u, machine_raw) + with database.get_db() as conn: + fp = database.trades_fingerprint( + conn, account_id=account_id, machine_id=machine_id + ) + return jsonify({"ok": True, "fp": fp, "ts": database.now()}) + @app.get("/records/stats") @login_required def records_stats_page(): diff --git a/app/templates/records.html b/app/templates/records.html index b03d97c..ff86b49 100644 --- a/app/templates/records.html +++ b/app/templates/records.html @@ -1,8 +1,11 @@ {% extends "base.html" %} {% block title %}交易复盘 · {{ app_name }}{% endblock %} {% block content %} -
按机器筛选 · 每页 {{ per_page }} 条 · 时间均为北京时间 · 已隐藏对账/去重影子记录
+按机器筛选 · 每页 {{ per_page }} 条 · 北京时间 · 成交变化会自动刷新 · 已隐藏对账/去重影子记录
默认按北京时间今日真实平仓统计;对账/去重产生的假平仓已排除。 + 成交/标注变化会自动刷新本页。 {% if selected_period == 'today' and stats.day %}当前:{{ stats.day }}{% endif %} {% if stats.skipped_synthetic %} · 已排除假平仓 {{ stats.skipped_synthetic }} 笔{% endif %} {% if stats.skipped_dup_ticket %} · 已排除重复单号 {{ stats.skipped_dup_ticket }} 笔{% endif %} @@ -82,6 +86,7 @@
需在复盘页选「入场形式」后才会分入顺势/反转;未选的汇总在「未标注」。
| {{ g.avg_hold }} | ||||
| 暂无数据 | ||||
| 暂无入场形式标注 | ||||