恢复下单界面并排布局,品种推荐数据库缓存与 SSE 推送。
期货下单与持仓监控左右并排,推荐按资金过滤存库,后台刷新并通过 EventSource 推送。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+82
-44
@@ -19,60 +19,81 @@
|
||||
</div>
|
||||
|
||||
<div class="trade-dashboard">
|
||||
<div class="card trade-card" id="order">
|
||||
<h2>期货下单</h2>
|
||||
<div class="card-body">
|
||||
<p class="hint">开仓、加仓由<strong>程序</strong>在「策略交易」中执行,经 CTP 自动报单至 SimNow / 期货公司柜台。</p>
|
||||
<div class="trade-order-status">
|
||||
<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 %}
|
||||
<div class="trade-row-split">
|
||||
<div class="card trade-card" id="order">
|
||||
<h2>期货下单</h2>
|
||||
<div class="card-body">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-row">
|
||||
<span class="text-muted">风控状态</span>
|
||||
<strong class="{% if risk_status.can_trade %}text-profit{% else %}text-loss{% endif %}">{{ risk_status.status_label }}</strong>
|
||||
|
||||
<div class="trade-input-row">
|
||||
<div class="symbol-wrap trade-field">
|
||||
<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>
|
||||
<input type="number" id="trade-lots" min="1" step="1" value="1">
|
||||
</div>
|
||||
<div class="trade-field">
|
||||
<label class="text-label">价格</label>
|
||||
<input type="number" id="trade-price" step="any" placeholder="限价">
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-row">
|
||||
<span class="text-muted">程序监控</span>
|
||||
<strong>{{ monitor_count }}</strong> 笔
|
||||
{% if roll_count %}<span class="text-muted">· 滚仓组 {{ roll_count }}</span>{% endif %}
|
||||
|
||||
<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>
|
||||
{% if active_trend %}
|
||||
<div class="status-row trend-active">
|
||||
<span class="text-muted">趋势回调</span>
|
||||
<strong>#{{ active_trend.id }} {{ active_trend.symbol }} {{ '多' if active_trend.direction=='long' else '空' }}</strong>
|
||||
<span class="text-muted">已开 {{ active_trend.lots_open or 0 }}/{{ active_trend.target_lots }} 手</span>
|
||||
|
||||
<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>
|
||||
|
||||
<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 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not ctp_status.connected %}
|
||||
<p class="hint text-accent" style="margin-top:.75rem">请先连接 CTP,程序报单才会进入柜台。</p>
|
||||
{% endif %}
|
||||
{% if ctp_status.last_error %}
|
||||
<p class="text-loss" style="font-size:.78rem;margin-top:.5rem">{{ ctp_status.last_error }}</p>
|
||||
{% endif %}
|
||||
<div class="trade-order-actions">
|
||||
<a href="{{ url_for('strategy_page') }}" class="btn-primary">前往策略交易</a>
|
||||
<a href="{{ url_for('strategy_records_page') }}" class="text-muted" style="font-size:.82rem">策略记录 →</a>
|
||||
</div>
|
||||
|
||||
<div class="card trade-card" id="positions">
|
||||
<h2>持仓监控</h2>
|
||||
<div class="card-body card-scroll" id="position-live-list">
|
||||
<div class="empty-hint">加载中…</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card trade-card" id="positions">
|
||||
<h2>持仓监控</h2>
|
||||
<div class="card-body card-scroll" id="position-live-list">
|
||||
<div class="empty-hint">加载中…</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card trade-card" id="recommend">
|
||||
<div class="card trade-card trade-card-full" id="recommend">
|
||||
<h2>品种推荐</h2>
|
||||
<div class="card-body">
|
||||
<p class="hint">按当前权益 <strong class="text-accent" id="rec-capital">{{ '%.2f'|format(capital) }}</strong> 元筛选;
|
||||
灰色为保证金不足,优先展示可开 1 手且风险规则较友好的品种。</p>
|
||||
<p class="hint">按权益 <strong class="text-accent" id="rec-capital">{{ '%.2f'|format(capital) }}</strong> 元筛选,仅显示可开 1 手的品种。
|
||||
{% if recommend_updated_at %}<span class="text-muted">更新 {{ recommend_updated_at }}</span>{% else %}<span class="text-muted" id="rec-updated">后台刷新中…</span>{% endif %}
|
||||
</p>
|
||||
<div class="trade-table-wrap">
|
||||
<table class="trade-table">
|
||||
<thead>
|
||||
@@ -81,7 +102,20 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="recommend-list">
|
||||
<tr><td colspan="6" class="empty-hint">品种推荐加载中…</td></tr>
|
||||
{% if recommend_rows %}
|
||||
{% for r in recommend_rows %}
|
||||
<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.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>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr><td colspan="6" class="empty-hint">等待后台推送推荐…</td></tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -91,5 +125,9 @@
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
window.TRADE_SIZING_MODE = {{ sizing_mode|tojson }};
|
||||
window.TRADE_RISK_PERCENT = {{ risk_percent }};
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/trade.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user