c5262a0a54
Mobile gets compact trade/records UI with detail modals; static assets are cache-busted and settings cards fold correctly on tablet grid layout. Co-authored-by: Cursor <cursoragent@cursor.com>
210 lines
13 KiB
HTML
210 lines
13 KiB
HTML
{# Copyright (c) 2025-2026 马建军. All rights reserved. 专有软件,详见 LICENSE.zh-CN.txt #}
|
|
{% extends "base.html" %}
|
|
{% block title %}策略交易 - 国内期货 · 交易复盘系统{% endblock %}
|
|
{% block extra_css %}
|
|
<style>
|
|
.strategy-page .split-grid .card{min-height:420px;display:flex;flex-direction:column}
|
|
.strategy-page .split-grid .card-body{flex:1}
|
|
.strategy-preview{background:var(--card-inner);border:1px solid var(--card-border);border-radius:8px;padding:.65rem .85rem;font-size:.78rem;line-height:1.5;margin-top:.75rem;max-height:360px;overflow:auto}
|
|
.strategy-preview .trend-summary{margin-bottom:.45rem;color:var(--text-title);font-size:.8rem;line-height:1.55}
|
|
.strategy-preview .trend-detail{margin-bottom:.55rem;color:var(--text-muted);font-size:.75rem;line-height:1.5}
|
|
.strategy-preview-table{width:100%;border-collapse:collapse;font-size:.72rem;min-width:520px}
|
|
.strategy-preview-table th,.strategy-preview-table td{padding:.35rem .4rem;border-bottom:1px solid var(--table-border);text-align:right;white-space:nowrap}
|
|
.strategy-preview-table th:first-child,.strategy-preview-table td:first-child{text-align:left}
|
|
.strategy-preview-table thead th{color:var(--text-muted);font-weight:600;background:var(--list-item-bg)}
|
|
.strategy-page .form-line.line-trend-head{grid-template-columns:1.5fr .75fr .85fr}
|
|
.strategy-steps{margin:.75rem 0 0;padding-left:1.1rem;font-size:.82rem;color:var(--text-muted);line-height:1.6}
|
|
.strategy-steps a{color:var(--accent)}
|
|
.strategy-active-roll{margin-top:.65rem;padding:.55rem .75rem;background:var(--card-inner);border-radius:8px;font-size:.8rem;border:1px solid var(--card-border)}
|
|
</style>
|
|
{% endblock %}
|
|
{% block content %}
|
|
<div class="strategy-page">
|
|
<details class="module-rules">
|
|
<summary>规则说明</summary>
|
|
<div class="module-rules-body">
|
|
<p><strong>趋势回调</strong></p>
|
|
<ul>
|
|
<li>填写品种、方向、周期、止损、补仓边界、止盈 → <strong>预览计划</strong> → 确认后<strong>市价开首仓</strong></li>
|
|
<li>须 CTP 已连接、交易时段内、账户风控允许开仓</li>
|
|
<li>运行中:价格触及<strong>止盈</strong> → 全部平仓结案;回落至<strong>网格档位</strong> → 自动分档补仓</li>
|
|
<li>可手动「结束计划」;记录归档至策略交易记录</li>
|
|
</ul>
|
|
<p><strong>顺势加仓(滚仓)</strong></p>
|
|
<ul>
|
|
<li>仅<strong>固定金额(以损定仓)</strong>模式;<strong>移动保本</strong>持仓不可滚仓</li>
|
|
<li>须「下单监控」有 active 持仓;与趋势回调互斥</li>
|
|
<li>风险预算 = 系统设置<strong>固定金额</strong>;合并持仓打到新止损总亏损 ≤ B</li>
|
|
<li>最多 3 腿(已成交);同一组最多 1 条 pending 监控腿</li>
|
|
<li>止盈锁定首仓;突破由程序监控标记价穿越后市价加仓</li>
|
|
</ul>
|
|
</div>
|
|
</details>
|
|
<div class="split-grid">
|
|
<div class="card">
|
|
<h2>趋势回调</h2>
|
|
<div class="card-body">
|
|
{% if active_trend %}
|
|
<p class="hint">运行中 #{{ active_trend.id }} · {{ active_trend.symbol_name or active_trend.symbol }} · {{ '做多' if active_trend.direction == 'long' else '做空' }} · {{ active_trend.period_label or '15分' }}</p>
|
|
<p class="hint">已开 <strong>{{ active_trend.lots_open or 0 }}</strong> / {{ active_trend.target_lots }} 手 · 止损 {{ active_trend.stop_loss }} · 止盈 {{ active_trend.take_profit }}</p>
|
|
<form id="trend-stop-form" class="form-row" style="margin-top:.75rem">
|
|
<input type="hidden" name="plan_id" value="{{ active_trend.id }}">
|
|
<button type="button" class="btn-primary" id="btn-trend-stop">结束计划</button>
|
|
</form>
|
|
<p class="hint" style="margin-top:.75rem;font-size:.75rem">后台按档位自动补仓,触及止盈或手动结束。</p>
|
|
{% else %}
|
|
<p class="hint" style="margin-bottom:.65rem">设置止损/补仓边界/止盈 → 预览 → 确认执行首仓;后续自动分档加仓。</p>
|
|
<form id="trend-form" class="form-compact">
|
|
<div class="form-line line-trend-head">
|
|
<div class="symbol-wrap symbol-mains">
|
|
<input type="text" class="symbol-input" placeholder="品种,输入中文或代码" autocomplete="off" required>
|
|
<input type="hidden" name="symbol" class="symbol-ths-code">
|
|
<input type="hidden" name="symbol_name">
|
|
<div class="symbol-dropdown"></div>
|
|
<div class="symbol-selected"></div>
|
|
</div>
|
|
<select name="direction"><option value="long">做多</option><option value="short">做空</option></select>
|
|
<select name="period" title="参考 K 线周期">
|
|
{% for p in trend_periods %}
|
|
<option value="{{ p.key }}"{% if p.key == '15m' %} selected{% endif %}>{{ p.label }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="form-line line-3">
|
|
<input name="stop_loss" type="number" step="any" placeholder="止损" required>
|
|
<input name="add_upper" type="number" step="any" placeholder="补仓边界" required>
|
|
<input name="take_profit" type="number" step="any" placeholder="止盈" required>
|
|
</div>
|
|
<div class="form-line line-2">
|
|
<input name="risk_percent" type="number" step="0.1" value="{{ risk_percent }}" placeholder="单笔风险 %" title="单笔风险%">
|
|
<button type="button" class="btn-primary" id="btn-trend-preview">预览计划</button>
|
|
</div>
|
|
</form>
|
|
<div id="trend-preview" class="strategy-preview" hidden></div>
|
|
<button type="button" class="btn-primary" id="btn-trend-exec" hidden style="margin-top:.65rem;width:100%">确认执行首仓</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>顺势加仓(滚仓)</h2>
|
|
<div class="card-body">
|
|
<details class="module-rules" style="margin-bottom:.65rem">
|
|
<summary>顺势加仓规则说明</summary>
|
|
<div class="module-rules-body" style="font-size:.78rem;line-height:1.55">
|
|
<ul>
|
|
<li>手动提交;须实盘已有同向持仓与 active 监控单</li>
|
|
<li>计仓模式须为<strong>固定金额</strong>;移动保本不可滚仓</li>
|
|
<li>做多/做空各最多 3 次滚仓(仅计已成交);止盈为首仓 TP 不变</li>
|
|
<li>风险预算 B = 系统设置中的<strong>固定金额</strong>;打到新止损 S 时合并持仓总亏损 ≤ B</li>
|
|
<li>突破:标记价穿越触发价后按当时持仓重算手数再市价加仓</li>
|
|
<li>pending 腿不可改,只能删除;手动平仓后滚仓组关闭</li>
|
|
</ul>
|
|
</div>
|
|
</details>
|
|
{% if not roll_allowed %}
|
|
<p class="hint text-muted">当前为「{{ sizing_mode_label }}」模式,滚仓不可用。请在系统设置切换为<strong>固定金额</strong>。</p>
|
|
{% endif %}
|
|
{% if monitors %}
|
|
<p class="hint" id="roll-risk-hint">风险预算(固定金额):<strong id="roll-risk-budget">{{ '%.0f'|format(fixed_amount) }} 元</strong></p>
|
|
<form id="roll-form" class="form-compact">
|
|
<div class="form-line line-2">
|
|
<select name="monitor_id" id="roll-monitor-select" required {% if not roll_allowed %}disabled{% endif %}>
|
|
{% for m in monitors %}
|
|
<option value="{{ m.id }}"
|
|
data-direction="{{ m.direction }}"
|
|
data-eligible="{{ '1' if m.roll_eligible else '0' }}"
|
|
data-block="{{ m.roll_block_reason or '' }}"
|
|
{% if not m.roll_eligible %}disabled{% endif %}>
|
|
{{ m.symbol_name or m.symbol }} {{ m.symbol }} · {{ '多' if m.direction == 'long' else '空' }} #{{ m.id }}
|
|
· {{ m.lots }}手 · SL {{ m.stop_loss or '—' }}
|
|
{% if not m.roll_eligible %} · {{ m.roll_block_reason }}{% endif %}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
<select name="add_mode" id="roll-add-mode" {% if not roll_allowed %}disabled{% endif %}>
|
|
<option value="market">市价加仓</option>
|
|
<option value="breakout">突破加仓</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-line line-2">
|
|
<input name="new_stop_loss" id="roll-new-sl" type="number" step="any" placeholder="新统一止损" required {% if not roll_allowed %}disabled{% endif %}>
|
|
<input name="breakthrough_price" id="roll-break-price" type="number" step="any" placeholder="突破价" hidden>
|
|
</div>
|
|
<div class="form-line line-2">
|
|
<button type="button" class="btn-primary" id="btn-roll-preview" {% if not roll_allowed %}disabled{% endif %}>预览</button>
|
|
<button type="button" class="btn-primary" id="btn-roll-exec" hidden {% if not roll_allowed %}disabled{% endif %}>执行滚仓</button>
|
|
</div>
|
|
<div id="roll-preview" class="strategy-preview" hidden></div>
|
|
<p class="hint" id="roll-exec-hint" hidden style="font-size:.75rem;margin-top:.45rem">市价加仓:须交易时段内确认,10 秒倒计时执行;突破加仓:任意时间可提交,开盘后再监控触价</p>
|
|
</form>
|
|
{% else %}
|
|
<p class="empty-hint">暂无可用持仓监控</p>
|
|
<ol class="strategy-steps">
|
|
<li>打开 <a href="{{ url_for('positions') }}">持仓监控</a>,连接 CTP</li>
|
|
<li>系统设置为<strong>固定金额</strong>,在「期货下单」开仓(勿开移动保本)</li>
|
|
<li>开仓成功后生成本页可选监控,即可滚仓</li>
|
|
</ol>
|
|
{% endif %}
|
|
<h3 style="font-size:.85rem;margin:1rem 0 .45rem">活跃滚仓组</h3>
|
|
{% if roll_groups %}
|
|
<div class="table-responsive">
|
|
<table class="strategy-preview-table">
|
|
<thead><tr>
|
|
<th>ID</th><th>品种</th><th>方向</th><th>腿数</th><th>首仓TP</th><th>当前SL</th><th>当前均价</th><th>止盈盈利(元)</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
{% for g in roll_groups %}
|
|
<tr>
|
|
<td>#{{ g.id }}</td>
|
|
<td>{{ g.symbol_name or g.symbol }}</td>
|
|
<td>{{ '多' if g.direction == 'long' else '空' }}</td>
|
|
<td>{{ g.leg_count or 0 }}/3</td>
|
|
<td>{{ g.initial_take_profit or '—' }}</td>
|
|
<td>{{ g.current_stop_loss or '—' }}</td>
|
|
<td>{{ g.avg_entry or '—' }}</td>
|
|
<td>{{ g.reward_at_tp if g.reward_at_tp is not none else '—' }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<p class="hint text-muted">暂无</p>
|
|
{% endif %}
|
|
<h3 style="font-size:.85rem;margin:1rem 0 .45rem">最近滚仓腿</h3>
|
|
{% if roll_legs %}
|
|
<div class="table-responsive">
|
|
<table class="strategy-preview-table">
|
|
<thead><tr>
|
|
<th>#</th><th>组</th><th>方式</th><th>手数</th><th>触发/限价</th><th>新SL</th><th>状态</th><th>操作</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
{% for l in roll_legs %}
|
|
<tr>
|
|
<td>{{ l.id }}</td>
|
|
<td>#{{ l.roll_group_id }}</td>
|
|
<td>{{ add_mode_labels.get(l.add_mode, l.add_mode) }}</td>
|
|
<td>{{ l.lots or '—' }}</td>
|
|
<td>{{ l.breakthrough_price or l.limit_price or l.fill_price or '—' }}</td>
|
|
<td>{{ l.new_stop_loss or '—' }}</td>
|
|
<td title="{{ l.invalidated_reason or '' }}">{{ roll_leg_status_labels.get(l.status, l.status) }}{% if l.status == 'invalidated' and l.invalidated_reason %} · {{ l.invalidated_reason[:24] }}{% endif %}</td>
|
|
<td>{% if l.status == 'pending' %}<button type="button" class="btn-link roll-cancel-leg" data-leg-id="{{ l.id }}">删除</button>{% else %}—{% endif %}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<p class="hint text-muted">暂无</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p class="hint" style="margin-top:1rem"><a href="{{ url_for('strategy_records_page') }}">策略交易记录 →</a></p>
|
|
</div>
|
|
{% endblock %}
|
|
{% block extra_js %}
|
|
<script src="{{ url_for('static', filename='js/strategy.js') }}"></script>
|
|
{% endblock %}
|