2065122777
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
214 lines
9.1 KiB
HTML
214 lines
9.1 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}仓位管理{% endblock %}
|
||
{% block heading %}仓位管理{% endblock %}
|
||
{% block breadcrumb %}振幅锁仓 · 仓位跟踪{% endblock %}
|
||
|
||
{% block content %}
|
||
|
||
{% set error = request.query_params.get('error', '') %}
|
||
|
||
{% if error %}
|
||
<div style="background:var(--danger-bg);color:var(--danger-fg);padding:10px 16px;border-radius:6px;margin-bottom:16px;font-size:0.88rem;">{{ error }}</div>
|
||
{% endif %}
|
||
|
||
{% if not active_round %}
|
||
{# ═══════════════ 新建轮次 ═══════════════ #}
|
||
<div class="section-title">新建轮次</div>
|
||
<div class="form-card" style="margin-bottom:28px;">
|
||
<form method="post" action="/positions/round">
|
||
<div style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;">
|
||
<div class="form-group" style="margin-bottom:0;flex:1;min-width:140px;">
|
||
<label>合约</label>
|
||
<select name="contract_code" required>
|
||
<option value="">-- 选择合约 --</option>
|
||
{% for c in contracts %}
|
||
<option value="{{ c }}">{{ c }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="form-group" style="margin-bottom:0;flex:1;min-width:100px;">
|
||
<label>每日手数 N</label>
|
||
<input type="number" name="daily_hands" value="1" min="1" max="10" required>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary">开始新轮</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div style="text-align:center;padding:60px;color:var(--sub);">
|
||
<p style="font-size:1.1rem;margin-bottom:8px;">暂无活跃轮次</p>
|
||
<p style="font-size:0.82rem;">创建一轮新的交易,开始跟踪仓位和锁仓状态</p>
|
||
</div>
|
||
|
||
{% else %}
|
||
{# ═══════════════ 活跃轮次信息 ═══════════════ #}
|
||
{% set locks = active_round.total_locks %}
|
||
<div class="stat-grid">
|
||
<div class="stat-card">
|
||
<div class="label">合约</div>
|
||
<div class="value">{{ active_round.contract_code }}</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="label">每日手数</div>
|
||
<div class="value">{{ active_round.daily_hands }} 手/天</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="label">已开仓天数</div>
|
||
<div class="value">{{ active_round.positions|length }} 天</div>
|
||
</div>
|
||
<div class="stat-card" style="{% if locks >= 3 %}border-color:var(--danger);background:var(--danger-bg);{% endif %}">
|
||
<div class="label">累计锁仓</div>
|
||
<div class="value" style="{% if locks >= 3 %}color:var(--danger-fg);{% endif %}">
|
||
{{ locks }} / 3
|
||
{% if locks >= 3 %}⚠ 熔断{% endif %}
|
||
</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="label">开始日期</div>
|
||
<div class="value" style="font-size:1rem;">{{ active_round.started_at }}</div>
|
||
</div>
|
||
</div>
|
||
|
||
{# ═══════════════ 止盈阈值提示 ═══════════════ #}
|
||
{% if active_round.positions|length > 0 %}
|
||
{% set latest = active_round.positions[-1] %}
|
||
<div style="background:var(--accent-light);border:1px solid var(--accent);border-radius:8px;padding:14px 18px;margin-bottom:24px;display:flex;align-items:center;gap:24px;flex-wrap:wrap;">
|
||
<div>
|
||
<span style="font-size:0.78rem;color:var(--sub);">止盈阈值</span>
|
||
<span style="font-weight:700;font-size:1.1rem;margin-left:8px;">{{ active_round.daily_hands }} × {{ latest.amp_threshold }} = {{ active_round.daily_hands * latest.amp_threshold }} 点</span>
|
||
</div>
|
||
<div>
|
||
<span style="font-size:0.78rem;color:var(--sub);">当前振幅 A</span>
|
||
<span style="font-weight:700;font-size:1.1rem;margin-left:8px;">{{ latest.amp_threshold }} 点</span>
|
||
</div>
|
||
<div>
|
||
<span style="font-size:0.78rem;color:var(--sub);">总手数</span>
|
||
<span style="font-weight:700;font-size:1.1rem;margin-left:8px;">{{ active_round.daily_hands * active_round.positions|length }}</span>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
{# ═══════════════ 添加仓位 ═══════════════ #}
|
||
<div class="section-title">添加当日仓位</div>
|
||
<div class="form-card" style="margin-bottom:28px;">
|
||
<form method="post" action="/positions/add" id="addForm">
|
||
<div style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;">
|
||
<div class="form-group" style="margin-bottom:0;flex:1;min-width:120px;">
|
||
<label>开仓价</label>
|
||
<input type="number" name="open_price" id="openPrice" required placeholder="如 1300" style="font-size:1rem;">
|
||
</div>
|
||
<div class="form-group" style="margin-bottom:0;flex:1;min-width:120px;">
|
||
<label>振幅阈值 A</label>
|
||
<input type="number" name="amp_threshold" id="ampThreshold" required placeholder="如 18" style="font-size:1rem;">
|
||
</div>
|
||
<div class="form-group" style="margin-bottom:0;flex:1;min-width:80px;">
|
||
<label>手数</label>
|
||
<input type="number" name="hands" value="1" min="1" max="10" required>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;align-items:center;min-width:100px;">
|
||
<span style="font-size:0.75rem;color:var(--sub);margin-bottom:4px;">锁仓价位</span>
|
||
<span id="lockPricePreview" style="font-size:1.3rem;font-weight:700;color:var(--danger-fg);">—</span>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary">添加仓位</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
{# ═══════════════ 仓位列表 ═══════════════ #}
|
||
<div class="section-title">本轮仓位</div>
|
||
|
||
{% if active_round.positions %}
|
||
<div class="table-wrap">
|
||
<table>
|
||
<tr>
|
||
<th>日期</th>
|
||
<th>开仓价</th>
|
||
<th>振幅 A</th>
|
||
<th>锁仓价位</th>
|
||
<th>手数</th>
|
||
<th>已锁</th>
|
||
<th>状态</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
{% for p in active_round.positions|reverse %}
|
||
<tr>
|
||
<td><strong>{{ p.opened_at }}</strong></td>
|
||
<td>{{ p.open_price }}</td>
|
||
<td>{{ p.amp_threshold }}</td>
|
||
<td style="color:var(--danger-fg);font-weight:600;">{{ p.lock_price }}</td>
|
||
<td>{{ p.hands }}</td>
|
||
<td>
|
||
{% if p.locked_count > 0 %}
|
||
<span class="badge badge-warn">{{ p.locked_count }}/{{ p.hands }}</span>
|
||
{% else %}
|
||
<span class="na">0/{{ p.hands }}</span>
|
||
{% endif %}
|
||
</td>
|
||
<td>
|
||
{% if p.locked_count >= p.hands %}
|
||
<span class="badge badge-down">已全锁</span>
|
||
{% elif p.locked_count > 0 %}
|
||
<span class="badge badge-warn">部分锁仓</span>
|
||
{% else %}
|
||
<span class="badge badge-up">活跃</span>
|
||
{% endif %}
|
||
</td>
|
||
<td>
|
||
<div style="display:flex;gap:8px;justify-content:center;">
|
||
<form method="post" action="/positions/{{ p.id }}/lock" style="display:inline;">
|
||
<button style="background:var(--warn-bg);color:var(--warn-fg);border:1px solid var(--warn);padding:3px 10px;border-radius:4px;cursor:pointer;font-size:0.78rem;font-weight:600;"
|
||
{% if p.locked_count >= p.hands %}disabled style="opacity:0.4;cursor:default;"{% endif %}>
|
||
🔒 锁
|
||
</button>
|
||
</form>
|
||
<form method="post" action="/positions/{{ p.id }}/unlock" style="display:inline;">
|
||
<button style="background:var(--surface);color:var(--sub);border:1px solid var(--border);padding:3px 10px;border-radius:4px;cursor:pointer;font-size:0.78rem;"
|
||
{% if p.locked_count == 0 %}disabled style="opacity:0.4;cursor:default;"{% endif %}>
|
||
撤销
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</table>
|
||
</div>
|
||
{% else %}
|
||
<div style="text-align:center;padding:40px;color:var(--sub);">暂无仓位,请添加当日仓位。</div>
|
||
{% endif %}
|
||
|
||
{# ═══════════════ 结束轮次 ═══════════════ #}
|
||
<div style="margin-top:28px;padding:20px;background:var(--surface);border:1px solid var(--border);border-radius:10px;display:flex;align-items:center;gap:16px;">
|
||
<span style="font-size:0.88rem;font-weight:600;">结束本轮:</span>
|
||
<form method="post" action="/positions/close" style="display:inline;">
|
||
<input type="hidden" name="result" value="profit_taken">
|
||
<button type="submit" class="btn" style="background:var(--success);color:#fff;" onclick="return confirm('确认止盈清仓?')">🟢 止盈</button>
|
||
</form>
|
||
<form method="post" action="/positions/close" style="display:inline;">
|
||
<input type="hidden" name="result" value="meltdown">
|
||
<button type="submit" class="btn" style="background:var(--danger);color:#fff;" onclick="return confirm('确认熔断清仓?')">🔴 熔断</button>
|
||
</form>
|
||
</div>
|
||
|
||
{% endif %}
|
||
|
||
<script>
|
||
var openPrice = document.getElementById('openPrice');
|
||
var ampThreshold = document.getElementById('ampThreshold');
|
||
var preview = document.getElementById('lockPricePreview');
|
||
function updatePreview() {
|
||
var op = parseInt(openPrice.value) || 0;
|
||
var at = parseInt(ampThreshold.value) || 0;
|
||
if (op > 0 && at > 0) {
|
||
preview.textContent = (op + at) + ' 点';
|
||
} else {
|
||
preview.textContent = '—';
|
||
}
|
||
}
|
||
if (openPrice && ampThreshold) {
|
||
openPrice.addEventListener('input', updatePreview);
|
||
ampThreshold.addEventListener('input', updatePreview);
|
||
}
|
||
</script>
|
||
{% endblock %}
|