1
This commit is contained in:
parent
7299f0259b
commit
0f52cbe0be
@ -481,6 +481,14 @@ def _fmt_pct(value) -> str:
|
|||||||
return f"{sign}{pct:.2f}%"
|
return f"{sign}{pct:.2f}%"
|
||||||
|
|
||||||
|
|
||||||
|
def _side_label(side: str) -> str:
|
||||||
|
return "空" if normalize_side(side) == "short" else "多"
|
||||||
|
|
||||||
|
|
||||||
|
def _side_action(side: str, long_text: str, short_text: str) -> str:
|
||||||
|
return short_text if normalize_side(side) == "short" else long_text
|
||||||
|
|
||||||
|
|
||||||
def _card_field(label: str, value) -> dict:
|
def _card_field(label: str, value) -> dict:
|
||||||
return {
|
return {
|
||||||
"tag": "div",
|
"tag": "div",
|
||||||
@ -549,13 +557,16 @@ def _push_custom_paper_card(card: dict) -> tuple[bool, object]:
|
|||||||
def _push_event_card(event_type: str, trade: dict, result: dict, event_time: str = "") -> None:
|
def _push_event_card(event_type: str, trade: dict, result: dict, event_time: str = "") -> None:
|
||||||
symbol = str(trade.get("symbol") or "")
|
symbol = str(trade.get("symbol") or "")
|
||||||
short_symbol = symbol.replace("/USDT", "")
|
short_symbol = symbol.replace("/USDT", "")
|
||||||
|
side = normalize_side(result.get("side") or trade.get("side"))
|
||||||
|
side_label = _side_label(side)
|
||||||
if event_type == "open":
|
if event_type == "open":
|
||||||
_push_paper_card(
|
_push_paper_card(
|
||||||
event_type,
|
event_type,
|
||||||
symbol,
|
symbol,
|
||||||
f"交易开仓 - {short_symbol}",
|
f"交易开仓({side_label}) - {short_symbol}",
|
||||||
"blue",
|
"blue",
|
||||||
[
|
[
|
||||||
|
("方向", side_label),
|
||||||
("成交价", _fmt_price(result.get("entry_price"))),
|
("成交价", _fmt_price(result.get("entry_price"))),
|
||||||
("名义仓位", f"{_safe_float(result.get('notional_usdt')):.2f} USDT"),
|
("名义仓位", f"{_safe_float(result.get('notional_usdt')):.2f} USDT"),
|
||||||
("杠杆/保证金", f"{_safe_float(result.get('leverage')):.1f}x / {_safe_float(result.get('margin_usdt')):.2f} USDT"),
|
("杠杆/保证金", f"{_safe_float(result.get('leverage')):.1f}x / {_safe_float(result.get('margin_usdt')):.2f} USDT"),
|
||||||
@ -570,9 +581,10 @@ def _push_event_card(event_type: str, trade: dict, result: dict, event_time: str
|
|||||||
_push_paper_card(
|
_push_paper_card(
|
||||||
event_type,
|
event_type,
|
||||||
symbol,
|
symbol,
|
||||||
f"{title_prefix} - {short_symbol}",
|
f"{title_prefix}({side_label}) - {short_symbol}",
|
||||||
"red" if _safe_float(result.get("pnl_usdt")) < 0 else "green",
|
"red" if _safe_float(result.get("pnl_usdt")) < 0 else "green",
|
||||||
[
|
[
|
||||||
|
("方向", side_label),
|
||||||
("退出价", _fmt_price(result.get("exit_price"))),
|
("退出价", _fmt_price(result.get("exit_price"))),
|
||||||
("收益率", _fmt_pct(result.get("pnl_pct"))),
|
("收益率", _fmt_pct(result.get("pnl_pct"))),
|
||||||
("收益额", f"{_safe_float(result.get('pnl_usdt')):.2f} USDT"),
|
("收益额", f"{_safe_float(result.get('pnl_usdt')):.2f} USDT"),
|
||||||
@ -586,12 +598,13 @@ def _push_event_card(event_type: str, trade: dict, result: dict, event_time: str
|
|||||||
_push_paper_card(
|
_push_paper_card(
|
||||||
event_type,
|
event_type,
|
||||||
symbol,
|
symbol,
|
||||||
f"移动止盈{'启动' if event_type == 'trailing_activate' else '上移'} - {short_symbol}",
|
f"移动止盈{'启动' if event_type == 'trailing_activate' else '调整'}({side_label}) - {short_symbol}",
|
||||||
"yellow",
|
"yellow",
|
||||||
[
|
[
|
||||||
|
("方向", side_label),
|
||||||
("保护价", _fmt_price(result.get("trailing_stop"))),
|
("保护价", _fmt_price(result.get("trailing_stop"))),
|
||||||
("当前收益", _fmt_pct(result.get("pnl_pct"))),
|
("当前收益", _fmt_pct(result.get("pnl_pct"))),
|
||||||
("动作", "启动保护" if event_type == "trailing_activate" else "上移保护价"),
|
("动作", "启动保护" if event_type == "trailing_activate" else _side_action(side, "上移保护价", "下移保护价")),
|
||||||
],
|
],
|
||||||
"移动止盈用于锁定浮盈。",
|
"移动止盈用于锁定浮盈。",
|
||||||
event_time,
|
event_time,
|
||||||
@ -600,39 +613,45 @@ def _push_event_card(event_type: str, trade: dict, result: dict, event_time: str
|
|||||||
|
|
||||||
def _push_order_created_card(order: dict, event_time: str = "") -> None:
|
def _push_order_created_card(order: dict, event_time: str = "") -> None:
|
||||||
symbol = str(order.get("symbol") or "")
|
symbol = str(order.get("symbol") or "")
|
||||||
|
side = normalize_side(order.get("side"))
|
||||||
|
side_label = _side_label(side)
|
||||||
target = _safe_float(order.get("target_price"))
|
target = _safe_float(order.get("target_price"))
|
||||||
current = _safe_float(order.get("current_price_at_create"))
|
current = _safe_float(order.get("current_price_at_create"))
|
||||||
distance = round((current / target - 1) * 100, 2) if target and current else 0
|
distance = order_distance_pct(side, current, target) if target and current else 0
|
||||||
_push_paper_card(
|
_push_paper_card(
|
||||||
"paper_order_create",
|
"paper_order_create",
|
||||||
symbol,
|
symbol,
|
||||||
f"挂单创建 - {symbol.replace('/USDT', '')}",
|
f"挂单创建({side_label}) - {symbol.replace('/USDT', '')}",
|
||||||
"wathet",
|
"wathet",
|
||||||
[
|
[
|
||||||
|
("方向", side_label),
|
||||||
("目标价", _fmt_price(target)),
|
("目标价", _fmt_price(target)),
|
||||||
("当前价", _fmt_price(current)),
|
("当前价", _fmt_price(current)),
|
||||||
("距目标", _fmt_pct(distance)),
|
("距目标", _fmt_pct(distance)),
|
||||||
("有效期", order.get("expires_at") or "--"),
|
("有效期", order.get("expires_at") or "--"),
|
||||||
],
|
],
|
||||||
"等回踩机会已进入挂单,触价后进入持仓。",
|
_side_action(side, "等回踩机会已进入挂单,触价后进入持仓。", "等反抽机会已进入挂单,触价后进入持仓。"),
|
||||||
event_time,
|
event_time,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _push_order_filled_card(order: dict, result: dict, event_time: str = "") -> None:
|
def _push_order_filled_card(order: dict, result: dict, event_time: str = "") -> None:
|
||||||
symbol = str(order.get("symbol") or "")
|
symbol = str(order.get("symbol") or "")
|
||||||
|
side = normalize_side(result.get("side") or order.get("side"))
|
||||||
|
side_label = _side_label(side)
|
||||||
_push_paper_card(
|
_push_paper_card(
|
||||||
"paper_order_fill",
|
"paper_order_fill",
|
||||||
symbol,
|
symbol,
|
||||||
f"挂单成交并开仓 - {symbol.replace('/USDT', '')}",
|
f"挂单成交并开仓({side_label}) - {symbol.replace('/USDT', '')}",
|
||||||
"green",
|
"green",
|
||||||
[
|
[
|
||||||
|
("方向", side_label),
|
||||||
("挂单价", _fmt_price(order.get("target_price"))),
|
("挂单价", _fmt_price(order.get("target_price"))),
|
||||||
("成交价", _fmt_price(result.get("entry_price") or order.get("fill_price"))),
|
("成交价", _fmt_price(result.get("entry_price") or order.get("fill_price"))),
|
||||||
("名义仓位", f"{_safe_float(result.get('notional_usdt')):.2f} USDT"),
|
("名义仓位", f"{_safe_float(result.get('notional_usdt')):.2f} USDT"),
|
||||||
("来源", order.get("source_status") or "wait_pullback"),
|
("来源", order.get("source_status") or "wait_pullback"),
|
||||||
],
|
],
|
||||||
"价格触达理想入场位,挂单已转为持仓。",
|
_side_action(side, "价格触达理想回踩位,挂单已转为持仓。", "价格触达理想反抽位,挂单已转为持仓。"),
|
||||||
event_time,
|
event_time,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -808,6 +827,7 @@ def _open_trade(conn, rec: dict, current_price: float, event_time: str, config:
|
|||||||
result = {
|
result = {
|
||||||
"opened": True,
|
"opened": True,
|
||||||
"trade_id": trade_id,
|
"trade_id": trade_id,
|
||||||
|
"side": side,
|
||||||
"entry_price": entry_price,
|
"entry_price": entry_price,
|
||||||
"qty": qty,
|
"qty": qty,
|
||||||
"notional_usdt": notional,
|
"notional_usdt": notional,
|
||||||
@ -1258,7 +1278,7 @@ def _close_trade(conn, trade: dict, current_price: float, reason: str, event_tim
|
|||||||
_push_event_card(
|
_push_event_card(
|
||||||
"close",
|
"close",
|
||||||
trade,
|
trade,
|
||||||
{"exit_price": exit_price, "exit_reason": reason, "pnl_pct": pnl_pct, "pnl_usdt": pnl_usdt},
|
{"side": side, "exit_price": exit_price, "exit_reason": reason, "pnl_pct": pnl_pct, "pnl_usdt": pnl_usdt},
|
||||||
now,
|
now,
|
||||||
)
|
)
|
||||||
return {"closed": True, "trade_id": trade["id"], "exit_reason": reason, "pnl_pct": pnl_pct, "pnl_usdt": pnl_usdt}
|
return {"closed": True, "trade_id": trade["id"], "exit_reason": reason, "pnl_pct": pnl_pct, "pnl_usdt": pnl_usdt}
|
||||||
@ -1313,6 +1333,7 @@ def _apply_position_health_guard(
|
|||||||
|
|
||||||
def _update_trailing_stop(conn, trade: dict, current_price: float, pnl_pct: float, event_time: str) -> tuple[float, dict]:
|
def _update_trailing_stop(conn, trade: dict, current_price: float, pnl_pct: float, event_time: str) -> tuple[float, dict]:
|
||||||
cfg = _trailing_config()
|
cfg = _trailing_config()
|
||||||
|
side = normalize_side(trade.get("side"))
|
||||||
current_trail = _safe_float(trade.get("trailing_stop"))
|
current_trail = _safe_float(trade.get("trailing_stop"))
|
||||||
decision = evaluate_trailing_stop(position=trade, current_price=current_price, pnl_pct=pnl_pct, config=cfg).as_dict()
|
decision = evaluate_trailing_stop(position=trade, current_price=current_price, pnl_pct=pnl_pct, config=cfg).as_dict()
|
||||||
if not decision.get("activated") and not decision.get("moved"):
|
if not decision.get("activated") and not decision.get("moved"):
|
||||||
@ -1358,7 +1379,7 @@ def _update_trailing_stop(conn, trade: dict, current_price: float, pnl_pct: floa
|
|||||||
},
|
},
|
||||||
event_time,
|
event_time,
|
||||||
)
|
)
|
||||||
_push_event_card(event_type, trade, {"trailing_stop": new_trail, "pnl_pct": pnl_pct}, event_time)
|
_push_event_card(event_type, trade, {"side": side, "trailing_stop": new_trail, "pnl_pct": pnl_pct}, event_time)
|
||||||
return new_trail, {
|
return new_trail, {
|
||||||
"activated": bool(decision.get("activated")),
|
"activated": bool(decision.get("activated")),
|
||||||
"moved": bool(decision.get("moved")),
|
"moved": bool(decision.get("moved")),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user