Files
crypto_monitor/manual_trading_hub/hub_ai/archive_quote.py
T
2026-06-11 21:10:39 +08:00

117 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""内照明心复盘语录 → 交易教练点评。"""
from __future__ import annotations
from typing import Any
from hub_ai.chat import _is_ai_error_reply
from hub_ai.client import generate_text, model_label
from hub_ai.config import CHAT_MAX_CONTINUATIONS, CHAT_MAX_OUTPUT_TOKENS, CHAT_TEMPERATURE
from hub_ai.prompts import CHAT_SYSTEM, build_archive_quote_review_prompt
from hub_ai.store import CHAT_BOT_TRADING, append_chat_message, create_new_session, list_chat_sessions
from hub_symbol_archive_lib import list_daily_trades
def _tag_label(tag: str) -> str:
t = (tag or "").strip().lower()
if t == "sick":
return "犯病"
if t == "emotion":
return "情绪化"
return t or ""
def _fmt_pnl(v: Any) -> str:
try:
n = float(v or 0)
except (TypeError, ValueError):
return ""
sign = "+" if n > 0 else ""
return f"{sign}{n:.2f}U"
def format_archive_trades_for_ai(payload: dict[str, Any]) -> str:
trades = payload.get("trades") or []
stats = payload.get("stats") or {}
lines = [
(
f"统计:开仓 {int(stats.get('open_count') or 0)} 笔,"
f"犯病 {int(stats.get('sick_count') or 0)} 笔,"
f"盈亏合计 {_fmt_pnl(stats.get('pnl_total'))}"
f"剔除犯病盈亏 {_fmt_pnl(stats.get('pnl_ex_sick'))}"
)
]
if not trades:
lines.append("(该日无交易记录)")
return "\n".join(lines)
for i, t in enumerate(trades, 1):
ex = str(t.get("exchange_key") or t.get("account_exchange_key") or "")
sym = str(t.get("symbol") or "")
direction = str(t.get("direction") or "")
opened = str(t.get("opened_at") or "")
closed = str(t.get("closed_at") or "")
hold = str(t.get("hold_minutes_text") or t.get("hold_minutes") or "")
result = str(t.get("result") or "")
pnl = _fmt_pnl(t.get("pnl_amount"))
entry = str(t.get("entry_type") or t.get("entry_reason") or t.get("monitor_type") or "")
tag = _tag_label(str(t.get("behavior_tag") or ""))
note = str(t.get("note") or "").strip()
line = (
f"{i}. {ex} | {sym} | {direction} | 开仓类型 {entry} | "
f"{opened} | 平 {closed} | 持仓 {hold} | 结果 {result} | "
f"盈亏 {pnl} | 标签 {tag}"
)
if note:
line += f" | 备注 {note}"
lines.append(line)
return "\n".join(lines)
def send_archive_quote_review(
*,
quote_date: str,
content: str,
) -> dict[str, Any]:
text = (content or "").strip()
if not text:
return {"ok": False, "msg": "语录内容不能为空"}
day = (quote_date or "").strip()[:10]
if not day:
return {"ok": False, "msg": "语录日期无效"}
session = create_new_session(
trading_day=day,
title=f"复盘 {day}",
bot_mode=CHAT_BOT_TRADING,
)
sid = session["id"]
archive_payload = list_daily_trades(trading_day=day, period="today")
archive_trades_text = format_archive_trades_for_ai(archive_payload)
append_chat_message(sid, "user", text)
user_prompt = build_archive_quote_review_prompt(
quote_date=day,
archive_trades_text=archive_trades_text,
user_message=text,
)
reply = generate_text(
system=CHAT_SYSTEM,
user=user_prompt,
temperature=CHAT_TEMPERATURE,
max_tokens=CHAT_MAX_OUTPUT_TOKENS,
max_continuations=CHAT_MAX_CONTINUATIONS,
)
if _is_ai_error_reply(reply):
return {"ok": False, "msg": reply, "session_id": sid}
session = append_chat_message(sid, "assistant", reply)
return {
"ok": True,
"trading_day": day,
"session": session,
"sessions": list_chat_sessions(),
"reply": reply,
"model": model_label(),
}