1
This commit is contained in:
parent
b732324d63
commit
1e927521b7
@ -8,6 +8,7 @@ from datetime import datetime, timedelta
|
||||
|
||||
from app.config.system_config import paper_trading_config
|
||||
from app.db.schema import get_conn
|
||||
from app.integrations.feishu_push import push_card
|
||||
|
||||
|
||||
def _now() -> str:
|
||||
@ -174,6 +175,43 @@ def _record_event(conn, trade_id: int, rec_id: int, symbol: str, event_type: str
|
||||
)
|
||||
|
||||
|
||||
def _push_event_card(event_type: str, trade: dict, result: dict, event_time: str = "") -> None:
|
||||
try:
|
||||
symbol = str(trade.get("symbol") or "")
|
||||
title = {
|
||||
"open": f"📒 模拟交易开仓 — {symbol.replace('/USDT', '')}",
|
||||
"close": f"🏁 模拟交易平仓 — {symbol.replace('/USDT', '')}",
|
||||
"trailing_activate": f"🛡️ 模拟交易移动止盈启动 — {symbol.replace('/USDT', '')}",
|
||||
"trailing_move": f"🛡️ 模拟交易移动止盈上移 — {symbol.replace('/USDT', '')}",
|
||||
}.get(event_type)
|
||||
if not title:
|
||||
return
|
||||
card = {
|
||||
"config": {"wide_screen_mode": True},
|
||||
"header": {
|
||||
"template": "blue" if event_type == "open" else ("yellow" if event_type.startswith("trailing") else "red"),
|
||||
"title": {"tag": "plain_text", "content": title},
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"tag": "div",
|
||||
"text": {
|
||||
"tag": "lark_md",
|
||||
"content": (
|
||||
f"**币种**: {symbol}\n"
|
||||
f"**事件**: {event_type}\n"
|
||||
f"**成交价**: ${result.get('entry_price') or result.get('exit_price') or result.get('trailing_stop') or trade.get('current_price') or 0}\n"
|
||||
f"**时间**: {event_time or ''}"
|
||||
),
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
push_card(card)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _open_trade(conn, rec: dict, current_price: float, event_time: str) -> dict:
|
||||
rec_id = _safe_int(rec.get("id"))
|
||||
symbol = str(rec.get("symbol") or "").strip().upper()
|
||||
@ -246,6 +284,7 @@ def _open_trade(conn, rec: dict, current_price: float, event_time: str) -> dict:
|
||||
},
|
||||
now,
|
||||
)
|
||||
_push_event_card("open", {"symbol": symbol}, {"entry_price": entry_price}, now)
|
||||
return {
|
||||
"opened": True,
|
||||
"trade_id": trade_id,
|
||||
@ -307,6 +346,7 @@ def _close_trade(conn, trade: dict, current_price: float, reason: str, event_tim
|
||||
{"realized_pnl_usdt": pnl_usdt, "fee_usdt": total_fee},
|
||||
now,
|
||||
)
|
||||
_push_event_card("close", trade, {"exit_price": exit_price}, now)
|
||||
return {"closed": True, "trade_id": trade["id"], "exit_reason": reason, "pnl_pct": pnl_pct, "pnl_usdt": pnl_usdt}
|
||||
|
||||
|
||||
@ -352,6 +392,7 @@ def _update_trailing_stop(conn, trade: dict, current_price: float, pnl_pct: floa
|
||||
},
|
||||
event_time,
|
||||
)
|
||||
_push_event_card(event_type, trade, {"trailing_stop": new_trail}, event_time)
|
||||
return new_trail, {
|
||||
"activated": activated,
|
||||
"moved": moved,
|
||||
|
||||
@ -4,27 +4,14 @@ Separates eligibility / cooldown decisions from payload rendering and transport.
|
||||
"""
|
||||
|
||||
from app.db.recommendation_queries import log_push, should_push
|
||||
from app.integrations.feishu_push import push_altcoin_tp_sl_alert, push_recommendation_state_alert
|
||||
from app.integrations.feishu_push import build_trade_action_card, push_card
|
||||
|
||||
|
||||
def push_mainline_state_update(symbol: str, rec_id: int, mainline_item: dict, title_prefix: str | None = None, entry_push_type: str = "entry", watch_push_type: str = "watch_pool") -> bool:
|
||||
if not mainline_item or mainline_item.get("execution_status") not in ("buy_now", "wait_pullback"):
|
||||
status = mainline_item.get("execution_status") if mainline_item else "missing"
|
||||
print(f"[push] skip {symbol}: mainline_status={status}")
|
||||
return False
|
||||
|
||||
push_type = entry_push_type if mainline_item.get("execution_status") == "buy_now" else watch_push_type
|
||||
action = mainline_item.get("action_status", "")
|
||||
if not should_push(symbol, push_type, action):
|
||||
print(f"⏭ 跳过推送({symbol}): {push_type}/{action} 12h冷却中")
|
||||
return False
|
||||
|
||||
ok, resp = push_recommendation_state_alert(mainline_item, title_prefix=title_prefix)
|
||||
if ok:
|
||||
log_push(symbol, push_type, action, rec_id=rec_id)
|
||||
return True
|
||||
|
||||
print(f"[push] failed {symbol}: {resp}")
|
||||
"""主链路状态只记录,不再飞书推送。"""
|
||||
status = mainline_item.get("execution_status") if mainline_item else "missing"
|
||||
action = mainline_item.get("action_status", "") if mainline_item else ""
|
||||
print(f"[push] skip {symbol}: mainline notifications disabled (status={status}, action={action})")
|
||||
return False
|
||||
|
||||
|
||||
@ -34,7 +21,7 @@ def push_trade_action_update(symbol: str, rec_id: int, state_decision: dict, fin
|
||||
if not should_push(symbol, push_type, final_action):
|
||||
print(f"⏭ 跳过推送({symbol}): {push_type}/{final_action} 12h冷却中")
|
||||
return False
|
||||
ok, resp = push_altcoin_tp_sl_alert(
|
||||
card = build_trade_action_card(
|
||||
state_decision["push_symbol"],
|
||||
state_decision["push_current_price"],
|
||||
state_decision["push_entry_price"],
|
||||
@ -45,6 +32,10 @@ def push_trade_action_update(symbol: str, rec_id: int, state_decision: dict, fin
|
||||
state_decision.get("tp1", 0),
|
||||
state_decision.get("tp2", 0),
|
||||
)
|
||||
if isinstance(card, tuple):
|
||||
ok, resp = card
|
||||
else:
|
||||
ok, resp = push_card(card)
|
||||
if ok:
|
||||
log_push(symbol, push_type, final_action, rec_id=rec_id)
|
||||
return True
|
||||
|
||||
@ -30,13 +30,14 @@ from app.db.altcoin_db import (
|
||||
update_latest_price_cache,
|
||||
)
|
||||
from app.db.paper_trading import sync_recommendation as sync_paper_trade
|
||||
from app.integrations.push_orchestrator import push_trade_action_update
|
||||
from app.core.pa_engine import (
|
||||
calc_atr, full_pa_analysis, detect_trend_exhaustion,
|
||||
analyze_entry_point,
|
||||
)
|
||||
from app.integrations.push_orchestrator import push_trade_action_update
|
||||
from app.config.config_loader import load_rules
|
||||
from app.core.opportunity_lifecycle import apply_entry_quality_gate
|
||||
from app.db.paper_trading import sync_recommendation as sync_paper_trade
|
||||
|
||||
exchange = ccxt.binance({"enableRateLimit": True})
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
@ -337,7 +338,8 @@ def track_prices():
|
||||
current_price,
|
||||
event_time=datetime.now().isoformat(),
|
||||
)
|
||||
push_trade_action_update(symbol, rec["id"], state_decision, final_action, push_type="entry")
|
||||
if paper_result.get("opened") or paper_result.get("closed") or paper_result.get("activated") or paper_result.get("moved"):
|
||||
print(f" {symbol}: paper trading event -> {paper_result}")
|
||||
|
||||
results.append({
|
||||
"symbol": symbol,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user