@@ -11,7 +11,6 @@
< 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;" >
@@ -35,102 +34,84 @@
< / form >
< / div >
{% if not active_rounds %}
< 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;" >
{% for round in active_rounds % }
{# ═══════════════ 轮次卡片 ═══════════════ #}
{% set locks = round.total_locks %}
< div style = "margin-bottom:32px;border:1px solid var(--border);border-radius:10px;overflow:hidden; " >
{# ── 轮次头部 ── #}
< div style = "display:flex;align-items:center;gap:16px;padding:14px 20px;background:var(--th-bg);flex-wrap:wrap;" >
< strong style = "font-size:1rem;" > {{ round.contract_code }}< / strong >
< span class = "badge badge-up" > {{ round.daily_hands }} 手/天< / span >
< span style = "font-size:0.82rem;color:var(--sub);" > 已开 {{ round.positions|length }} 天< / span >
< span style = "font-size:0.82rem;color:var(--sub);" > 开始 {{ round.started_at }}< / span >
< span style = "font-size:0.82rem;font-weight:600;{% if locks >= 3 %}color:var(--danger-fg);{% endif %}" >
锁仓 {{ locks }}/3
{% if locks >= 3 %} ⚠ 熔断{% endif %}
< / span >
< span style = "margin-left:auto;display:flex;gap:8px;" >
< form method = "post" action = "/positions/{{ round.id }}/close" style = "display:inline;" >
< input type = "hidden" name = "result" value = "profit_taken" >
< button class = "btn" style = "background:var(--success);color:#fff;font-size:0.78rem;padding:4px 14px;" onclick = "return confirm('确认 {{ round.contract_code }} 止盈清仓?')" > 止盈< / button >
< / form >
< form method = "post" action = "/positions/{{ round.id }}/close" style = "display:inline;" >
< input type = "hidden" name = "result" value = "meltdown" >
< button class = "btn" style = "background:var(--danger);color:#fff;font-size:0.78rem;padding:4px 14px;" onclick = "return confirm('确认 {{ round.contract_code }} 熔断清仓?')" > 熔断< / button >
< / form >
< / span >
< / div >
< div style = "padding:16px 20px;" >
{# ── 止盈阈值 ── #}
{% if round.positions %}
{% set latest = round.positions[-1] %}
< div style = "background:var(--accent-light);border:1px solid var(--accent);border-radius:6px;padding:10px 16px;margin-bottom:16px;display:flex;align-items:center;gap:20px;flex-wrap:wrap;" >
< span style = "font-size:0.78rem;color:var(--sub);" > 止盈阈值< / span >
< span style = "font-weight:700;" > {{ round.daily_hands }} × {{ latest.amp_threshold }} = {{ round.daily_hands * latest.amp_threshold }} 点< / span >
< span style = "color:var(--sub);" > |< / span >
< span style = "font-size:0.78rem;color:var(--sub);" > 当前 A = {{ latest.amp_threshold }}< / span >
< span style = "color:var(--sub);" > |< / span >
< span style = "font-size:0.78rem;color:var(--sub);" > 总手数 {{ round.daily_hands * round.positions|length }}< / span >
< / div >
{% endif %}
{# ── 添加仓位 ── #}
< div style = "margin-bottom:16px;" >
< form method = "post" action = "/positions/{{ round.id }}/add" >
< div style = "display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;" >
< div class = "form-group" style = "margin-bottom:0;flex:1;min-width:100px;" >
< label > 开仓价< / label >
< input type = "number" name = "open_price" id = "openPrice" required placeholder = "如 1300" style = "font-size:1 rem;" >
< input type = "number" name = "open_price" required placeholder = "如 1300" style = "font-size:0.9 rem;" >
< / div >
< div class = "form-group" style = "margin-bottom:0;flex:1;min-width:12 0px;" >
< label > 振幅阈值 A< / label >
< input type = "number" name = "amp_threshold" id = "ampThreshold" required placeholder = "如 18" style = "font-size:1 rem;" >
< div class = "form-group" style = "margin-bottom:0;flex:1;min-width:10 0px;" >
< label > 振幅 A< / label >
< input type = "number" name = "amp_threshold" required placeholder = "如 18" style = "font-size:0.9 rem;" >
< / div >
< div class = "form-group" style = "margin-bottom:0;flex:1;min-width:8 0px;" >
< div class = "form-group" style = "margin-bottom:0;flex:1;min-width:7 0px;" >
< label > 手数< / label >
< input type = "number" name = "hands" value = "1 " min = "1" max = "10" required >
< input type = "number" name = "hands" value = "{{ round.daily_hands }} " min = "1" max = "10" required style = "font-size:0.9rem;" >
< / 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 >
< button type = "submit" class = "btn btn-primary" style = "font-size:0.82rem;padding:8px 18px;" > + 添加 < / button >
< / div >
< / form >
< / div >
< / div >
{# ═══════════════ 仓位列表 ═══════════════ #}
< div class = "section-title" > 本轮仓位< / div >
{% if active_round.positions %}
< div class = "table-wrap" >
< table >
{# ── 仓位表格 ── #}
{% if round.positions %}
< div class = "table-wrap" style = "margin-bottom:0;" >
< table style = "font-size:0.84rem;" >
< tr >
< th > 日期< / th >
< th > 开仓价< / th >
< th > 振幅 A< / th >
< th > 锁仓价位< / th >
< th > 手数< / th >
< th > 已锁< / th >
< th > 状态< / th >
< th > 操作< / th >
< 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 %}
{% for p in round.positions|reverse %}
< tr >
< td > < strong > {{ p.opened_at }}< / strong > < / td >
< td > {{ p.open_price }}< / td >
@@ -148,66 +129,33 @@
{% if p.locked_count >= p.hands %}
< span class = "badge badge-down" > 已全锁< / span >
{% elif p.locked_count > 0 %}
< span class = "badge badge-warn" > 部分锁仓 < / span >
< span class = "badge badge-warn" > 部分锁< / span >
{% else %}
< span class = "badge badge-up" > 活跃< / span >
{% endif %}
< / td >
< td >
< div style = "display:flex;gap:8 px;justify-content:center;" >
< div style = "display:flex;gap:6 px;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:3 px 10 px;border-radius:4px;cursor:pointer;font-size:0.78 rem;font-weight:600;"
{ % if p . locked_count > = p.hands %}disabled style="opacity:0.4;cursor:default;"{% endif %}>
🔒 锁
< / button >
< button style = "background:var(--warn-bg);color:var(--warn-fg);border:1px solid var(--warn);padding:2 px 8 px;border-radius:4px;cursor:pointer;font-size:0.75 rem;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:3 px 10 px;border-radius:4px;cursor:pointer;font-size:0.78 rem;"
{ % if p . locked_count = = 0 % } disabled style = "opacity:0.4;cursor:default;" { % endif % } >
撤销
< / button >
< button style = "background:var(--surface);color:var(--sub);border:1px solid var(--border);padding:2 px 8 px;border-radius:4px;cursor:pointer;font-size:0.75 rem;"
{ % if p . locked_count = = 0 % } disabled style = "opacity:0.4;cursor:default;" { % endif % } > 撤 < / button >
< / form >
< / div >
< / td >
< / tr >
{% endfor %}
< / table >
< / table >
< / div >
{% else %}
< div style = "text-align:center;padding:24px;color:var(--sub);font-size:0.84rem;" > 暂无仓位,请添加。< / div >
{% endif %}
< / div >
< / div >
{% else %}
< div style = "text-align:center;padding:40px;color:var(--sub);" > 暂无仓位,请添加当日仓位。< / div >
{% endif %}
{% endfor %}
{# ═══════════════ 结束轮次 ═══════════════ #}
< 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 %}