Improve key monitor form with bar period, box direction, and labeled fields.
Match order-monitor layout; persist bar_period and enforce upper-direction filter for box breakouts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -305,6 +305,7 @@ def init_db():
|
||||
"ALTER TABLE key_monitors ADD COLUMN alert_break_side TEXT",
|
||||
"ALTER TABLE key_monitors ADD COLUMN breakout_bar_time TEXT",
|
||||
"ALTER TABLE key_monitors ADD COLUMN alert_close_price REAL",
|
||||
"ALTER TABLE key_monitors ADD COLUMN bar_period TEXT DEFAULT '5m'",
|
||||
"ALTER TABLE review_records ADD COLUMN direction TEXT",
|
||||
"ALTER TABLE review_records ADD COLUMN entry_price REAL",
|
||||
"ALTER TABLE review_records ADD COLUMN stop_loss REAL",
|
||||
@@ -1057,6 +1058,8 @@ def ai_messages_page():
|
||||
@app.route("/keys")
|
||||
@login_required
|
||||
def keys():
|
||||
from key_monitor_lib import key_monitor_periods
|
||||
|
||||
conn = get_db()
|
||||
key_list = conn.execute(
|
||||
"SELECT * FROM key_monitors WHERE status='active' OR status IS NULL ORDER BY id DESC"
|
||||
@@ -1065,7 +1068,12 @@ def keys():
|
||||
"SELECT * FROM key_monitors WHERE status='archived' ORDER BY archived_at DESC LIMIT 100"
|
||||
).fetchall()
|
||||
conn.close()
|
||||
return render_template("keys.html", keys=key_list, history=history)
|
||||
return render_template(
|
||||
"keys.html",
|
||||
keys=key_list,
|
||||
history=history,
|
||||
key_periods=key_monitor_periods(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1103,21 +1111,26 @@ def add_key():
|
||||
if trailing_be and risk_reward < 3:
|
||||
risk_reward = 3.0
|
||||
|
||||
from key_monitor_lib import normalize_bar_period
|
||||
|
||||
bar_period = normalize_bar_period(d.get("bar_period") or "5m")
|
||||
direction = (d.get("direction") or "").strip().lower()
|
||||
if monitor_type in ("箱体突破", "收敛突破"):
|
||||
direction = direction or "long"
|
||||
if monitor_type == "箱体突破":
|
||||
if direction not in ("long", "short"):
|
||||
flash("箱体突破须选择上方向(做多/做空)")
|
||||
return redirect(url_for("keys"))
|
||||
else:
|
||||
direction = direction or "long"
|
||||
direction = ""
|
||||
|
||||
conn = get_db()
|
||||
conn.execute(
|
||||
"""INSERT INTO key_monitors
|
||||
(symbol, symbol_name, market_code, sina_code, monitor_type, direction,
|
||||
upper, lower, trade_mode, risk_reward, trailing_be)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
upper, lower, trade_mode, risk_reward, trailing_be, bar_period)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
(
|
||||
symbol, symbol_name, market_code, sina_code, monitor_type, direction,
|
||||
upper, lower, trade_mode, risk_reward, trailing_be,
|
||||
upper, lower, trade_mode, risk_reward, trailing_be, bar_period,
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
@@ -2933,6 +2933,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
def _execute_key_breakout(conn, row, bar, break_side):
|
||||
"""关键位箱体/收敛:5m 收盘突破后自动市价开仓。"""
|
||||
from key_monitor_lib import (
|
||||
TYPE_BOX,
|
||||
calc_breakout_sl_tp,
|
||||
format_auto_breakout_msg,
|
||||
normalize_monitor_type,
|
||||
@@ -2966,6 +2967,13 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
detail=detail,
|
||||
))
|
||||
|
||||
if monitor_type == TYPE_BOX:
|
||||
cfg_dir = (row.get("direction") or "").strip().lower()
|
||||
if cfg_dir in ("long", "short") and direction != cfg_dir:
|
||||
dir_cn = "做多" if cfg_dir == "long" else "做空"
|
||||
_notify(False, f"突破方向与上方向({dir_cn})不一致", entry=0, sl=0, tp=0, lots=0)
|
||||
return False, "突破方向与上方向不一致"
|
||||
|
||||
try:
|
||||
init_strategy_tables(conn)
|
||||
mode = get_trading_mode(get_setting)
|
||||
|
||||
+49
-10
@@ -27,8 +27,38 @@ ZONE_TYPES = (TYPE_ZONE, "关键阻力位", "关键支撑位")
|
||||
ALERT_MAX_PUSH = 3
|
||||
ALERT_INTERVAL_SEC = 300
|
||||
SL_TICK_BUFFER = 2
|
||||
BAR_PERIOD = "5m"
|
||||
BAR_MINUTES = 5
|
||||
DEFAULT_BAR_PERIOD = "5m"
|
||||
|
||||
PERIOD_MINUTES_MAP = {
|
||||
"1m": 1, "2m": 2, "3m": 3, "5m": 5, "15m": 15, "30m": 30,
|
||||
"1h": 60, "2h": 120, "4h": 240, "d": 1440, "1d": 1440,
|
||||
}
|
||||
|
||||
|
||||
def key_monitor_periods() -> list[dict[str, str]]:
|
||||
"""关键位监控可选 K 线周期(触发用)。"""
|
||||
from kline_chart import MARKET_PERIODS
|
||||
|
||||
allowed = frozenset({"5m", "15m", "30m", "1h", "2h", "4h", "d"})
|
||||
return [p for p in MARKET_PERIODS if p["key"] in allowed]
|
||||
|
||||
|
||||
def normalize_bar_period(raw: str) -> str:
|
||||
valid = {p["key"] for p in key_monitor_periods()}
|
||||
k = (raw or DEFAULT_BAR_PERIOD).strip()
|
||||
return k if k in valid else DEFAULT_BAR_PERIOD
|
||||
|
||||
|
||||
def bar_period_label(key: str) -> str:
|
||||
k = normalize_bar_period(key)
|
||||
for p in key_monitor_periods():
|
||||
if p["key"] == k:
|
||||
return p["label"]
|
||||
return k
|
||||
|
||||
|
||||
def bar_period_minutes(period: str) -> int:
|
||||
return PERIOD_MINUTES_MAP.get(normalize_bar_period(period), 5)
|
||||
|
||||
|
||||
def normalize_monitor_type(raw: str) -> str:
|
||||
@@ -95,14 +125,19 @@ def _parse_bar_time(raw: str) -> Optional[datetime]:
|
||||
return None
|
||||
|
||||
|
||||
def last_closed_bar(bars: list[dict], now: Optional[datetime] = None) -> Optional[dict]:
|
||||
def last_closed_bar(
|
||||
bars: list[dict],
|
||||
period_minutes: int = 5,
|
||||
now: Optional[datetime] = None,
|
||||
) -> Optional[dict]:
|
||||
"""取最近一根已收盘 K 线。"""
|
||||
dnow = now or datetime.now(TZ)
|
||||
mins = max(1, int(period_minutes or 5))
|
||||
for bar in reversed(bars or []):
|
||||
dt = _parse_bar_time(str(bar.get("time") or ""))
|
||||
if not dt:
|
||||
continue
|
||||
bar_end = dt + timedelta(minutes=BAR_MINUTES)
|
||||
bar_end = dt + timedelta(minutes=mins)
|
||||
if dnow >= bar_end:
|
||||
return bar
|
||||
return None
|
||||
@@ -116,24 +151,26 @@ def detect_break_side(close: float, upper: float, lower: float) -> Optional[str]
|
||||
return None
|
||||
|
||||
|
||||
def fetch_closed_5m_bar(
|
||||
def fetch_closed_bar(
|
||||
sym: str,
|
||||
period: str,
|
||||
*,
|
||||
db_path: str,
|
||||
trading_mode: str,
|
||||
) -> Optional[dict]:
|
||||
p = normalize_bar_period(period)
|
||||
try:
|
||||
data = fetch_market_klines(
|
||||
sym,
|
||||
BAR_PERIOD,
|
||||
p,
|
||||
db_path=db_path,
|
||||
trading_mode=trading_mode,
|
||||
prefer_ctp=True,
|
||||
)
|
||||
bars = data.get("bars") or []
|
||||
return last_closed_bar(bars)
|
||||
return last_closed_bar(bars, bar_period_minutes(p))
|
||||
except Exception as exc:
|
||||
logger.debug("key monitor kline %s: %s", sym, exc)
|
||||
logger.debug("key monitor kline %s %s: %s", sym, p, exc)
|
||||
return None
|
||||
|
||||
|
||||
@@ -201,9 +238,10 @@ def format_auto_breakout_msg(
|
||||
break_label, _ = break_direction_label(break_side)
|
||||
dir_cn = "做多" if direction == "long" else "做空"
|
||||
rr = float(row.get("risk_reward") or 2)
|
||||
period_label = bar_period_label(row.get("bar_period") or DEFAULT_BAR_PERIOD)
|
||||
lines = [
|
||||
f"{'✅' if ok else '❌'} {name} {typ}自动单",
|
||||
f"⏱ 5m 收盘:{bar_time}",
|
||||
f"⏱ {period_label} 收盘:{bar_time}",
|
||||
f"🎯 {break_label} · {trade_mode} · {dir_cn}",
|
||||
f"💹 入场:{entry:g} 止损:{sl:g} 止盈:{tp:g}(盈亏比 {rr:g})",
|
||||
f"📦 手数:{lots}",
|
||||
@@ -333,7 +371,8 @@ def run_key_monitor_check(
|
||||
archive_monitor(conn, pid)
|
||||
continue
|
||||
|
||||
bar = fetch_closed_5m_bar(sym, db_path=db_path, trading_mode=mode)
|
||||
bar_period = normalize_bar_period(row.get("bar_period") or DEFAULT_BAR_PERIOD)
|
||||
bar = fetch_closed_bar(sym, bar_period, db_path=db_path, trading_mode=mode)
|
||||
if not bar:
|
||||
continue
|
||||
bar_time = str(bar.get("time") or "")[:19]
|
||||
|
||||
+17
-8
@@ -3,11 +3,20 @@
|
||||
.key-rules-body{padding:.35rem 0 .15rem}
|
||||
.key-rules-body ul{margin:.25rem 0 .5rem 1.1rem;padding:0}
|
||||
.key-rules-body li{margin:.15rem 0}
|
||||
.key-check{display:inline-flex;align-items:center;gap:.35rem;font-size:.82rem;flex:1;min-width:0;margin:0}
|
||||
.key-check-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
.line-key-actions{display:flex;align-items:center;justify-content:space-between;gap:.75rem;flex-wrap:nowrap}
|
||||
.line-key-actions.is-hidden{display:none!important}
|
||||
.line-key-actions .key-submit-btn{flex-shrink:0;min-width:5.5rem;padding:.55rem 1.1rem}
|
||||
.line-key-actions.key-actions-zone{justify-content:flex-end}
|
||||
.line-key-actions.key-actions-zone .key-check{display:none}
|
||||
#key-trade-mode-wrap.is-hidden,#key-rr-wrap.is-hidden{display:none!important}
|
||||
.key-form-rows{display:flex;flex-direction:column;gap:.75rem;margin-bottom:.85rem}
|
||||
.key-form-line{display:grid;gap:.65rem;align-items:end}
|
||||
.key-form-line.line-3{grid-template-columns:1.4fr .85fr .85fr}
|
||||
.key-form-line.line-2{grid-template-columns:1fr 1fr}
|
||||
.key-field label{display:block;font-size:.72rem;margin-bottom:.28rem;color:var(--text-label)}
|
||||
.key-field select,.key-field input{width:100%;box-sizing:border-box}
|
||||
.key-action-row{display:flex;flex-direction:column;gap:.35rem;margin-top:.15rem}
|
||||
.key-action-row .trailing-be-toggle{display:flex;align-items:center;gap:.4rem;font-size:.78rem;color:var(--text-label);margin:0;cursor:pointer;user-select:none}
|
||||
.key-action-row .trailing-be-toggle input{width:auto;margin:0;flex-shrink:0}
|
||||
.key-trailing-hint{font-size:.72rem;margin:0;color:var(--text-muted);line-height:1.45}
|
||||
.key-action-row .key-submit-btn{width:100%;padding:.65rem .75rem;font-size:.9rem;margin-top:.25rem}
|
||||
#key-row-auto.is-hidden,#key-rr-wrap.is-hidden,#key-trade-mode-wrap.is-hidden,#key-direction-wrap.is-hidden,#key-trailing-wrap.is-hidden,#key-trailing-hint.is-hidden{display:none!important}
|
||||
@media(max-width:720px){
|
||||
.key-form-line.line-3{grid-template-columns:1fr 1fr}
|
||||
.key-form-line.line-3 .key-field:first-child{grid-column:1/-1}
|
||||
.key-form-line.line-2{grid-template-columns:1fr}
|
||||
}
|
||||
|
||||
+13
-4
@@ -5,26 +5,35 @@
|
||||
(function () {
|
||||
var keyTimer = null;
|
||||
var typeEl = document.getElementById('key-type');
|
||||
var rowAuto = document.getElementById('key-row-auto');
|
||||
var tradeModeWrap = document.getElementById('key-trade-mode-wrap');
|
||||
var directionWrap = document.getElementById('key-direction-wrap');
|
||||
var rrWrap = document.getElementById('key-rr-wrap');
|
||||
var rrEl = document.getElementById('key-rr');
|
||||
var trailingWrap = document.getElementById('key-trailing-wrap');
|
||||
var trailingHint = document.getElementById('key-trailing-hint');
|
||||
var trailingEl = document.getElementById('key-trailing');
|
||||
var rowActions = document.getElementById('key-row-actions');
|
||||
var rowPrices = document.getElementById('key-row-prices');
|
||||
var directionEl = document.getElementById('key-direction');
|
||||
|
||||
function isAutoType(typ) {
|
||||
return typ === '箱体突破' || typ === '收敛突破';
|
||||
}
|
||||
|
||||
function isBoxType(typ) {
|
||||
return typ === '箱体突破';
|
||||
}
|
||||
|
||||
function syncKeyForm() {
|
||||
var typ = typeEl ? typeEl.value : '';
|
||||
var auto = isAutoType(typ);
|
||||
var box = isBoxType(typ);
|
||||
if (rowAuto) rowAuto.classList.toggle('is-hidden', !auto);
|
||||
if (tradeModeWrap) tradeModeWrap.classList.toggle('is-hidden', !auto);
|
||||
if (rrWrap) rrWrap.classList.toggle('is-hidden', !auto);
|
||||
if (directionWrap) directionWrap.classList.toggle('is-hidden', !box);
|
||||
if (trailingWrap) trailingWrap.classList.toggle('is-hidden', !auto);
|
||||
if (rowActions) rowActions.classList.toggle('key-actions-zone', !auto);
|
||||
if (rowPrices) rowPrices.classList.toggle('key-zone-mode', !auto);
|
||||
if (trailingHint) trailingHint.classList.toggle('is-hidden', !auto);
|
||||
if (directionEl) directionEl.disabled = !box;
|
||||
if (!auto && trailingEl) trailingEl.checked = false;
|
||||
if (auto && trailingEl && trailingEl.checked && rrEl) {
|
||||
if (parseFloat(rrEl.value) < 3) rrEl.value = '3';
|
||||
|
||||
+80
-39
@@ -14,56 +14,88 @@
|
||||
<div class="key-rules-body">
|
||||
<p><strong>箱体突破 / 收敛突破(自动单)</strong></p>
|
||||
<ul>
|
||||
<li>触发:<strong>5 分钟 K 线收盘</strong>收在上沿或下沿之外</li>
|
||||
<li>触发:<strong>上周期 K 线收盘</strong>收在上沿或下沿之外(默认 5 分)</li>
|
||||
<li>箱体突破须选<strong>上方向</strong>,仅当突破后下单方向一致时才自动开仓</li>
|
||||
<li>顺势:上破做多、下破做空;反转:上破做空、下破做多</li>
|
||||
<li>自动<strong>市价开仓</strong>;止损 = 突破 K 线极值 ± 2 跳</li>
|
||||
<li>盈亏比默认 2(可改);开启移动保本时默认 3,达目标价自动止盈</li>
|
||||
<li>成交后进入「下单监控」持仓,来源备注为监控类型</li>
|
||||
</ul>
|
||||
<p><strong>关键支阻区(仅提醒)</strong></p>
|
||||
<ul>
|
||||
<li>上沿 = 阻力,下沿 = 支撑,合并为一个区间</li>
|
||||
<li>5m 收盘突破上沿或跌破下沿 → 微信推送(最多 3 次,间隔约 5 分钟)</li>
|
||||
<li>上周期 K 线收盘突破 → 微信推送(最多 3 次,间隔约 5 分钟)</li>
|
||||
<li>推送完毕后自动结案,<strong>不参与自动开仓</strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
||||
<form action="{{ url_for('add_key') }}" method="post" class="form-compact" id="key-add-form">
|
||||
<div class="form-line line-3">
|
||||
<div class="symbol-wrap symbol-mains">
|
||||
<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>
|
||||
<form action="{{ url_for('add_key') }}" method="post" id="key-add-form">
|
||||
<div class="key-form-rows">
|
||||
<div class="key-form-line line-3">
|
||||
<div class="key-field symbol-wrap symbol-mains">
|
||||
<label class="text-label">品种</label>
|
||||
<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>
|
||||
<div class="key-field">
|
||||
<label class="text-label">类型</label>
|
||||
<select name="type" id="key-type" required>
|
||||
<option value="箱体突破">箱体突破</option>
|
||||
<option value="收敛突破">收敛突破</option>
|
||||
<option value="关键支阻区">关键支阻区</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="key-field">
|
||||
<label class="text-label">上周期</label>
|
||||
<select name="bar_period" id="key-bar-period">
|
||||
{% for p in key_periods %}
|
||||
<option value="{{ p.key }}"{% if p.key == '5m' %} selected{% endif %}>{{ p.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<select name="type" id="key-type" required>
|
||||
<option value="箱体突破">箱体突破</option>
|
||||
<option value="收敛突破">收敛突破</option>
|
||||
<option value="关键支阻区">关键支阻区</option>
|
||||
</select>
|
||||
<div id="key-trade-mode-wrap">
|
||||
<select name="trade_mode" id="key-trade-mode">
|
||||
<option value="顺势">顺势</option>
|
||||
<option value="反转">反转</option>
|
||||
</select>
|
||||
<div class="key-form-line line-3" id="key-row-auto">
|
||||
<div class="key-field" id="key-trade-mode-wrap">
|
||||
<label class="text-label">模式</label>
|
||||
<select name="trade_mode" id="key-trade-mode">
|
||||
<option value="顺势">顺势</option>
|
||||
<option value="反转">反转</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="key-field" id="key-direction-wrap">
|
||||
<label class="text-label">上方向</label>
|
||||
<select name="direction" id="key-direction">
|
||||
<option value="long">做多</option>
|
||||
<option value="short">做空</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="key-field" id="key-rr-wrap">
|
||||
<label class="text-label">盈亏比</label>
|
||||
<input name="risk_reward" id="key-rr" type="number" step="0.1" min="0.5" max="10" value="2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-line line-3" id="key-row-prices">
|
||||
<input name="upper" type="number" step="0.0001" placeholder="上沿(阻力)" required>
|
||||
<input name="lower" type="number" step="0.0001" placeholder="下沿(支撑)" required>
|
||||
<div id="key-rr-wrap">
|
||||
<input name="risk_reward" id="key-rr" type="number" step="0.1" min="0.5" max="10" value="2" placeholder="盈亏比">
|
||||
<div class="key-form-line line-2" id="key-row-prices">
|
||||
<div class="key-field">
|
||||
<label class="text-label">上沿(阻力)</label>
|
||||
<input name="upper" type="number" step="0.0001" required>
|
||||
</div>
|
||||
<div class="key-field">
|
||||
<label class="text-label">下沿(支撑)</label>
|
||||
<input name="lower" type="number" step="0.0001" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="key-action-row" id="key-row-actions">
|
||||
<label class="trailing-be-toggle" id="key-trailing-wrap">
|
||||
<input type="checkbox" name="trailing_be" id="key-trailing" value="1">
|
||||
<span>移动保本</span>
|
||||
</label>
|
||||
<p class="hint key-trailing-hint" id="key-trailing-hint">开启后盈亏比默认 3,达 3R 自动止盈并启用移动止损</p>
|
||||
<button type="submit" class="btn-primary key-submit-btn">添加</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-line line-key-actions" id="key-row-actions">
|
||||
<label class="key-check" id="key-trailing-wrap">
|
||||
<input type="checkbox" name="trailing_be" id="key-trailing" value="1">
|
||||
<span class="key-check-text">移动保本(默认盈亏比 3,达 3R 止盈)</span>
|
||||
</label>
|
||||
<button type="submit" class="btn-primary key-submit-btn">添加</button>
|
||||
</div>
|
||||
</form>
|
||||
<h3 class="section-label">监控列表</h3>
|
||||
@@ -72,8 +104,12 @@
|
||||
<div class="list-item key-item" data-key-id="{{ k.id }}" style="padding:.75rem;font-size:.85rem">
|
||||
<div>
|
||||
<strong>{{ k.symbol_name or k.symbol }}</strong> {{ k.monitor_type }}
|
||||
<span class="badge planned">{{ k.bar_period or '5m' }}</span>
|
||||
{% if k.monitor_type in ('箱体突破', '收敛突破') %}
|
||||
<span class="badge planned">{{ k.trade_mode or '顺势' }}</span>
|
||||
{% if k.monitor_type == '箱体突破' and k.direction %}
|
||||
<span class="badge profit">{{ '做多' if k.direction == 'long' else '做空' }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if k.trailing_be %}
|
||||
<span class="badge profit">移动保本</span>
|
||||
@@ -101,15 +137,20 @@
|
||||
<h2>监控历史</h2>
|
||||
<div class="card-body card-scroll">
|
||||
<table>
|
||||
<thead><tr><th>品种</th><th>类型</th><th>模式</th><th>上沿</th><th>下沿</th><th>归档</th></tr></thead>
|
||||
<thead><tr><th>品种</th><th>类型</th><th>周期</th><th>模式</th><th>上沿</th><th>下沿</th><th>归档</th></tr></thead>
|
||||
<tbody>
|
||||
{% for k in history %}
|
||||
<tr>
|
||||
<td>{{ k.symbol_name or k.symbol }}</td>
|
||||
<td>{{ k.monitor_type }}</td>
|
||||
<td>{{ k.bar_period or '5m' }}</td>
|
||||
<td>
|
||||
{% if k.monitor_type in ('箱体突破', '收敛突破') %}
|
||||
{{ k.trade_mode or '顺势' }}{% if k.trailing_be %} · 移动保本{% endif %}
|
||||
{{ k.trade_mode or '顺势' }}
|
||||
{% if k.monitor_type == '箱体突破' and k.direction %}
|
||||
· {{ '做多' if k.direction == 'long' else '做空' }}
|
||||
{% endif %}
|
||||
{% if k.trailing_be %} · 移动保本{% endif %}
|
||||
{% elif k.monitor_type in ('关键阻力位', '关键支撑位') %}
|
||||
支阻区
|
||||
{% else %}
|
||||
@@ -121,7 +162,7 @@
|
||||
<td>{{ k.archived_at[:16] if k.archived_at else '' }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="6" class="text-muted">暂无历史</td></tr>
|
||||
<tr><td colspan="7" class="text-muted">暂无历史</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user