Files
qihuo/templates/records.html
T
2026-06-30 00:12:10 +08:00

559 lines
34 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{# Copyright (c) 2025-2026 马建军. All rights reserved. 专有软件,详见 LICENSE.zh-CN.txt #}
{% extends "base.html" %}
{% block title %}交易记录与复盘 - 国内期货 · 交易复盘系统{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/records.css') }}?v={{ asset_v }}">
{% endblock %}
{% block content %}
{% macro trade_detail_json(t) -%}
{{ {
"symbol": t.symbol_name or t.symbol,
"symbol_code": t.symbol,
"monitor_type": t.monitor_type,
"source": "柜台" if t.source == "ctp" else "本地",
"direction": "做多" if t.direction == "long" else "做空",
"entry_price": t.entry_price,
"close_price": t.close_price,
"stop_loss": t.stop_loss,
"take_profit": t.take_profit,
"lots": t.lots,
"margin": t.margin,
"margin_pct": t.margin_pct,
"holding_minutes": t.holding_minutes or 0,
"open_time": t.open_time,
"close_time": t.close_time,
"pnl": t.pnl,
"fee": t.fee,
"pnl_net": t.pnl_net,
"equity_after": t.equity_after,
"result": t.result,
"verified": t.verified,
"fill_review_url": url_for("fill_review_from_trade", tid=t.id),
"del_url": url_for("del_trade", tid=t.id)
} | tojson }}
{%- endmacro %}
{% macro trade_symbol_cell(t) %}
<div class="dash-symbol-cell">
<div class="dash-symbol-title">
{{ t.symbol_name or t.symbol }}
{% if t.symbol_exchange %}<span class="dash-symbol-ex text-muted">{{ t.symbol_exchange }}</span>{% endif %}
{% if t.symbol_is_main %}<span class="badge planned dash-main-badge">主力</span>{% endif %}
{% if t.symbol and (t.symbol_name or '')|lower != (t.symbol or '')|lower %}
<span class="text-accent">{{ t.symbol }}</span>
{% endif %}
</div>
</div>
{% endmacro %}
{% macro trade_pnl_cell(v) %}
{% if v is not none %}{% set n = v|float %}<span class="{% if n > 0 %}pnl-pos{% elif n < 0 %}pnl-neg{% endif %}">{{ ('+' if n > 0 else '') ~ ('%.2f'|format(n)) }} 元</span>{% else %}—{% endif %}
{% endmacro %}
{% macro trade_verify_form(t) %}
<form method="post" action="{{ url_for('update_trade', tid=t.id) }}" class="records-trade-verify-form">
<input type="hidden" name="symbol_name" value="{{ t.symbol_name or t.symbol }}">
<input type="hidden" name="monitor_type" value="{{ t.monitor_type }}">
<input type="hidden" name="direction" value="{{ t.direction }}">
<input type="hidden" name="entry_price" value="{{ t.entry_price }}">
<input type="hidden" name="stop_loss" value="{{ t.stop_loss }}">
<input type="hidden" name="take_profit" value="{{ t.take_profit }}">
<input type="hidden" name="close_price" value="{{ t.close_price or '' }}">
<input type="hidden" name="lots" value="{{ t.lots }}">
<input type="hidden" name="margin" value="{{ t.margin or '' }}">
<input type="hidden" name="holding_minutes" value="{{ t.holding_minutes or 0 }}">
<input type="hidden" name="open_time" value="{{ t.open_time or '' }}">
<input type="hidden" name="close_time" value="{{ t.close_time or '' }}">
<input type="hidden" name="pnl" value="{{ t.pnl or '' }}">
<input type="hidden" name="result" value="{{ t.result }}">
<button type="submit" class="btn-verify" {% if t.verified %}disabled{% endif %}>核对修改</button>
</form>
{% endmacro %}
{% macro trade_row_actions(t, detail_class) %}
<div class="trade-actions records-trade-row-actions">
<button type="button" class="btn-link {{ detail_class }}">详情</button>
<a href="{{ url_for('fill_review_from_trade', tid=t.id) }}" class="btn-fill">填入复盘</a>
{{ trade_verify_form(t) }}
<a href="{{ url_for('del_trade', tid=t.id) }}" class="btn-del" onclick="return confirm('删除?')">删除</a>
</div>
{% endmacro %}
<div class="records-page">
<div class="card records-equity-card" style="margin-bottom:1.25rem">
<h2>资金曲线</h2>
<div class="card-body">
<div id="equity-curve-chart" style="width:100%;min-height:220px;overflow:hidden"></div>
</div>
</div>
<div class="card records-trade-card" style="margin-bottom:1.25rem">
<h2>交易记录</h2>
<div class="card-body">
{% if ctp_sync_info and ctp_sync_info.connected %}
<p class="hint" style="margin-top:0">
已连接 CTP,本页已自动同步柜台成交(新增 {{ ctp_sync_info.synced or 0 }} 条,更新 {{ ctp_sync_info.updated or 0 }} 条)。
带来源「柜台」的记录以交易所成交为准;「本地」为程序写入,可手动删除错误项。
</p>
{% else %}
<p class="hint" style="margin-top:0">CTP 未连接时仅显示本地数据库记录;连接后打开本页会自动同步柜台成交。</p>
{% endif %}
<label class="trade-switch-label records-desktop-only">
<input type="checkbox" id="trade-edit-switch">
<span>修改/核对开关(开启后可编辑关键字段)</span>
</label>
<div class="records-mobile-list records-phone-only" id="records-trade-mobile">
{% for t in trades %}
{% set trade_pnl = t.pnl_net if t.pnl_net is not none else t.pnl %}
{% set trade_px = t.close_price if t.close_price else t.entry_price %}
{% set pnl_cls = 'is-profit' if trade_pnl and trade_pnl > 0 else ('is-loss' if trade_pnl and trade_pnl < 0 else 'is-flat') %}
<div class="records-trade-row" data-trade-id="{{ t.id }}" data-trade='{{ trade_detail_json(t)|trim }}'>
<div class="records-trade-main">
<div class="records-trade-head">
<span class="records-trade-title">
<span class="records-mobile-symbol">{{ t.symbol_name or t.symbol }}</span>
{% if t.symbol and (t.symbol_name or '')|lower != (t.symbol or '')|lower %}
<span class="text-accent records-trade-code">{{ t.symbol }}</span>
{% endif %}
<span class="badge dir">{{ '做多' if t.direction == 'long' else '做空' }}</span>
{% if t.verified %}<span class="badge active records-verified-badge">已核对</span>{% endif %}
</span>
</div>
<div class="records-trade-summary">
{{ (t.lots or 0)|int }}手 平仓 {{ trade_px if trade_px is not none else '-' }}
盈亏 <span class="records-mobile-pnl {{ pnl_cls }}">{{ trade_pnl if trade_pnl is not none else '-' }}</span>
</div>
</div>
<div class="records-trade-phone-foot">
<span class="records-mobile-chevron">详情 </span>
</div>
</div>
{% else %}
<p class="records-mobile-empty">暂无交易记录</p>
{% endfor %}
</div>
<div class="card-scroll records-trade-table-wrap records-tablet-only">
<table class="dashboard-table records-trade-table">
<thead>
<tr>
<th>品种</th>
<th>方向</th>
<th>手数</th>
<th>开仓</th>
<th>平仓</th>
<th>盈亏</th>
<th>净盈亏</th>
<th>平仓时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for t in trades %}
<tr data-trade-id="{{ t.id }}" data-trade='{{ trade_detail_json(t)|trim }}'>
<td>{{ trade_symbol_cell(t) }}</td>
<td>
<span class="badge dir {% if t.direction == 'long' %}dir-long{% else %}dir-short{% endif %}">
{{ '做多' if t.direction == 'long' else '做空' }}
</span>
</td>
<td>{% if t.lots is not none %}{{ '%.2f'|format(t.lots|float) }}{% else %}—{% endif %}</td>
<td>{% if t.entry_price is not none %}{{ '%.2f'|format(t.entry_price|float) }}{% else %}—{% endif %}</td>
<td>{% if t.close_price is not none %}{{ '%.2f'|format(t.close_price|float) }}{% elif t.entry_price is not none %}{{ '%.2f'|format(t.entry_price|float) }}{% else %}—{% endif %}</td>
<td>{{ trade_pnl_cell(t.pnl) }}</td>
<td>{{ trade_pnl_cell(t.pnl_net) }}</td>
<td>{{ (t.close_time or '')[:16].replace('T', ' ') or '—' }}</td>
<td>{{ trade_row_actions(t, 'records-tablet-detail-btn') }}</td>
</tr>
{% else %}
<tr><td colspan="9" class="text-muted">暂无交易记录</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="trade-table-wrap records-desktop-only">
<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><th>结果</th><th>操作</th>
</tr>
</thead>
<tbody>
{% for t in trades %}
<tr data-trade-id="{{ t.id }}">
<td><span class="cell-readonly">{{ t.symbol_name or t.symbol }}</span></td>
<td>
<span class="cell-readonly cell-edit-hide">{{ t.monitor_type }}</span>
{% if t.source == 'ctp' %}
<span class="badge" style="margin-left:.25rem;font-size:.65rem">柜台</span>
{% else %}
<span class="text-muted" style="margin-left:.25rem;font-size:.65rem">本地</span>
{% endif %}
<input class="cell-edit-show" type="hidden" name="monitor_type" value="{{ t.monitor_type }}">
</td>
<td>
<span class="cell-readonly cell-edit-hide">
<span class="badge dir">{{ '做多' if t.direction == 'long' else '做空' }}</span>
</span>
<select class="cell-edit-show" name="direction" style="display:none">
<option value="long" {% if t.direction=='long' %}selected{% endif %}>做多</option>
<option value="short" {% if t.direction=='short' %}selected{% endif %}>做空</option>
</select>
</td>
<td>
<span class="cell-readonly cell-edit-hide">{{ t.entry_price }}</span>
<input class="cell-edit-show" type="number" step="0.0001" name="entry_price" value="{{ t.entry_price }}" style="display:none">
</td>
<td>
<span class="cell-readonly cell-edit-hide">{{ t.stop_loss }}</span>
<input class="cell-edit-show" type="number" step="0.0001" name="stop_loss" value="{{ t.stop_loss }}" style="display:none">
</td>
<td>
<span class="cell-readonly cell-edit-hide">{{ t.take_profit }}</span>
<input class="cell-edit-show" type="number" step="0.0001" name="take_profit" value="{{ t.take_profit }}" style="display:none">
</td>
<td>
<span class="cell-readonly cell-edit-hide">{{ t.lots }}</span>
<input class="cell-edit-show" type="number" step="0.01" name="lots" value="{{ t.lots }}" style="display:none">
</td>
<td>
<span class="cell-readonly cell-edit-hide">{{ t.margin if t.margin is not none else '-' }}</span>
<input class="cell-edit-show" type="number" step="0.01" name="margin" value="{{ t.margin or '' }}" placeholder="保证金" style="display:none">
</td>
<td>
<span class="cell-readonly cell-edit-hide">
{% if t.margin_pct is not none %}{{ t.margin_pct }}%{% else %}-{% endif %}
</span>
</td>
<td>
<span class="cell-readonly cell-edit-hide">{{ t.holding_minutes or 0 }}</span>
<input class="cell-edit-show" type="number" name="holding_minutes" value="{{ t.holding_minutes or 0 }}" style="display:none">
</td>
<td>
<span class="cell-readonly cell-edit-hide">{{ (t.open_time or '')[:16].replace('T',' ') }}</span>
<input class="cell-edit-show" type="text" name="open_time" value="{{ t.open_time or '' }}" style="display:none">
</td>
<td>
<span class="cell-readonly cell-edit-hide">{{ (t.close_time or '')[:16].replace('T',' ') }}</span>
<input class="cell-edit-show" type="text" name="close_time" value="{{ t.close_time or '' }}" style="display:none">
</td>
<td>
<span class="cell-readonly cell-edit-hide {% if t.pnl and t.pnl > 0 %}text-profit{% elif t.pnl and t.pnl < 0 %}text-loss{% endif %}">
{{ t.pnl if t.pnl is not none else '-' }}
</span>
<input class="cell-edit-show" type="number" step="0.01" name="pnl" value="{{ t.pnl or '' }}" style="display:none">
<input type="hidden" name="close_price" value="{{ t.close_price or '' }}">
<input type="hidden" name="symbol_name" value="{{ t.symbol_name or t.symbol }}">
</td>
<td><span class="cell-readonly text-muted">{{ t.fee if t.fee is not none else '-' }}</span></td>
<td>
<span class="cell-readonly {% if t.pnl_net and t.pnl_net > 0 %}text-profit{% elif t.pnl_net and t.pnl_net < 0 %}text-loss{% endif %}">
{{ t.pnl_net if t.pnl_net is not none else '-' }}
</span>
</td>
<td>
<span class="cell-readonly">{{ t.equity_after if t.equity_after is not none else '-' }}</span>
</td>
<td>
<span class="cell-readonly cell-edit-hide">
{% if t.result == '止盈' %}<span class="badge profit">{{ t.result }}</span>
{% elif t.result == '止损' %}<span class="badge loss">{{ t.result }}</span>
{% elif t.result == '移动止盈' %}<span class="badge profit">{{ t.result }}</span>
{% elif t.result == '保本止盈' %}<span class="badge profit">{{ t.result }}</span>
{% elif t.result == '手动平仓' %}<span class="badge result-manual">{{ t.result }}</span>
{% else %}<span class="badge result-external">{{ t.result }}</span>{% endif %}
{% if t.verified %}<span class="badge active" style="margin-left:.25rem">已核对</span>{% endif %}
</span>
<select class="cell-edit-show" name="result" style="display:none">
<option value="手动平仓" {% if t.result=='手动平仓' %}selected{% endif %}>手动平仓</option>
<option value="止盈" {% if t.result=='止盈' %}selected{% endif %}>止盈</option>
<option value="止损" {% if t.result=='止损' %}selected{% endif %}>止损</option>
<option value="移动止盈" {% if t.result=='移动止盈' %}selected{% endif %}>移动止盈</option>
<option value="保本止盈" {% if t.result=='保本止盈' %}selected{% endif %}>保本止盈</option>
</select>
</td>
<td>
<div class="trade-actions">
<a href="{{ url_for('fill_review_from_trade', tid=t.id) }}" class="btn-fill">填入复盘</a>
<button type="button" class="btn-verify trade-save-btn" disabled>核对修改</button>
<a href="{{ url_for('del_trade', tid=t.id) }}" class="btn-del" onclick="return confirm('删除?')">删除</a>
</div>
</td>
</tr>
{% else %}
<tr><td colspan="18" class="text-muted">暂无交易记录</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="split-grid records-split">
<div class="card" id="review-panel">
<h2>复盘上传</h2>
<div class="card-body">
<form id="review-form" action="{{ url_for('add_review') }}" method="post" enctype="multipart/form-data" class="form-compact form-compact-review line-tight">
<div class="form-line line-4">
<div class="symbol-wrap">
<input type="text" class="symbol-input" placeholder="品种" autocomplete="off" required>
<input type="hidden" name="symbol" required>
<input type="hidden" name="symbol_name">
<input type="hidden" name="market_code" required>
<input type="hidden" name="sina_code">
<div class="symbol-dropdown"></div>
<div class="symbol-selected"></div>
</div>
<select name="direction" required>
<option value="">方向</option>
<option value="long">做多</option>
<option value="short">做空</option>
</select>
<input name="lots" type="number" step="1" min="1" value="1" placeholder="张数" required>
<input name="timeframe" value="5m" placeholder="周期">
</div>
<div class="form-line line-4">
<input name="entry_price" type="number" step="0.0001" placeholder="成交价" required>
<input name="stop_loss" type="number" step="0.0001" placeholder="止损" required>
<input name="take_profit" type="number" step="0.0001" placeholder="止盈" required>
<input name="close_price" type="number" step="0.0001" placeholder="平仓价" required>
</div>
<div class="form-line line-4">
<div class="mini-field"><span>开仓时间</span><input type="datetime-local" name="open_time" required></div>
<div class="mini-field"><span>平仓时间</span><input type="datetime-local" name="close_time" required></div>
<input id="holding_duration" type="text" readonly class="calc-readonly" placeholder="持仓时长(自动)">
<input name="pnl" type="number" step="0.01" placeholder="盈亏金额(手动)">
</div>
<div class="form-line line-2">
<input id="initial_rr" type="text" readonly class="calc-readonly" placeholder="初始盈亏比(自动)">
<input id="actual_rr" type="text" readonly class="calc-readonly" placeholder="实际盈亏比(自动)">
</div>
<div class="form-line line-4">
<select name="open_type" required>
<option value="">开仓类型</option>
{% for t in open_types %}<option value="{{ t }}">{{ t }}</option>{% endfor %}
</select>
<select name="exit_trigger" required>
<option value="">离场触发</option>
{% for t in exit_triggers %}<option value="{{ t }}">{{ t }}</option>{% endfor %}
</select>
<input name="exit_supplement" placeholder="离场补充">
<select name="watch_after_breakeven" title="保本后盯盘">
<option value="否">保本盯盘:否</option>
<option value="是">保本盯盘:是</option>
</select>
</div>
<div class="form-line line-4">
<select name="new_position_while_occupied" title="占用时新开仓">
<option value="否">占用新开:否</option>
<option value="是">占用新开:是</option>
</select>
<input type="file" name="screenshot" accept="image/*" title="截图上传">
<textarea name="notes" placeholder="备注" rows="1"></textarea>
<button type="submit" class="btn-primary">保存</button>
</div>
<div class="kline-row">
<label><input type="checkbox" name="auto_kline" value="1" checked> 自动K线</label>
<select name="kline_period1" title="周期1">{% for p in kline_periods %}<option value="{{ p }}" {% if p=='15m' %}selected{% endif %}>{{ p }}</option>{% endfor %}</select>
<select name="kline_period2" title="周期2">{% for p in kline_periods %}<option value="{{ p }}" {% if p=='1h' %}selected{% endif %}>{{ p }}</option>{% endfor %}</select>
<input name="kline_count" type="number" value="300" placeholder="K线数" title="K线数">
<select name="kline_cutoff" title="K线截止">{% for c in kline_cutoffs %}<option value="{{ c }}">{{ c }}</option>{% endfor %}</select>
</div>
<p class="section-hint">勾选行为标签即为情绪单</p>
<div class="tag-grid">
{% for tag in behavior_tags %}
<label><input type="checkbox" name="tag_{{ tag }}" value="1"> {{ tag }}</label>
{% endfor %}
</div>
</form>
</div>
</div>
<div class="card">
<h2>复盘历史</h2>
<div class="card-body">
<div class="preset-tabs">
<a href="{{ url_for('records', preset='today') }}" class="{% if preset=='today' %}active{% endif %}">本日</a>
<a href="{{ url_for('records', preset='week') }}" class="{% if preset=='week' %}active{% endif %}">本周</a>
<a href="{{ url_for('records', preset='month') }}" class="{% if preset=='month' %}active{% endif %}">本月</a>
<a href="{{ url_for('records', preset='custom') }}" class="{% if preset=='custom' %}active{% endif %}">自定义</a>
</div>
{% if preset == 'custom' or start or end %}
<form method="get" class="filter-row">
<input type="hidden" name="preset" value="custom">
<div class="field"><label>开始</label><input type="date" name="start" value="{{ start }}"></div>
<div class="field"><label>结束</label><input type="date" name="end" value="{{ end }}"></div>
<button type="submit" class="btn-primary">筛选</button>
</form>
{% endif %}
<div class="records-mobile-list records-review-mobile">
{% for r in reviews %}
<button type="button" class="records-mobile-item review-view-btn{% if r.is_emotion %} is-emotion{% endif %}" data-review='{{ {
"symbol": r.symbol_name or r.symbol, "symbol_code": r.symbol,
"direction": "做多" if r.direction=="long" else "做空",
"lots": r.lots, "timeframe": r.timeframe,
"entry_price": r.entry_price, "stop_loss": r.stop_loss, "take_profit": r.take_profit,
"close_price": r.close_price,
"open_time": r.open_time, "close_time": r.close_time,
"holding_duration": r.holding_duration,
"initial_pnl": r.initial_pnl, "actual_pnl": r.actual_pnl, "pnl": r.pnl,
"fee": r.fee, "pnl_net": r.pnl_net,
"open_type": r.open_type,
"exit_trigger": r.exit_trigger, "exit_supplement": r.exit_supplement,
"watch_after_breakeven": r.watch_after_breakeven,
"new_position_while_occupied": r.new_position_while_occupied,
"is_emotion": r.is_emotion, "behavior_tags": r.behavior_tags,
"notes": r.notes, "screenshot": r.screenshot
} | tojson }}'>
<div class="records-mobile-item-head">
<span class="records-mobile-symbol">{{ r.symbol_name or r.symbol }}</span>
<span class="badge dir">{{ '多' if r.direction == 'long' else '空' }}</span>
</div>
<div class="records-mobile-item-meta">
<span>{{ r.close_time[:16].replace('T', ' ') if r.close_time else '' }}</span>
{% if r.is_emotion %}<span class="badge emotion">情绪单</span>{% endif %}
</div>
<div class="records-mobile-item-foot">
<span class="records-mobile-pnl {{ 'is-profit' if r.pnl_net and r.pnl_net > 0 else ('is-loss' if r.pnl_net and r.pnl_net < 0 else 'is-flat') }}">
<span class="records-mobile-pnl-lbl">净盈亏 </span>{{ r.pnl_net if r.pnl_net is not none else '-' }}
</span>
<span class="records-mobile-chevron">详情 </span>
</div>
</button>
{% else %}
<p class="records-mobile-empty">暂无复盘记录</p>
{% endfor %}
</div>
<div class="card-scroll records-desktop-only">
<table>
<thead>
<tr>
<th>平仓</th><th>品种</th><th>方向</th><th>盈亏</th><th>手续费</th><th>净盈亏</th><th>情绪单</th><th>详情</th><th></th>
</tr>
</thead>
<tbody>
{% for r in reviews %}
<tr class="{% if r.is_emotion %}row-emotion{% endif %}">
<td>{{ r.close_time[:16] if r.close_time else '' }}</td>
<td>{{ r.symbol_name or r.symbol }}</td>
<td><span class="badge dir">{{ '多' if r.direction == 'long' else '空' }}</span></td>
<td>
{% if r.pnl and r.pnl > 0 %}<span class="badge profit">{{ r.pnl }}</span>
{% elif r.pnl and r.pnl < 0 %}<span class="badge loss">{{ r.pnl }}</span>
{% else %}{{ r.actual_pnl or '-' }}{% endif %}
</td>
<td class="text-muted">{{ r.fee if r.fee is not none else '-' }}</td>
<td>
{% if r.pnl_net and r.pnl_net > 0 %}<span class="badge profit">{{ r.pnl_net }}</span>
{% elif r.pnl_net and r.pnl_net < 0 %}<span class="badge loss">{{ r.pnl_net }}</span>
{% else %}-{% endif %}
</td>
<td>{% if r.is_emotion %}<span class="badge emotion">情绪单</span>{% else %}-{% endif %}</td>
<td>
<button type="button" class="btn-link review-view-btn" data-review='{{ {
"symbol": r.symbol_name or r.symbol, "symbol_code": r.symbol,
"direction": "做多" if r.direction=="long" else "做空",
"lots": r.lots, "timeframe": r.timeframe,
"entry_price": r.entry_price, "stop_loss": r.stop_loss, "take_profit": r.take_profit,
"close_price": r.close_price,
"open_time": r.open_time, "close_time": r.close_time,
"holding_duration": r.holding_duration,
"initial_pnl": r.initial_pnl, "actual_pnl": r.actual_pnl, "pnl": r.pnl,
"fee": r.fee, "pnl_net": r.pnl_net,
"open_type": r.open_type,
"exit_trigger": r.exit_trigger, "exit_supplement": r.exit_supplement,
"watch_after_breakeven": r.watch_after_breakeven,
"new_position_while_occupied": r.new_position_while_occupied,
"is_emotion": r.is_emotion, "behavior_tags": r.behavior_tags,
"notes": r.notes, "screenshot": r.screenshot
} | tojson }}'>放大查看</button>
</td>
<td><a href="{{ url_for('del_review', rid=r.id) }}" class="btn-del" onclick="return confirm('删除?')"></a></td>
</tr>
{% else %}
<tr><td colspan="9" class="text-muted">暂无复盘记录</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<div id="review-modal" class="modal-mask">
<div class="modal-box review-modal-fullscreen">
<span class="modal-close"></span>
<h3>复盘详情</h3>
<div id="review-modal-body" class="review-modal-body"></div>
</div>
</div>
<div id="trade-detail-modal" class="modal-mask">
<div class="modal-box review-modal-fullscreen">
<span class="modal-close"></span>
<h3>交易详情</h3>
<div id="trade-detail-modal-body" class="review-modal-body"></div>
</div>
</div>
{% if auto_records %}
<div class="card" style="margin-top:1rem">
<h2>系统自动记录(止盈/止损)</h2>
<table>
<thead><tr><th>品种</th><th>类型</th><th>方向</th><th>触发价</th><th>结果</th><th>时间</th></tr></thead>
<tbody>
{% for r in auto_records %}
<tr>
<td>{{ r.symbol_name or r.symbol }}</td>
<td>{{ r.monitor_type }}</td>
<td><span class="badge dir">{{ '多' if r.direction == 'long' else '空' }}</span></td>
<td>{{ r.trigger_price }}</td>
<td>{% if r.result == '止盈' %}<span class="badge profit">止盈</span>{% else %}<span class="badge loss">止损</span>{% endif %}</td>
<td>{{ r.created_at[:16] if r.created_at else '' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</div>
{% endblock %}
{% block extra_js %}
<script src="https://unpkg.com/lightweight-charts@4.2.0/dist/lightweight-charts.standalone.production.js"></script>
<script>window.__EQUITY_CURVE__ = {{ equity_curve | default([]) | tojson }};</script>
<script src="{{ url_for('static', filename='js/equity_curve.js') }}"></script>
<script src="{{ url_for('static', filename='js/review.js') }}?v={{ asset_v }}"></script>
<script src="{{ url_for('static', filename='js/records.js') }}?v={{ asset_v }}"></script>
<script src="{{ url_for('static', filename='js/trades.js') }}?v={{ asset_v }}"></script>
{% if prefill %}
<script>
function bootReviewPrefill() {
var form = document.getElementById('review-form');
var panel = document.getElementById('review-panel');
if (!form) return;
var map = {{ prefill | tojson }};
Object.keys(map).forEach(function (k) {
var el = form.querySelector('[name="' + k + '"]');
if (el && map[k] != null && map[k] !== '') el.value = map[k];
});
var symInput = form.querySelector('.symbol-input');
if (symInput && map.symbol_name) symInput.value = map.symbol_name;
if (typeof recalc === 'function') recalc();
if (panel) panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
if (window.qihuoOnPageLoad) window.qihuoOnPageLoad(bootReviewPrefill);
else document.addEventListener('DOMContentLoaded', bootReviewPrefill);
</script>
{% endif %}
<script>
(function () {
function scrollReviewPanel() {
if (window.location.hash === '#review-panel') {
var panel = document.getElementById('review-panel');
if (panel) panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
if (window.qihuoOnPageLoad) window.qihuoOnPageLoad(scrollReviewPanel);
else document.addEventListener('DOMContentLoaded', scrollReviewPanel);
})();
</script>
{% endblock %}