修改币种精度
This commit is contained in:
+124
-53
@@ -239,10 +239,10 @@ def _wechat_trading_capital_text(fallback=None):
|
||||
except Exception:
|
||||
trading_capital = None
|
||||
if trading_capital is not None:
|
||||
return f"{round(float(trading_capital), 4)}U"
|
||||
return f"{round(float(trading_capital), FUNDS_DECIMALS)}U"
|
||||
if fallback is not None:
|
||||
try:
|
||||
return f"{round(float(fallback), 4)}U"
|
||||
return f"{round(float(fallback), FUNDS_DECIMALS)}U"
|
||||
except Exception:
|
||||
pass
|
||||
return "-"
|
||||
@@ -271,7 +271,7 @@ def build_wechat_close_message(
|
||||
try:
|
||||
if pnl_amount is not None:
|
||||
pv = float(pnl_amount)
|
||||
pnl_disp = f"{'+' if pv > 0 else ''}{round(pv, 4)} U"
|
||||
pnl_disp = f"{'+' if pv > 0 else ''}{round(pv, FUNDS_DECIMALS)} U"
|
||||
else:
|
||||
pnl_disp = "-"
|
||||
except (TypeError, ValueError):
|
||||
@@ -1352,19 +1352,19 @@ def _compute_period_metrics(trades):
|
||||
closed = len(trades)
|
||||
wins = sum(1 for p, _, _ in trades if p > 0)
|
||||
losses = sum(1 for p, _, _ in trades if p < 0)
|
||||
net = round(sum(p for p, _, _ in trades), 4)
|
||||
net = round(sum(p for p, _, _ in trades), FUNDS_DECIMALS)
|
||||
loss_sum_raw = sum(p for p, _, _ in trades if p < 0)
|
||||
loss_sum_u = round(abs(loss_sum_raw), 4) if loss_sum_raw < 0 else 0.0
|
||||
loss_sum_u = round(abs(loss_sum_raw), FUNDS_DECIMALS) if loss_sum_raw < 0 else 0.0
|
||||
neg_pnls = [p for p, _, _ in trades if p < 0]
|
||||
pos_pnls = [p for p, _, _ in trades if p > 0]
|
||||
max_single_loss = round(min(neg_pnls), 4) if neg_pnls else None
|
||||
max_single_profit = round(max(pos_pnls), 4) if pos_pnls else None
|
||||
max_single_loss = round(min(neg_pnls), FUNDS_DECIMALS) if neg_pnls else None
|
||||
max_single_profit = round(max(pos_pnls), FUNDS_DECIMALS) if pos_pnls else None
|
||||
cum = peak = max_dd = 0.0
|
||||
for p, _, _ in trades:
|
||||
cum += p
|
||||
peak = max(peak, cum)
|
||||
max_dd = max(max_dd, peak - cum)
|
||||
max_dd = round(max_dd, 4)
|
||||
max_dd = round(max_dd, FUNDS_DECIMALS)
|
||||
streak = 0
|
||||
for p, _, _ in reversed(trades):
|
||||
if p < 0:
|
||||
@@ -1388,7 +1388,7 @@ def _compute_period_metrics(trades):
|
||||
else:
|
||||
run = 0
|
||||
worst_day = min(daily.keys(), key=lambda x: daily[x])
|
||||
worst_day_pnl = round(daily[worst_day], 4)
|
||||
worst_day_pnl = round(daily[worst_day], FUNDS_DECIMALS)
|
||||
win_rate_pct = round(wins / (wins + losses) * 100, 2) if (wins + losses) else None
|
||||
return {
|
||||
"closed_count": closed,
|
||||
@@ -1619,10 +1619,10 @@ def update_session_capital(conn, session_date, pnl_amount):
|
||||
new_capital = float(session_row["current_capital"]) + float(pnl_amount)
|
||||
conn.execute(
|
||||
"UPDATE trading_sessions SET current_capital = ?, updated_at = CURRENT_TIMESTAMP WHERE session_date = ?",
|
||||
(round(new_capital, 4), session_date)
|
||||
(round(new_capital, FUNDS_DECIMALS), session_date)
|
||||
)
|
||||
conn.commit()
|
||||
return round(new_capital, 4)
|
||||
return round(new_capital, FUNDS_DECIMALS)
|
||||
|
||||
|
||||
def calc_hold_seconds(opened_at_str, closed_at_dt):
|
||||
@@ -1684,17 +1684,66 @@ def to_effective_trade_dict(row):
|
||||
return item
|
||||
|
||||
|
||||
# USDT 等资金类:展示与入库舍入统一为 2 位小数(与交易所常见口径一致)
|
||||
FUNDS_DECIMALS = 2
|
||||
|
||||
|
||||
def format_funds_u(value):
|
||||
if value in (None, ""):
|
||||
return "-"
|
||||
try:
|
||||
return f"{float(value):.{FUNDS_DECIMALS}f}"
|
||||
except (TypeError, ValueError):
|
||||
return str(value)
|
||||
|
||||
|
||||
def round_funds(value):
|
||||
try:
|
||||
return round(float(value), FUNDS_DECIMALS)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def _ccxt_swap_symbol_for_precision(symbol):
|
||||
"""解析为 ccxt markets 中的永续 symbol,供 price_to_precision 使用。"""
|
||||
raw = (symbol or "").strip()
|
||||
if not raw:
|
||||
return None
|
||||
try:
|
||||
ensure_markets_loaded()
|
||||
markets = getattr(exchange, "markets", {}) or {}
|
||||
except Exception:
|
||||
return None
|
||||
upper = raw.upper().replace(" ", "")
|
||||
candidates = []
|
||||
candidates.append(normalize_exchange_symbol(raw))
|
||||
if upper.endswith("USDT") and len(upper) > 4 and "/" not in raw and ":" not in raw:
|
||||
candidates.append(f"{upper[:-4]}/USDT:USDT")
|
||||
if "/" not in raw and ":" not in raw and upper.isalnum() and not upper.endswith("USDT"):
|
||||
candidates.append(f"{upper}/USDT:USDT")
|
||||
for c in candidates:
|
||||
if c and c in markets:
|
||||
return c
|
||||
return None
|
||||
|
||||
|
||||
def format_price_for_symbol(symbol, value):
|
||||
if value in (None, ""):
|
||||
return "-"
|
||||
try:
|
||||
v = float(value)
|
||||
except Exception:
|
||||
except (TypeError, ValueError):
|
||||
return str(value)
|
||||
if v == 0:
|
||||
return "0"
|
||||
try:
|
||||
ex_sym = _ccxt_swap_symbol_for_precision(symbol)
|
||||
if ex_sym:
|
||||
return str(exchange.price_to_precision(ex_sym, v))
|
||||
except Exception:
|
||||
pass
|
||||
av = abs(v)
|
||||
# 根据币价量级动态精度:低价币保留更多小数,高价币减少噪音位数
|
||||
# 无法加载市场或无该合约时:按价格量级回退(尽量不阻断页面)
|
||||
if av >= 10000:
|
||||
d = 2
|
||||
elif av >= 100:
|
||||
@@ -1734,7 +1783,7 @@ def calc_pnl(direction, trigger_price, exit_price, margin_capital, leverage):
|
||||
pnl_ratio = (trigger - exit_p) / trigger
|
||||
else:
|
||||
pnl_ratio = (exit_p - trigger) / trigger
|
||||
return round(margin * lev * pnl_ratio, 4)
|
||||
return round(margin * lev * pnl_ratio, FUNDS_DECIMALS)
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
@@ -1784,7 +1833,7 @@ def calc_risk_amount_from_plan(direction, entry_price, stop_loss, margin_capital
|
||||
notional = float(margin_capital) * float(leverage)
|
||||
if notional <= 0:
|
||||
return None
|
||||
return round(notional * rf, 6)
|
||||
return round(notional * rf, FUNDS_DECIMALS)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
@@ -1910,7 +1959,7 @@ def enrich_order_item(raw_item, current_capital):
|
||||
notional = item.get("notional_value")
|
||||
ratio = item.get("position_ratio")
|
||||
if notional is None:
|
||||
notional = round(margin * lev, 4) if margin and lev else 0
|
||||
notional = round(margin * lev, FUNDS_DECIMALS) if margin and lev else 0
|
||||
if ratio is None:
|
||||
ratio = round(margin / current_capital * 100, 2) if current_capital else 0
|
||||
item["notional_value"] = notional
|
||||
@@ -2083,7 +2132,7 @@ def friendly_exchange_error(err, available_usdt=None):
|
||||
or "margin" in low and ("not enough" in low or "不足" in msg)
|
||||
or "balance" in low and "insufficient" in low
|
||||
):
|
||||
tail = f"(当前交易账户可用约 {round(available_usdt, 4)}U)" if available_usdt is not None else ""
|
||||
tail = f"(当前交易账户可用约 {round(available_usdt, FUNDS_DECIMALS)}U)" if available_usdt is not None else ""
|
||||
return f"交易所下单失败:保证金不足 {tail}。请降低保证金/杠杆,或先划转USDT到合约账户。"
|
||||
clean = re.sub(r"\s+", " ", msg).strip()
|
||||
return f"交易所下单失败:{clean}"
|
||||
@@ -2173,7 +2222,7 @@ def auto_transfer_once_per_day():
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return
|
||||
needed = round(max(target_amount - float(to_balance), 0), 4)
|
||||
needed = round(max(target_amount - float(to_balance), 0), FUNDS_DECIMALS)
|
||||
if needed <= 0:
|
||||
conn.execute(
|
||||
"INSERT INTO transfer_logs (transfer_type, transfer_day, amount, from_account, to_account, status, message) VALUES (?,?,?,?,?,?,?)",
|
||||
@@ -2185,12 +2234,12 @@ def auto_transfer_once_per_day():
|
||||
if from_balance is not None and from_balance < needed:
|
||||
conn.execute(
|
||||
"INSERT INTO transfer_logs (transfer_type, transfer_day, amount, from_account, to_account, status, message) VALUES (?,?,?,?,?,?,?)",
|
||||
("auto_daily", transfer_day, needed, AUTO_TRANSFER_FROM, AUTO_TRANSFER_TO, "failed", f"{AUTO_TRANSFER_FROM}账户USDT不足,需{needed}U,当前{round(from_balance,4)}U")
|
||||
("auto_daily", transfer_day, needed, AUTO_TRANSFER_FROM, AUTO_TRANSFER_TO, "failed", f"{AUTO_TRANSFER_FROM}账户USDT不足,需{needed}U,当前{round(from_balance, FUNDS_DECIMALS)}U")
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
send_wechat_msg(
|
||||
f"自动划转失败:{AUTO_TRANSFER_FROM}余额不足,需{needed}U,当前{round(from_balance,4)}U\n"
|
||||
f"自动划转失败:{AUTO_TRANSFER_FROM}余额不足,需{needed}U,当前{round(from_balance, FUNDS_DECIMALS)}U\n"
|
||||
f"账簿日(UTC):{transfer_day}|触发时刻(北京):{app_now_str()}"
|
||||
)
|
||||
return
|
||||
@@ -2688,13 +2737,21 @@ def parse_ccxt_position_metrics(position, order_leverage=None):
|
||||
mark = _coerce_float(p.get("markPrice"), p.get("mark_price"), info.get("mark_price"), info.get("markPrice"))
|
||||
out = {}
|
||||
if initial is not None and initial > 0:
|
||||
out["initial_margin"] = round(initial, 4)
|
||||
out["initial_margin"] = round(initial, FUNDS_DECIMALS)
|
||||
if notional is not None and notional > 0:
|
||||
out["notional"] = round(notional, 4)
|
||||
out["notional"] = round(notional, FUNDS_DECIMALS)
|
||||
if unrealized is not None:
|
||||
out["unrealized_pnl"] = round(unrealized, 6)
|
||||
out["unrealized_pnl"] = round(unrealized, FUNDS_DECIMALS)
|
||||
if mark is not None and mark > 0:
|
||||
out["mark_price"] = round(mark, 8)
|
||||
ps = p.get("symbol")
|
||||
try:
|
||||
ex_sym = _ccxt_swap_symbol_for_precision(ps or "")
|
||||
if ex_sym:
|
||||
out["mark_price"] = float(exchange.price_to_precision(ex_sym, mark))
|
||||
else:
|
||||
out["mark_price"] = round(mark, 8)
|
||||
except Exception:
|
||||
out["mark_price"] = round(mark, 8)
|
||||
return out or None
|
||||
|
||||
|
||||
@@ -3817,8 +3874,8 @@ def render_main_page(page="trade"):
|
||||
local_current_capital = float(session_row["current_capital"])
|
||||
funding_capital, trading_capital = get_exchange_capitals()
|
||||
# 资金账户:仅展示交易所读取结果(含 0)。不可用 TOTAL_CAPITAL 兜底,否则会与实盘不符。
|
||||
funding_usdt = round(funding_capital, 4) if funding_capital is not None else None
|
||||
current_capital = round(trading_capital, 4) if trading_capital is not None else round(local_current_capital, 4)
|
||||
funding_usdt = round(funding_capital, FUNDS_DECIMALS) if funding_capital is not None else None
|
||||
current_capital = round(trading_capital, FUNDS_DECIMALS) if trading_capital is not None else round(local_current_capital, FUNDS_DECIMALS)
|
||||
recommended_capital = get_recommended_capital(current_capital)
|
||||
key_list = conn.execute("SELECT * FROM key_monitors").fetchall()
|
||||
key_history = conn.execute("SELECT * FROM key_monitor_history ORDER BY id DESC LIMIT 80").fetchall()
|
||||
@@ -3880,6 +3937,7 @@ def render_main_page(page="trade"):
|
||||
breakeven_offset_pct=BREAKEVEN_OFFSET_PCT,
|
||||
occupied_miss_total=occupied_miss_total,
|
||||
price_fmt=format_price_for_symbol,
|
||||
funds_fmt=format_funds_u,
|
||||
entry_reason_options=list(ENTRY_REASON_OPTIONS),
|
||||
entry_reason_other_value=ENTRY_REASON_OTHER,
|
||||
exchange_display=EXCHANGE_DISPLAY_NAME,
|
||||
@@ -3919,8 +3977,8 @@ def api_account_snapshot():
|
||||
session_row = ensure_session(conn, trading_day)
|
||||
local_current_capital = float(session_row["current_capital"])
|
||||
funding_capital, trading_capital = get_exchange_capitals(force=True)
|
||||
funding_usdt = round(funding_capital, 4) if funding_capital is not None else None
|
||||
current_capital = round(trading_capital, 4) if trading_capital is not None else round(local_current_capital, 4)
|
||||
funding_usdt = round(funding_capital, FUNDS_DECIMALS) if funding_capital is not None else None
|
||||
current_capital = round(trading_capital, FUNDS_DECIMALS) if trading_capital is not None else round(local_current_capital, FUNDS_DECIMALS)
|
||||
recommended_capital = get_recommended_capital(current_capital)
|
||||
active_count = conn.execute("SELECT COUNT(*) FROM order_monitors WHERE status='active'").fetchone()[0]
|
||||
conn.close()
|
||||
@@ -3929,7 +3987,7 @@ def api_account_snapshot():
|
||||
return jsonify({
|
||||
"funding_usdt": funding_usdt,
|
||||
"current_capital": current_capital,
|
||||
"available_trading_usdt": round(available_trading_usdt, 4) if available_trading_usdt is not None else None,
|
||||
"available_trading_usdt": round(available_trading_usdt, FUNDS_DECIMALS) if available_trading_usdt is not None else None,
|
||||
"recommended_capital": recommended_capital,
|
||||
"active_count": active_count,
|
||||
"can_trade": can_trade,
|
||||
@@ -3995,19 +4053,21 @@ def api_price_snapshot():
|
||||
vol_now = round(float(gate.get("vol_break") or 0), 4)
|
||||
vol_avg = round(float(gate.get("avg20") or 0), 4)
|
||||
amp_pct = round(float(gate.get("amp_pct") or 0), 4)
|
||||
cfm_close = round(float(gate.get("confirm_close") or 0), 8)
|
||||
edge = round(float(gate.get("edge_price") or 0), 8)
|
||||
cfm_close = float(gate.get("confirm_close") or 0)
|
||||
edge = float(gate.get("edge_price") or 0)
|
||||
gate_metrics = (
|
||||
f"量值:{vol_now}/{vol_avg} "
|
||||
f"幅值:{amp_pct}% "
|
||||
f"二确值:{cfm_close}@{edge}"
|
||||
f"二确值:{format_price_for_symbol(r['symbol'], cfm_close)}@{format_price_for_symbol(r['symbol'], edge)}"
|
||||
)
|
||||
except Exception:
|
||||
gate_metrics = ""
|
||||
sym_k = r["symbol"]
|
||||
key_prices.append({
|
||||
"id": r["id"],
|
||||
"symbol": r["symbol"],
|
||||
"symbol": sym_k,
|
||||
"price": round(price, 6),
|
||||
"price_display": format_price_for_symbol(sym_k, price),
|
||||
"upper_diff": upper_diff,
|
||||
"upper_pct": upper_pct,
|
||||
"lower_diff": lower_diff,
|
||||
@@ -4026,7 +4086,7 @@ def api_price_snapshot():
|
||||
leverage = float(r["leverage"] or 0)
|
||||
entry = float(r["trigger_price"] or 0)
|
||||
pnl = calc_pnl(r["direction"], entry, price, margin, leverage) if entry > 0 else 0
|
||||
pnl_pct = round((pnl / margin * 100), 4) if margin > 0 else 0
|
||||
pnl_pct = round((pnl / margin * 100), 2) if margin > 0 else 0
|
||||
rr_ratio = calc_rr_ratio(r["direction"], entry, r["initial_stop_loss"] or r["stop_loss"], r["take_profit"])
|
||||
ex_sym = resolve_monitor_exchange_symbol(r)
|
||||
prow = _select_live_position_row(all_swap_positions, ex_sym, r["direction"])
|
||||
@@ -4036,13 +4096,15 @@ def api_price_snapshot():
|
||||
"id": r["id"],
|
||||
"symbol": r["symbol"],
|
||||
"price": round(price, 6),
|
||||
"float_pnl": round(pnl, 6),
|
||||
"price_display": format_price_for_symbol(ex_sym, price),
|
||||
"float_pnl": round(pnl, FUNDS_DECIMALS),
|
||||
"float_pct": pnl_pct,
|
||||
"rr_ratio": rr_ratio,
|
||||
"plan_margin": round(margin, 4) if margin else None,
|
||||
"plan_margin": round(margin, FUNDS_DECIMALS) if margin else None,
|
||||
"exchange_initial_margin": None,
|
||||
"exchange_notional": None,
|
||||
"exchange_mark_price": None,
|
||||
"exchange_mark_price_display": None,
|
||||
"pnl_source": "plan",
|
||||
}
|
||||
if ex_metrics:
|
||||
@@ -4051,13 +4113,15 @@ def api_price_snapshot():
|
||||
if ex_metrics.get("notional") is not None:
|
||||
payload["exchange_notional"] = ex_metrics["notional"]
|
||||
if ex_metrics.get("mark_price") is not None:
|
||||
payload["exchange_mark_price"] = ex_metrics["mark_price"]
|
||||
mp = ex_metrics["mark_price"]
|
||||
payload["exchange_mark_price"] = mp
|
||||
payload["exchange_mark_price_display"] = format_price_for_symbol(ex_sym, mp)
|
||||
if ex_metrics.get("unrealized_pnl") is not None:
|
||||
payload["float_pnl"] = round(float(ex_metrics["unrealized_pnl"]), 6)
|
||||
payload["float_pnl"] = round(float(ex_metrics["unrealized_pnl"]), FUNDS_DECIMALS)
|
||||
payload["pnl_source"] = "exchange"
|
||||
denom = ex_metrics.get("initial_margin") or margin
|
||||
payload["float_pct"] = (
|
||||
round((payload["float_pnl"] / float(denom)) * 100, 4) if denom and float(denom) > 0 else pnl_pct
|
||||
round((payload["float_pnl"] / float(denom)) * 100, 2) if denom and float(denom) > 0 else pnl_pct
|
||||
)
|
||||
order_prices.append(payload)
|
||||
|
||||
@@ -4109,7 +4173,7 @@ def api_order_defaults():
|
||||
"exchange_symbol": exchange_symbol,
|
||||
"direction": direction,
|
||||
"leverage": leverage,
|
||||
"available_trading_usdt": round(available, 4) if available is not None else None
|
||||
"available_trading_usdt": round(available, FUNDS_DECIMALS) if available is not None else None
|
||||
})
|
||||
|
||||
|
||||
@@ -4122,7 +4186,7 @@ def order_focus():
|
||||
session_row = ensure_session(conn, trading_day)
|
||||
local_current_capital = float(session_row["current_capital"])
|
||||
_, trading_capital_live = get_exchange_capitals()
|
||||
current_capital = round(trading_capital_live, 4) if trading_capital_live is not None else round(local_current_capital, 4)
|
||||
current_capital = round(trading_capital_live, FUNDS_DECIMALS) if trading_capital_live is not None else round(local_current_capital, FUNDS_DECIMALS)
|
||||
raw_orders = conn.execute("SELECT * FROM order_monitors WHERE status='active' ORDER BY id DESC").fetchall()
|
||||
conn.close()
|
||||
orders = [enrich_order_item(row_to_dict(r), current_capital) for r in raw_orders]
|
||||
@@ -4161,7 +4225,7 @@ def api_order_kline():
|
||||
session_row = ensure_session(conn, trading_day)
|
||||
local_current_capital = float(session_row["current_capital"])
|
||||
_, trading_capital_live = get_exchange_capitals()
|
||||
current_capital = round(trading_capital_live, 4) if trading_capital_live is not None else round(local_current_capital, 4)
|
||||
current_capital = round(trading_capital_live, FUNDS_DECIMALS) if trading_capital_live is not None else round(local_current_capital, FUNDS_DECIMALS)
|
||||
row = conn.execute("SELECT * FROM order_monitors WHERE id=? AND status='active'", (order_id,)).fetchone()
|
||||
conn.close()
|
||||
if not row:
|
||||
@@ -4194,7 +4258,7 @@ def api_order_kline():
|
||||
leverage = float(order_item.get("leverage") or 0)
|
||||
entry = float(order_item.get("trigger_price") or 0)
|
||||
float_pnl = calc_pnl(order_item.get("direction") or "long", entry, current_price, margin, leverage) if current_price else 0
|
||||
float_pct = round((float_pnl / margin * 100), 4) if margin > 0 else 0
|
||||
float_pct = round((float_pnl / margin * 100), 2) if margin > 0 else 0
|
||||
|
||||
return jsonify({
|
||||
"ok": True,
|
||||
@@ -4207,13 +4271,17 @@ def api_order_kline():
|
||||
"trigger_price": order_item.get("trigger_price"),
|
||||
"stop_loss": order_item.get("stop_loss"),
|
||||
"take_profit": order_item.get("take_profit"),
|
||||
"trigger_price_display": format_price_for_symbol(exchange_symbol, order_item.get("trigger_price")),
|
||||
"stop_loss_display": format_price_for_symbol(exchange_symbol, order_item.get("stop_loss")),
|
||||
"take_profit_display": format_price_for_symbol(exchange_symbol, order_item.get("take_profit")),
|
||||
"margin_capital": order_item.get("margin_capital"),
|
||||
"leverage": order_item.get("leverage"),
|
||||
"position_ratio": order_item.get("position_ratio"),
|
||||
"rr_ratio": order_item.get("rr_ratio"),
|
||||
"breakeven_enabled": bool(int(order_item.get("breakeven_enabled") or 0)),
|
||||
"current_price": round(float(current_price), 8) if current_price else None,
|
||||
"float_pnl": round(float(float_pnl), 6),
|
||||
"current_price_display": format_price_for_symbol(exchange_symbol, current_price) if current_price else None,
|
||||
"float_pnl": round(float(float_pnl), FUNDS_DECIMALS),
|
||||
"float_pct": float_pct,
|
||||
},
|
||||
"candles": candles,
|
||||
@@ -4311,6 +4379,8 @@ def api_key_kline():
|
||||
"direction": key_row["direction"] or "long",
|
||||
"upper": upper,
|
||||
"lower": lower,
|
||||
"upper_display": format_price_for_symbol(exchange_symbol, upper) if upper is not None else None,
|
||||
"lower_display": format_price_for_symbol(exchange_symbol, lower) if lower is not None else None,
|
||||
"notification_count": int(key_row["notification_count"] or 0),
|
||||
"upper_diff": upper_diff,
|
||||
"upper_pct": upper_pct,
|
||||
@@ -4324,6 +4394,7 @@ def api_key_kline():
|
||||
"timeframe": timeframe,
|
||||
"limit": limit,
|
||||
"current_price": round(float(current_price), 8) if current_price is not None else None,
|
||||
"current_price_display": format_price_for_symbol(exchange_symbol, current_price) if current_price is not None else None,
|
||||
"key_monitor": key_info,
|
||||
"candles": candles,
|
||||
"updated_at": app_now_str(),
|
||||
@@ -4466,18 +4537,18 @@ def add_order():
|
||||
flash("止损方向不合法:请检查入场方向与止损价格关系")
|
||||
return redirect("/")
|
||||
risk_percent = max(0.01, float(RISK_PERCENT))
|
||||
risk_amount = round(capital_base * risk_percent / 100.0, 4)
|
||||
notional_value = round(risk_amount / risk_fraction, 4)
|
||||
margin_capital = round(notional_value / leverage, 4)
|
||||
risk_amount = round(capital_base * risk_percent / 100.0, FUNDS_DECIMALS)
|
||||
notional_value = round(risk_amount / risk_fraction, FUNDS_DECIMALS)
|
||||
margin_capital = round(notional_value / leverage, FUNDS_DECIMALS)
|
||||
if capital_base and margin_capital > capital_base:
|
||||
conn.close()
|
||||
flash("以损定仓后保证金超过当前交易资金,请放宽止损或降低风险比例")
|
||||
return redirect("/")
|
||||
if available_usdt is not None:
|
||||
max_margin = round(max(available_usdt * FULL_MARGIN_BUFFER_RATIO, 0), 4)
|
||||
max_margin = round(max(available_usdt * FULL_MARGIN_BUFFER_RATIO, 0), FUNDS_DECIMALS)
|
||||
if margin_capital > max_margin:
|
||||
conn.close()
|
||||
flash(f"保证金不足:交易账户可用约 {round(available_usdt,4)}U,当前最多建议 {max_margin}U")
|
||||
flash(f"保证金不足:交易账户可用约 {round(available_usdt, FUNDS_DECIMALS)}U,当前最多建议 {max_margin}U")
|
||||
return redirect("/")
|
||||
position_ratio = round(margin_capital / capital_base * 100, 2) if capital_base else 0
|
||||
try:
|
||||
@@ -4592,9 +4663,9 @@ def add_order():
|
||||
|
||||
_, trading_capital_after = get_exchange_capitals(force=True)
|
||||
account_base_display = (
|
||||
round(float(trading_capital_after), 4)
|
||||
round(float(trading_capital_after), FUNDS_DECIMALS)
|
||||
if trading_capital_after is not None
|
||||
else round(float(capital_base), 4)
|
||||
else round(float(capital_base), FUNDS_DECIMALS)
|
||||
)
|
||||
account_name = (os.getenv("BINANCE_ACCOUNT_LABEL") or "binance实盘账户").strip()
|
||||
dir_text = "多头(long)" if direction == "long" else "空头(short)"
|
||||
@@ -4620,7 +4691,7 @@ def add_order():
|
||||
"🧾 订单基础信息",
|
||||
f"🔖 交易所订单 ID:{open_order_id}",
|
||||
f"📈 交易风格:{style_zh}",
|
||||
f"⚠️ 单笔风控风险:{risk_percent}% ≈ {round(float(risk_amount_final), 4)} U",
|
||||
f"⚠️ 单笔风控风险:{risk_percent}% ≈ {round(float(risk_amount_final), FUNDS_DECIMALS)} U",
|
||||
"📊 仓位配置详情",
|
||||
f"账户基数:{account_base_display} USDT",
|
||||
f"合约杠杆:{leverage} 倍",
|
||||
@@ -5350,7 +5421,7 @@ def api_trade_record_review_update():
|
||||
reviewed_closed_at,
|
||||
reviewed_stop_loss,
|
||||
reviewed_take_profit,
|
||||
round(reviewed_pnl_amount, 4),
|
||||
round(reviewed_pnl_amount, FUNDS_DECIMALS),
|
||||
reviewed_result or None,
|
||||
reviewed_miss_reason or None,
|
||||
hold_seconds,
|
||||
|
||||
Reference in New Issue
Block a user