Add key-level auto trade, AI analysis, and trading UX improvements.

Key monitors use 5m close triggers with WeChat alerts and box/convergence auto orders; add pending-order worker, structured WeChat notify, AI settings/messages, session clock, CTP margin sizing, and dual-layer position limits.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-28 10:36:56 +08:00
parent 0109b59f27
commit 840e88daad
33 changed files with 2514 additions and 143 deletions
+131 -2
View File
@@ -85,6 +85,42 @@
.settings-admin-row .settings-compact-card > form .btn-primary{padding:.42rem .7rem;font-size:.78rem}
.settings-admin-row .settings-password-form{grid-template-columns:1fr;gap:.45rem .55rem}
.settings-admin-row .settings-password-form input{padding:.4rem .55rem;font-size:.78rem}
.settings-ai-full{margin-bottom:1.25rem}
.settings-ai-full .settings-fold.card{min-height:auto;height:auto}
.settings-ai-usage{margin-bottom:1rem;font-size:.84rem;color:var(--text-muted)}
.settings-ai-usage summary{cursor:pointer;color:var(--accent);font-weight:600;margin-bottom:.4rem}
.settings-ai-usage-body ul{margin:.25rem 0 0 1.1rem;padding:0;line-height:1.55}
.settings-ai-usage-body li{margin:.2rem 0}
.settings-ai-form{max-width:none}
.settings-ai-form input[type="checkbox"]{width:auto;flex-shrink:0;margin:0}
.settings-ai-form label.check-inline{
display:inline-flex;align-items:center;gap:.45rem;width:auto;
cursor:pointer;margin-bottom:0;font-size:.85rem;color:var(--text-muted)
}
.settings-ai-cards-row{
display:grid;grid-template-columns:1fr 1fr;gap:.85rem;margin-bottom:.85rem
}
.settings-ai-card{
border:1px solid var(--border);border-radius:10px;
padding:.85rem 1rem;background:var(--card-inner)
}
.settings-ai-card.is-active{border-color:var(--accent);box-shadow:0 0 0 1px rgba(56,189,248,.25)}
.settings-ai-card-head{
display:flex;align-items:center;justify-content:space-between;gap:.5rem;
margin-bottom:.65rem;font-size:.92rem;font-weight:600;color:var(--text-title)
}
.settings-ai-card .field{margin-bottom:.55rem}
.settings-ai-card .field:last-child{margin-bottom:0}
.settings-ai-daily{
border:1px solid var(--border);border-radius:10px;
padding:.85rem 1rem;background:var(--card-inner);margin-bottom:.85rem
}
.settings-ai-daily-grid{display:grid;grid-template-columns:auto 1fr 1fr;gap:.65rem .75rem;align-items:end}
.settings-ai-daily-grid .check-inline{align-self:center}
@media (max-width:768px){
.settings-ai-cards-row{grid-template-columns:1fr}
.settings-ai-daily-grid{grid-template-columns:1fr}
}
.settings-page .settings-fold.card{padding:0;overflow:hidden}
.settings-page .split-grid .settings-fold.card{min-height:auto;height:auto}
.settings-fold-head{
@@ -180,6 +216,10 @@
<label>保证金占用上限(%</label>
<input name="max_margin_pct" type="number" step="1" min="1" max="100" value="{{ max_margin_pct }}">
</div>
<div class="field">
<label>滚仓保证金占用上限(%</label>
<input name="roll_max_margin_pct" type="number" step="1" min="1" max="100" value="{{ roll_max_margin_pct }}">
</div>
<div class="field">
<label>移动保本缓冲(最小变动价位倍数)</label>
<input name="trailing_be_tick_buffer" type="number" step="1" min="1" max="20" value="{{ trailing_be_tick_buffer }}">
@@ -191,8 +231,12 @@
</div>
<button type="submit" class="btn-primary" style="margin-top:.75rem">保存交易设置</button>
<p class="hint" style="margin-top:.75rem;margin-bottom:0">
保证金上限用于开仓校验与品种最大手数估算(默认 30%)。<strong>移动保本</strong>:达 1R 后止损移至开仓价 ± N 跳
<strong>挂单超时</strong>:限价开仓未成交时,超过设定分钟数自动向柜台撤单(1~60 分钟)。CTP 账号与前置在下方「CTP 连接」中配置
开仓保证金上限用于开仓校验与品种最大手数估算(默认 30%)。固定金额计仓时<strong>先按止损算手数,再按保证金上限收紧</strong>
滚仓保证金上限为滚仓后<strong>总持仓</strong>占用上限(默认 50%,可在下方修改)
<strong>移动保本</strong>:达 1R 后止损移至开仓价 ± N 跳。
<strong>挂单超时</strong>:限价开仓未成交时,超过设定分钟数自动向柜台撤单(1~60 分钟)。
<span class="text-muted">{{ small_account_margin_rec.label }}。</span>
CTP 账号与前置在下方「CTP 连接」中配置。
</p>
</form>
{% endcall %}
@@ -369,6 +413,91 @@
{% endcall %}
</div>
<div class="settings-ai-full">
{% call settings_card('ai', 'AI 分析 · 使用说明') %}
<details class="settings-ai-usage" open>
<summary>使用说明</summary>
<div class="settings-ai-usage-body">
<ul>
<li><strong>触发时机</strong>:开仓成交、平仓入账、日终报告(默认日盘 15:05,可在下方修改)</li>
<li><strong>Ollama</strong>:服务器需能访问填写的地址(如本机 <code>127.0.0.1:11434</code></li>
<li><strong>OpenAI 兼容</strong>:支持 DeepSeek、硅基流动等 OpenAI 格式 API</li>
<li><strong>输出位置</strong>:分析写入导航「AI 消息」;若已配置企业微信,日终报告会同步推送摘要</li>
<li><strong>不替代交易</strong>:AI 仅作复盘与风险提示,下单仍以系统规则与 CTP 为准</li>
</ul>
</div>
</details>
<form action="{{ url_for('settings') }}" method="post" class="settings-ai-form">
<input type="hidden" name="action" value="ai">
<div class="field" style="margin-bottom:.75rem">
<label class="check-inline">
<input type="checkbox" name="ai_enabled" value="1" {% if ai_enabled %}checked{% endif %}>
<span>启用 AI 分析</span>
</label>
</div>
<div class="field" style="margin-bottom:.85rem;max-width:280px">
<label>当前使用的提供商</label>
<select name="ai_provider" id="ai-provider-select">
<option value="ollama" {% if ai_provider == 'ollama' %}selected{% endif %}>本地 Ollama</option>
<option value="openai" {% if ai_provider == 'openai' %}selected{% endif %}>OpenAI 兼容 API</option>
</select>
</div>
<div class="settings-ai-cards-row">
<div class="settings-ai-card{% if ai_provider == 'ollama' %} is-active{% endif %}" data-ai-provider="ollama">
<div class="settings-ai-card-head">
<span>本地 Ollama</span>
{% if ai_provider == 'ollama' %}<span class="badge profit">当前</span>{% endif %}
</div>
<div class="field">
<label>接口地址</label>
<input name="ai_ollama_base_url" type="url" placeholder="http://127.0.0.1:11434" value="{{ ai_ollama_base_url }}">
</div>
<div class="field">
<label>模型名</label>
<input name="ai_ollama_model" type="text" placeholder="qwen2.5:7b" value="{{ ai_ollama_model }}">
</div>
</div>
<div class="settings-ai-card{% if ai_provider == 'openai' %} is-active{% endif %}" data-ai-provider="openai">
<div class="settings-ai-card-head">
<span>OpenAI 兼容</span>
{% if ai_provider == 'openai' %}<span class="badge profit">当前</span>{% endif %}
</div>
<div class="field">
<label>API Base URL</label>
<input name="ai_openai_base_url" type="url" placeholder="https://api.openai.com/v1" value="{{ ai_openai_base_url }}">
</div>
<div class="field">
<label>API Key</label>
<input name="ai_openai_api_key" type="password" placeholder="sk-..." value="{{ ai_openai_api_key }}" autocomplete="off">
</div>
<div class="field">
<label>模型名</label>
<input name="ai_openai_model" type="text" placeholder="gpt-4o-mini" value="{{ ai_openai_model }}">
</div>
</div>
</div>
<div class="settings-ai-daily">
<p class="hint" style="margin:0 0 .65rem">日终报告(国内期货日盘收盘后推送一次)</p>
<div class="settings-ai-daily-grid">
<label class="check-inline">
<input type="checkbox" name="ai_daily_report_enabled" value="1" {% if ai_daily_report_enabled %}checked{% endif %}>
<span>启用</span>
</label>
<div class="field" style="margin:0">
<label>报告时刻(时)</label>
<input name="ai_daily_report_hour" type="number" min="0" max="23" step="1" value="{{ ai_daily_report_hour }}">
</div>
<div class="field" style="margin:0">
<label>报告时刻(分)</label>
<input name="ai_daily_report_minute" type="number" min="0" max="59" step="1" value="{{ ai_daily_report_minute }}">
</div>
</div>
</div>
<button type="submit" class="btn-primary">保存 AI 配置</button>
</form>
{% endcall %}
</div>
<div class="split-grid settings-admin-row">
{% call settings_card('backup', '数据备份与恢复', 'settings-compact-card') %}
<p class="settings-backup-meta">