新增平仓汇总页面,按期货/期权/双买分类统计盈亏和胜率
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}平仓汇总{% endblock %}
|
||||
{% block heading %}平仓汇总{% endblock %}
|
||||
{% block breadcrumb %}全部已平仓统计{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<style>
|
||||
.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; margin-bottom: 28px; }
|
||||
.stat-card {
|
||||
background: var(--surface); border: 1px solid var(--border);
|
||||
border-radius: 10px; padding: 18px 20px; text-align: center;
|
||||
}
|
||||
.stat-card .label { font-size: 0.75rem; color: var(--sub); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.04em; }
|
||||
.stat-card .value { font-size: 1.4rem; font-weight: 700; }
|
||||
.tabs { display: flex; gap: 0; margin-bottom: 24px; border-bottom: 2px solid var(--border); }
|
||||
.tab-btn {
|
||||
padding: 10px 20px; border: none; background: none;
|
||||
font-size: 0.88rem; font-weight: 500; color: var(--sub);
|
||||
cursor: pointer; text-decoration: none; border-bottom: 2px solid transparent;
|
||||
margin-bottom: -2px; transition: color .12s, border-color .12s;
|
||||
}
|
||||
.tab-btn:hover { color: var(--fg); }
|
||||
.tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
|
||||
.tab-panel { display: none; }
|
||||
.tab-panel.active { display: block; }
|
||||
.sub-stat { display: flex; gap: 18px; margin-bottom: 20px; flex-wrap: wrap; }
|
||||
.sub-stat span { font-size: 0.82rem; color: var(--sub); }
|
||||
.sub-stat b { color: var(--fg); }
|
||||
</style>
|
||||
|
||||
{% set view = request.query_params.get('view', '') %}
|
||||
|
||||
{# ── 总览卡片 ── #}
|
||||
<div class="stat-grid">
|
||||
<div class="stat-card">
|
||||
<div class="label">总平仓笔数</div>
|
||||
<div class="value">{{ total_count }}</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="label">总盈亏</div>
|
||||
<div class="value" style="{% if total_pnl > 0 %}color:var(--success-fg);{% elif total_pnl < 0 %}color:var(--danger-fg);{% endif %}">
|
||||
{% if total_pnl > 0 %}+{% endif %}{{ "%.0f"|format(total_pnl) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="label">总手续费</div>
|
||||
<div class="value">{{ "%.0f"|format(total_fee) }}</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="label">总胜率</div>
|
||||
<div class="value" style="{% if total_win_rate >= 50 %}color:var(--success-fg);{% else %}color:var(--danger-fg);{% endif %}">
|
||||
{{ total_win_rate }}%
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="label">净盈亏</div>
|
||||
<div class="value" style="{% if total_pnl - total_fee > 0 %}color:var(--success-fg);{% elif total_pnl - total_fee < 0 %}color:var(--danger-fg);{% endif %}">
|
||||
{% set net = total_pnl - total_fee %}
|
||||
{% if net > 0 %}+{% endif %}{{ "%.0f"|format(net) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# ── 按类型分拆 ── #}
|
||||
<div class="tabs">
|
||||
<a href="/summary/?view=futures" class="tab-btn{% if view != 'options' and view != 'dual' %} active{% endif %}">📝 期货</a>
|
||||
<a href="/summary/?view=options" class="tab-btn{% if view == 'options' %} active{% endif %}">📊 期权</a>
|
||||
<a href="/summary/?view=dual" class="tab-btn{% if view == 'dual' %} active{% endif %}">🎯 双买</a>
|
||||
</div>
|
||||
|
||||
{# ═══════════ 期货 ═══════════ #}
|
||||
<div class="tab-panel{% if view != 'options' and view != 'dual' %} active{% endif %}">
|
||||
<div class="sub-stat">
|
||||
<span>笔数 <b>{{ future_stats.count }}</b></span>
|
||||
<span>盈亏 <b style="{% if future_stats.pnl > 0 %}color:var(--success-fg);{% elif future_stats.pnl < 0 %}color:var(--danger-fg);{% endif %}">{% if future_stats.pnl > 0 %}+{% endif %}{{ "%.0f"|format(future_stats.pnl) }}</b></span>
|
||||
<span>手续费 <b>{{ "%.0f"|format(future_stats.total_fee) }}</b></span>
|
||||
<span>胜率 <b style="{% if future_stats.win_rate >= 50 %}color:var(--success-fg);{% else %}color:var(--danger-fg);{% endif %}">{{ future_stats.win_rate }}%</b></span>
|
||||
</div>
|
||||
|
||||
{% if future_trades %}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tr><th>品种</th><th>合约</th><th>方向</th><th>开仓日</th><th>平仓日</th><th>持仓</th><th>开仓价</th><th>平仓价</th><th>盈亏</th></tr>
|
||||
{% for t in future_trades %}
|
||||
<tr>
|
||||
<td>{{ t.product_code }}</td>
|
||||
<td><strong>{{ t.contract_code.replace(t.product_code, '', 1) if t.contract_code.startswith(t.product_code) else t.contract_code }}</strong></td>
|
||||
<td>
|
||||
{% if t.direction == 'long' %}
|
||||
<span class="badge badge-up">多</span>
|
||||
{% else %}
|
||||
<span class="badge badge-down">空</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="font-size:0.8rem;">{{ t.open_date }} {{ weekdays[t.open_date.weekday()] }}</td>
|
||||
<td style="font-size:0.8rem;">{{ t.close_date }} {{ weekdays[t.close_date.weekday()] }}</td>
|
||||
<td>{{ (t.close_date - t.open_date).days }}天</td>
|
||||
<td>{{ t.open_price }}</td>
|
||||
<td>{{ t.close_price }}</td>
|
||||
<td>
|
||||
{% set p = t.pnl %}
|
||||
{% if p is not none %}
|
||||
<span style="font-weight:700;{% if p > 0 %}color:var(--success-fg);{% elif p < 0 %}color:var(--danger-fg);{% endif %}">
|
||||
{% if p > 0 %}+{% endif %}{{ p }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="text-align:center;padding:40px;color:var(--sub);">暂无已平仓记录</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# ═══════════ 期权 ═══════════ #}
|
||||
<div class="tab-panel{% if view == 'options' %} active{% endif %}">
|
||||
<div class="sub-stat">
|
||||
<span>笔数 <b>{{ option_stats.count }}</b></span>
|
||||
<span>盈亏 <b style="{% if option_stats.pnl > 0 %}color:var(--success-fg);{% elif option_stats.pnl < 0 %}color:var(--danger-fg);{% endif %}">{% if option_stats.pnl > 0 %}+{% endif %}{{ "%.0f"|format(option_stats.pnl) }}</b></span>
|
||||
<span>手续费 <b>{{ "%.0f"|format(option_stats.total_fee) }}</b></span>
|
||||
<span>胜率 <b style="{% if option_stats.win_rate >= 50 %}color:var(--success-fg);{% else %}color:var(--danger-fg);{% endif %}">{{ option_stats.win_rate }}%</b></span>
|
||||
</div>
|
||||
|
||||
{% if option_trades %}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tr><th>品种</th><th>合约</th><th>类型</th><th>买卖</th><th>行权价</th><th>开仓日</th><th>平仓日</th><th>持仓</th><th>开仓价</th><th>平仓价</th><th>盈亏</th></tr>
|
||||
{% for t in option_trades %}
|
||||
<tr>
|
||||
<td>{{ t.product_code }}</td>
|
||||
<td><strong>{{ t.contract_code.replace(t.product_code, '', 1) if t.contract_code.startswith(t.product_code) else t.contract_code }}</strong></td>
|
||||
<td>
|
||||
{% if t.option_type == 'C' %}
|
||||
<span class="badge badge-up">C</span>
|
||||
{% else %}
|
||||
<span class="badge badge-down">P</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if t.direction == 'buy' %}
|
||||
<span class="badge badge-up">买</span>
|
||||
{% else %}
|
||||
<span class="badge badge-down">卖</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ t.strike_price }}</td>
|
||||
<td style="font-size:0.8rem;">{{ t.open_date }} {{ weekdays[t.open_date.weekday()] }}</td>
|
||||
<td style="font-size:0.8rem;">{{ t.close_date }} {{ weekdays[t.close_date.weekday()] }}</td>
|
||||
<td>{{ (t.close_date - t.open_date).days }}天</td>
|
||||
<td>{{ t.open_price }}</td>
|
||||
<td>{{ t.close_price }}</td>
|
||||
<td>
|
||||
{% set p = t.pnl %}
|
||||
{% if p is not none %}
|
||||
<span style="font-weight:700;{% if p > 0 %}color:var(--success-fg);{% elif p < 0 %}color:var(--danger-fg);{% endif %}">
|
||||
{% if p > 0 %}+{% endif %}{{ p }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="text-align:center;padding:40px;color:var(--sub);">暂无已平仓记录</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# ═══════════ 双买 ═══════════ #}
|
||||
<div class="tab-panel{% if view == 'dual' %} active{% endif %}">
|
||||
<div class="sub-stat">
|
||||
<span>笔数 <b>{{ dual_stats.count }}</b></span>
|
||||
<span>盈亏 <b style="{% if dual_stats.pnl > 0 %}color:var(--success-fg);{% elif dual_stats.pnl < 0 %}color:var(--danger-fg);{% endif %}">{% if dual_stats.pnl > 0 %}+{% endif %}{{ "%.0f"|format(dual_stats.pnl) }}</b></span>
|
||||
<span>手续费 <b>{{ "%.0f"|format(dual_stats.total_fee) }}</b></span>
|
||||
<span>胜率 <b style="{% if dual_stats.win_rate >= 50 %}color:var(--success-fg);{% else %}color:var(--danger-fg);{% endif %}">{{ dual_stats.win_rate }}%</b></span>
|
||||
</div>
|
||||
|
||||
{% if dual_trades %}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tr><th>品种</th><th>合约</th><th>C行权价</th><th>P行权价</th><th>开仓日</th><th>平仓日</th><th>持仓</th><th>看涨(开/平)</th><th>看跌(开/平)</th><th>盈亏</th></tr>
|
||||
{% for t in dual_trades %}
|
||||
<tr>
|
||||
<td>{{ t.product_code }}</td>
|
||||
<td><strong>{{ t.contract_code.replace(t.product_code, '', 1) if t.contract_code.startswith(t.product_code) else t.contract_code }}</strong></td>
|
||||
<td>{{ t.call_strike_price }}</td>
|
||||
<td>{{ t.put_strike_price }}</td>
|
||||
<td style="font-size:0.8rem;">{{ t.open_date }} {{ weekdays[t.open_date.weekday()] }}</td>
|
||||
<td style="font-size:0.8rem;">{{ t.close_date }} {{ weekdays[t.close_date.weekday()] }}</td>
|
||||
<td>{{ (t.close_date - t.open_date).days }}天</td>
|
||||
<td>{{ t.call_open_price }} / {{ t.call_close_price }}</td>
|
||||
<td>{{ t.put_open_price }} / {{ t.put_close_price }}</td>
|
||||
<td>
|
||||
{% set p = t.pnl %}
|
||||
{% if p is not none %}
|
||||
<span style="font-weight:700;{% if p > 0 %}color:var(--success-fg);{% elif p < 0 %}color:var(--danger-fg);{% endif %}">
|
||||
{% if p > 0 %}+{% endif %}{{ p }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="text-align:center;padding:40px;color:var(--sub);">暂无已平仓记录</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user