feat: 手续费仅CTP每日后台同步入库,前端只读展示

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-24 13:33:14 +08:00
parent de6815d481
commit e01c011df5
7 changed files with 240 additions and 214 deletions
+43 -88
View File
@@ -2,82 +2,46 @@
{% block title %}手续费配置 - 国内期货监控系统{% endblock %}
{% block extra_css %}
<style>
.fees-split{margin-bottom:1.25rem}
.fees-split .card{margin-bottom:0;min-height:auto}
.fees-status-card .card-body{display:flex;flex-wrap:wrap;gap:.75rem 1.25rem;align-items:center}
.fees-status-card .fees-meta{font-size:.85rem;color:var(--text-muted)}
.fees-table-card .trade-table-wrap{
max-height:min(70vh,560px);
width:100%;
border:none;
border-radius:10px;
}
.fees-table-card .trade-table{min-width:1100px}
.fees-table-card .trade-table{min-width:960px}
.fees-table-card .card-body{padding:.75rem 1rem 1rem}
.fees-source-stats{font-size:.78rem;margin-top:.35rem}
</style>
{% endblock %}
{% block content %}
<div class="split-grid fees-split">
<div class="card">
<h2>手续费数据源</h2>
<div class="card-body">
<form action="{{ url_for('fees') }}" method="post">
<input type="hidden" name="action" value="fee_source">
<div class="field" style="margin-bottom:.75rem">
<label>计费依据</label>
<select name="fee_source_mode">
<option value="ctp" {% if fee_source_mode == 'ctp' %}selected{% endif %}>CTP 柜台(SimNow/实盘,推荐)</option>
<option value="local" {% if fee_source_mode == 'local' %}selected{% endif %}>本地 / AKShare 参考表</option>
</select>
</div>
<button type="submit" class="btn-primary">保存</button>
</form>
<p class="hint" style="margin-top:.75rem">
默认使用 <strong>CTP 柜台</strong> 费率(连接后自动同步,与 SimNow/期货公司一致)。
</p>
<div class="form-row" style="margin-top:.75rem;flex-wrap:wrap;gap:.5rem">
<form action="{{ url_for('fees') }}" method="post" style="display:inline">
<input type="hidden" name="action" value="sync_ctp">
<button type="submit" class="btn-primary" {% if not ctp_connected %}disabled title="请先连接 CTP"{% endif %}>从 CTP 同步费率</button>
</form>
{% if ctp_connected %}
<span class="badge profit">CTP 已连接</span>
{% else %}
<span class="badge planned">CTP 未连接</span>
{% endif %}
</div>
{% if fee_counts %}
<p class="fees-source-stats text-muted">
已缓存:
{% if fee_counts.get('ctp') %}<span class="badge profit">CTP {{ fee_counts.ctp }}</span>{% endif %}
{% if fee_counts.get('local') %}<span class="badge planned">local {{ fee_counts.local }}</span>{% endif %}
{% if fee_counts.get('json') %}<span class="badge planned">json {{ fee_counts.json }}</span>{% endif %}
{% if fee_counts.get('manual') %}<span class="badge planned">manual {{ fee_counts.manual }}</span>{% endif %}
</p>
{% endif %}
</div>
</div>
<div class="card">
<h2>本地参考倍率</h2>
<div class="card-body">
<p class="hint" style="margin-bottom:.65rem;font-size:.78rem">仅「本地数据源」时使用</p>
<form action="{{ url_for('fees') }}" method="post" class="form-row" style="flex-wrap:wrap;gap:.5rem;align-items:center;margin-bottom:.75rem">
<input type="hidden" name="action" value="multiplier">
<label class="text-muted" style="font-size:.85rem">标准费率 ×</label>
<input name="fee_multiplier" type="number" step="0.1" min="0" value="{{ multiplier }}" style="width:88px">
<button type="submit" class="btn-primary">保存倍率</button>
</form>
<div class="form-row" style="flex-wrap:wrap;gap:.5rem">
<form action="{{ url_for('fees') }}" method="post" style="display:inline">
<input type="hidden" name="action" value="sync">
<button type="submit" class="btn-secondary">AKShare 同步</button>
</form>
<form action="{{ url_for('fees') }}" method="post" style="display:inline">
<input type="hidden" name="action" value="reload_json">
<button type="submit" class="btn-link" style="padding:.45rem .85rem;border:1px solid var(--card-border);border-radius:8px">重载 JSON</button>
</form>
</div>
</div>
<div class="card fees-status-card">
<h2>CTP 手续费</h2>
<div class="card-body">
<p class="fees-meta" style="margin:0;flex:1;min-width:220px">
费率由后台从 <strong>CTP 柜台</strong> 同步写入数据库,<strong>每日自动更新一次</strong>,本页只读展示。
</p>
{% if ctp_connected %}
<span class="badge profit">CTP 已连接</span>
{% else %}
<span class="badge planned">CTP 未连接</span>
{% endif %}
{% if fee_synced_today %}
<span class="badge profit">今日已同步</span>
{% else %}
<span class="badge planned">今日未同步</span>
{% endif %}
{% if fee_last_sync %}
<span class="text-muted" style="font-size:.8rem">上次:{{ fee_last_sync[:16] }}</span>
{% endif %}
{% if fee_counts.get('ctp') %}
<span class="text-muted" style="font-size:.8rem">共 {{ fee_counts.ctp }} 个品种</span>
{% endif %}
<form action="{{ url_for('fees') }}" method="post" style="display:inline">
<input type="hidden" name="action" value="sync_ctp">
<input type="hidden" name="force" value="1">
<button type="submit" class="btn-primary" {% if not ctp_connected %}disabled title="请先连接 CTP"{% endif %}>立即同步</button>
</form>
</div>
</div>
@@ -88,47 +52,38 @@
<table class="trade-table">
<thead>
<tr>
<th>品种</th><th>来源</th><th>交易所</th><th>乘数</th>
<th>品种</th><th>交易所</th><th>乘数</th>
<th>开仓(元/手)</th><th>开仓(比例)</th>
<th>平昨(元/手)</th><th>平昨(比例)</th>
<th>平今(元/手)</th><th>平今(比例)</th>
<th>更新</th><th>操作</th>
<th>更新</th>
</tr>
</thead>
<tbody>
{% for r in rates %}
{% set fid = 'fee-row-' ~ r.product %}
<tr>
<td><strong>{{ r.product }}</strong></td>
<td><span class="badge {% if r.source == 'ctp' %}profit{% else %}planned{% endif %}">{{ r.source or 'local' }}</span></td>
<td><input name="exchange" form="{{ fid }}" value="{{ r.exchange or '' }}" style="width:72px;padding:.3rem"></td>
<td><input name="mult" form="{{ fid }}" type="number" value="{{ r.mult }}" style="width:56px;padding:.3rem"></td>
<td><input name="open_fixed" form="{{ fid }}" type="number" step="0.0001" value="{{ r.open_fixed }}" style="width:72px;padding:.3rem"></td>
<td><input name="open_ratio" form="{{ fid }}" type="number" step="0.0000001" value="{{ r.open_ratio }}" style="width:88px;padding:.3rem"></td>
<td><input name="close_yesterday_fixed" form="{{ fid }}" type="number" step="0.0001" value="{{ r.close_yesterday_fixed }}" style="width:72px;padding:.3rem"></td>
<td><input name="close_yesterday_ratio" form="{{ fid }}" type="number" step="0.0000001" value="{{ r.close_yesterday_ratio }}" style="width:88px;padding:.3rem"></td>
<td><input name="close_today_fixed" form="{{ fid }}" type="number" step="0.0001" value="{{ r.close_today_fixed }}" style="width:72px;padding:.3rem"></td>
<td><input name="close_today_ratio" form="{{ fid }}" type="number" step="0.0000001" value="{{ r.close_today_ratio }}" style="width:88px;padding:.3rem"></td>
<td class="cell-readonly">{{ r.exchange or '—' }}</td>
<td class="cell-readonly">{{ r.mult }}</td>
<td class="cell-readonly">{{ r.open_fixed }}</td>
<td class="cell-readonly">{{ r.open_ratio }}</td>
<td class="cell-readonly">{{ r.close_yesterday_fixed }}</td>
<td class="cell-readonly">{{ r.close_yesterday_ratio }}</td>
<td class="cell-readonly">{{ r.close_today_fixed }}</td>
<td class="cell-readonly">{{ r.close_today_ratio }}</td>
<td class="text-muted" style="font-size:.72rem">{{ (r.updated_at or '')[:16] }}</td>
<td><button type="submit" form="{{ fid }}" class="btn-link">保存</button></td>
</tr>
{% else %}
<tr><td colspan="12" class="text-muted">暂无费率,请连接 CTP 后同步</td></tr>
<tr><td colspan="10" class="text-muted">暂无 CTP 费率,请连接 CTP 后等待自动同步或点击「立即同步」</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% for r in rates %}
<form id="fee-row-{{ r.product }}" action="{{ url_for('fees') }}" method="post" hidden>
<input type="hidden" name="action" value="save_row">
<input type="hidden" name="product" value="{{ r.product }}">
</form>
{% endfor %}
</div>
<p class="hint" style="margin-top:.75rem;padding:0 1rem 1rem">
公式:单边 = 固定(元/手)×手数 + 比例×价格×乘数×手数;往返 = 开仓 + 平仓(平今/平昨自动判断)。
{% if fee_source_mode == 'ctp' and ctp_connected and not fee_counts.get('ctp') %}
<br><strong class="text-loss">当前无 CTP 费率缓存,请点击「从 CTP 同步费率」</strong>
{% if ctp_connected and not fee_counts.get('ctp') %}
<br><strong class="text-loss">数据库尚无 CTP 费率,请点击「立即同步」或等待后台每日任务</strong>
{% endif %}
</p>
</div>