完善下单表单与 CTP 持仓,requirements 加入 vnpy 并更新部署文档

以损定仓/固定张数分栏下单、限价市价、持仓仅读柜台;DEPLOY 补充 SimNow 与 vnpy 安装说明。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-24 10:52:25 +08:00
parent 709801305f
commit 62cd868f79
9 changed files with 394 additions and 308 deletions
+49 -33
View File
@@ -26,64 +26,80 @@
<div class="trade-order-status trade-order-status-compact">
<div class="status-row">
<span class="text-muted">计仓</span>
<strong>{{ sizing_mode_label }}</strong>
{% if sizing_mode == 'risk' %}<span class="text-muted">· {{ risk_percent }}%</span>{% endif %}
<span class="text-muted">· 监控 {{ monitor_count }} 笔</span>
<strong id="sizing-label">{{ sizing_mode_label }}</strong>
{% if sizing_mode == 'risk' %}<span class="text-muted">· 单笔风险 {{ risk_percent }}%</span>{% endif %}
</div>
</div>
<div class="trade-input-row">
<div class="symbol-wrap trade-field">
<div class="trade-form-grid">
<div class="symbol-wrap trade-field span-2">
<label class="text-label">品种</label>
<input type="text" id="trade-symbol" class="symbol-input" placeholder="主力合约 rb2610" autocomplete="off">
<div class="symbol-dropdown"></div>
<div class="symbol-selected" id="sym-selected"></div>
</div>
<div class="trade-field">
<label class="text-label">方向</label>
<select id="trade-direction">
<option value="long">做多</option>
<option value="short">做空</option>
</select>
</div>
<div class="trade-field" id="field-lots" {% if sizing_mode == 'risk' %}hidden{% endif %}>
<label class="text-label">手数</label>
<input type="number" id="trade-lots" min="1" step="1" value="1">
</div>
<div class="trade-field">
<label class="text-label">价格</label>
<div class="trade-field span-2">
<label class="text-label">入场价</label>
<div class="price-type-tabs">
<button type="button" class="price-tab active" data-type="limit">限价</button>
<button type="button" class="price-tab" data-type="market">市价</button>
</div>
<input type="number" id="trade-price" step="any" placeholder="限价">
<p class="hint market-hint" id="market-hint" hidden>市价将按最新行情价报单</p>
</div>
<div class="trade-field">
<label class="text-label">止损</label>
<input type="number" id="trade-sl" step="any">
</div>
<div class="trade-field">
<label class="text-label">止盈</label>
<input type="number" id="trade-tp" step="any">
</div>
<div class="trade-field" id="field-calc-lots" {% if sizing_mode != 'risk' %}hidden{% endif %}>
<label class="text-label">计算手数</label>
<div class="calc-lots-row">
<input type="text" id="trade-lots-calc" readonly placeholder="填写止损后计算">
<button type="button" class="btn-secondary" id="btn-calc-lots">计算</button>
</div>
</div>
</div>
<div id="risk-fields" class="trade-risk-row" {% if sizing_mode != 'risk' %}hidden{% endif %}>
<div class="trade-field"><label class="text-label">止损</label><input type="number" id="trade-sl" step="any"></div>
<div class="trade-field"><label class="text-label">止盈</label><input type="number" id="trade-tp" step="any"></div>
</div>
<div class="trade-btn-row">
<button type="button" class="trade-btn long" id="btn-open-long">
<span class="btn-price" id="px-long"></span>
<span class="btn-label">加多</span>
</button>
<button type="button" class="trade-btn lock" id="btn-open-short">
<span class="btn-price" id="px-short"></span>
<span class="btn-label">加空</span>
</button>
<button type="button" class="trade-btn close" id="btn-close-long">
<span class="btn-label">平多</span>
<span class="btn-sub" id="pos-long">≤0</span>
</button>
<button type="button" class="trade-btn close" id="btn-close-short">
<span class="btn-label">平空</span>
<span class="btn-sub" id="pos-short">≤0</span>
</button>
<div class="trade-action-row">
<button type="button" class="btn-primary btn-open" id="btn-open">开仓</button>
<button type="button" class="btn-secondary" id="btn-close-pos">平仓</button>
</div>
<div class="trade-footer" id="trade-footer">
<p class="hint">程序报单经 CTP 进入柜台;策略自动化请用 <a href="{{ url_for('strategy_page') }}">策略交易</a></p>
{% if ctp_status.last_error %}<p class="text-loss" style="font-size:.78rem;margin-top:.35rem">{{ ctp_status.last_error }}</p>{% endif %}
<p class="hint" id="trade-metrics-hint">填写品种后显示精度与每跳价值;策略自动化请用 <a href="{{ url_for('strategy_page') }}">策略交易</a></p>
{% if ctp_status.last_error %}
<p class="text-loss ctp-install-hint" style="font-size:.78rem;margin-top:.35rem">{{ ctp_status.last_error }}</p>
{% else %}
<p class="text-muted ctp-install-hint" style="font-size:.72rem;margin-top:.35rem">报单需安装 vnpy 并连接 CTP(SimNow 模拟盘)。</p>
{% endif %}
</div>
</div>
</div>
<div class="card trade-card" id="positions">
<h2>持仓监控</h2>
<p class="hint pos-hint">数据来自 CTP 柜台(交易所回报),浮盈等为柜台实际值。</p>
<div class="card-body card-scroll" id="position-live-list">
<div class="empty-hint">加载中…</div>
<div class="empty-hint">{% if ctp_status.connected %}加载中…{% else %}请先连接 CTP 查看柜台持仓{% endif %}</div>
</div>
</div>
</div>
@@ -107,7 +123,7 @@
<tr class="rec-{{ r.status }}">
<td><strong>{{ r.name }}</strong> <span class="text-muted">{{ r.ths }}</span></td>
<td>{{ r.exchange }}</td>
<td class="rec-price" data-ths="{{ r.ths }}">{% if r.price %}{{ r.price }}{% else %}—{% endif %}</td>
<td>{% if r.price %}{{ r.price }}{% else %}—{% endif %}</td>
<td>{% if r.margin_one_lot %}{{ r.margin_one_lot }}{% else %}—{% endif %}</td>
<td>{% if r.min_capital_one_lot %}{{ r.min_capital_one_lot }}{% else %}—{% endif %}</td>
<td><span class="badge {% if r.status=='ok' %}profit{% else %}planned{% endif %}">{{ r.status_label }}</span></td>