Add trade stats board: win rate, hold buckets, by machine/side.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -12,7 +12,8 @@
|
||||
<div class="brand">{{ app_name }}</div>
|
||||
<nav class="nav">
|
||||
<a href="{{ url_for('dashboard') }}" class="{% if request.endpoint=='dashboard' %}active{% endif %}">总览</a>
|
||||
<a href="{{ url_for('records_page') }}" class="{% if request.endpoint and request.endpoint.startswith('record') %}active{% endif %}">交易复盘</a>
|
||||
<a href="{{ url_for('records_page') }}" class="{% if request.endpoint in ('records_page', 'record_detail', 'record_annotate') %}active{% endif %}">交易复盘</a>
|
||||
<a href="{{ url_for('records_stats_page') }}" class="{% if request.endpoint=='records_stats_page' %}active{% endif %}">统计看板</a>
|
||||
<a href="{{ url_for('download_page') }}" class="{% if request.endpoint and 'download' in request.endpoint %}active{% endif %}">下载中心</a>
|
||||
{% if is_admin %}
|
||||
<a href="{{ url_for('accounts_page') }}" class="{% if request.endpoint and 'account' in request.endpoint %}active{% endif %}">账户</a>
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
{% block title %}交易复盘 · {{ app_name }}{% endblock %}
|
||||
{% block content %}
|
||||
<h2 style="margin:0 0 6px">交易记录与复盘</h2>
|
||||
<p class="muted" style="margin:0 0 14px">按机器筛选 · 每页 {{ per_page }} 条 · 时间均为北京时间</p>
|
||||
<p class="muted" style="margin:0 0 10px">按机器筛选 · 每页 {{ per_page }} 条 · 时间均为北京时间</p>
|
||||
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;flex-wrap:wrap">
|
||||
<a class="btn" href="{{ url_for('records_page', machine_id=selected_machine_id) if selected_machine_id else url_for('records_page') }}">交易列表</a>
|
||||
<a class="btn secondary" href="{{ url_for('records_stats_page', machine_id=selected_machine_id) if selected_machine_id else url_for('records_stats_page') }}">统计看板</a>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-bottom:14px">
|
||||
<form method="get" action="{{ url_for('records_page') }}" style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}统计看板 · {{ app_name }}{% endblock %}
|
||||
{% block content %}
|
||||
<h2 style="margin:0 0 6px">统计看板</h2>
|
||||
<p class="muted" style="margin:0 0 10px">程序汇总成交数据;入场形式分类确定后再叠加维度。</p>
|
||||
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;flex-wrap:wrap">
|
||||
<a class="btn secondary" href="{{ url_for('records_page', machine_id=selected_machine_id) if selected_machine_id else url_for('records_page') }}">交易列表</a>
|
||||
<a class="btn" href="{{ url_for('records_stats_page', machine_id=selected_machine_id) if selected_machine_id else url_for('records_stats_page') }}">统计看板</a>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-bottom:14px">
|
||||
<form method="get" action="{{ url_for('records_stats_page') }}" style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
|
||||
<label class="muted" for="machine_id" style="margin:0">机器</label>
|
||||
<select name="machine_id" id="machine_id" style="min-width:200px;width:auto">
|
||||
<option value="">全部机器</option>
|
||||
{% for m in machines %}
|
||||
<option value="{{ m.id }}" {% if selected_machine_id == m.id %}selected{% endif %}>
|
||||
{{ m.name }} #{{ m.id }}{% if m.online %} · 在线{% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit" class="btn">筛选</button>
|
||||
{% if selected_machine_id %}
|
||||
<a class="btn secondary" href="{{ url_for('records_stats_page') }}">清除</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-3">
|
||||
<div class="card">
|
||||
<div class="muted">成交笔数</div>
|
||||
<div class="stat">{{ stats.total }}</div>
|
||||
<div class="muted" style="margin-top:6px">已平 {{ stats.closed }} · 持仓中 {{ stats.open_pos }}</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="muted">胜率</div>
|
||||
<div class="stat">{{ '%.1f'|format(stats.win_rate) }}%</div>
|
||||
<div class="muted" style="margin-top:6px">盈 {{ stats.wins }} · 亏 {{ stats.losses }} · 平 {{ stats.breakeven }}</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="muted">合计盈亏</div>
|
||||
<div class="stat" style="color:{% if stats.profit>0 %}var(--green){% elif stats.profit<0 %}var(--red){% else %}inherit{% endif %}">
|
||||
{{ '%.2f'|format(stats.profit) }}
|
||||
</div>
|
||||
<div class="muted" style="margin-top:6px">笔均 {{ '%.2f'|format(stats.avg_profit) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-3" style="margin-top:14px">
|
||||
<div class="card">
|
||||
<div class="muted">平均持仓时间</div>
|
||||
<div class="stat" style="font-size:22px;color:var(--accent)">{{ stats.avg_hold }}</div>
|
||||
<div class="muted" style="margin-top:6px">有开仓时间的样本参与计算</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="muted">盈亏因子</div>
|
||||
<div class="stat" style="font-size:22px">
|
||||
{% if stats.profit_factor is none %}—
|
||||
{% elif stats.profit_factor >= 999 %}∞
|
||||
{% else %}{{ '%.2f'|format(stats.profit_factor) }}{% endif %}
|
||||
</div>
|
||||
<div class="muted" style="margin-top:6px">毛利 {{ '%.2f'|format(stats.gross_win) }} / 毛亏 {{ '%.2f'|format(stats.gross_loss) }}</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="muted">入场形式标注</div>
|
||||
<div class="stat" style="font-size:22px">{{ stats.annotated }} <span class="muted" style="font-size:14px">/ {{ stats.total }}</span></div>
|
||||
<div class="muted" style="margin-top:6px">未标注 {{ stats.unannotated }}(分类确定后再细拆)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-2" style="margin-top:14px">
|
||||
<div class="card">
|
||||
<h3>按持仓时间</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>区间</th><th>笔数</th><th>胜率</th><th>盈亏</th><th>平均持仓</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for g in stats.by_hold %}
|
||||
<tr>
|
||||
<td>{{ g.label }}</td>
|
||||
<td>{{ g.count }}</td>
|
||||
<td>{{ '%.1f'|format(g.win_rate) }}%</td>
|
||||
<td style="color:{% if g.profit>0 %}var(--green){% elif g.profit<0 %}var(--red){% else %}inherit{% endif %}">
|
||||
{{ '%.2f'|format(g.profit) }}
|
||||
</td>
|
||||
<td class="muted">{{ g.avg_hold }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="5" class="muted">暂无数据</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>按方向</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>方向</th><th>笔数</th><th>胜率</th><th>盈亏</th><th>平均持仓</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for g in stats.by_side %}
|
||||
<tr>
|
||||
<td>{{ g.label }}</td>
|
||||
<td>{{ g.count }}</td>
|
||||
<td>{{ '%.1f'|format(g.win_rate) }}%</td>
|
||||
<td style="color:{% if g.profit>0 %}var(--green){% elif g.profit<0 %}var(--red){% else %}inherit{% endif %}">
|
||||
{{ '%.2f'|format(g.profit) }}
|
||||
</td>
|
||||
<td class="muted">{{ g.avg_hold }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="5" class="muted">暂无数据</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top:14px">
|
||||
<h3>按机器</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>机器</th><th>笔数</th><th>胜率</th><th>盈亏</th><th>笔均</th><th>平均持仓</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for g in stats.by_machine %}
|
||||
<tr>
|
||||
<td>{{ g.label }}</td>
|
||||
<td>{{ g.count }}</td>
|
||||
<td>{{ '%.1f'|format(g.win_rate) }}%</td>
|
||||
<td style="color:{% if g.profit>0 %}var(--green){% elif g.profit<0 %}var(--red){% else %}inherit{% endif %}">
|
||||
{{ '%.2f'|format(g.profit) }}
|
||||
</td>
|
||||
<td>{{ '%.2f'|format(g.avg_profit) }}</td>
|
||||
<td class="muted">{{ g.avg_hold }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="6" class="muted">暂无数据</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user