fix(telegram): /status shows auto_trade+paper_mode, adopt:dup edits message

Bug 1: /status didn't show auto_trade or paper_mode — the two most
important trading states for Pro users. Added a trading block that
queries the Subscription row (only when wallet-linked) and shows:
  Auto-Trade: ON/OFF, Mode: Paper/Live, Circuit breaker: clear/tripped.

Bug 2: adopt:dup callback (tapping an 'already managed' position in the
/adopt picker) answered the spinner but left the picker message stuck
with no guidance. Now edits the message in place: explains the position
is already managed and shows /release commands. Button no longer
results in a visually broken UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
k
2026-05-29 23:42:39 +08:00
parent fd2e61dc48
commit e2c00937b5
+39 -4
View File
@@ -393,6 +393,15 @@ async def _cmd_status(chat_id: int) -> None:
b = (await db.execute(
select(TelegramBinding).where(TelegramBinding.chat_id == chat_id)
)).scalar_one_or_none()
# Also fetch the subscription if the binding is wallet-linked, so we
# can show auto_trade + paper_mode — the two most important trading
# states that were previously invisible in /status.
sub = None
if b and b.wallet_address:
sub = (await db.execute(
select(Subscription).where(Subscription.wallet_address == b.wallet_address)
)).scalar_one_or_none()
if not b:
await send_message(chat_id,
"Not subscribed yet. Send /start to begin (no wallet required).")
@@ -418,6 +427,23 @@ async def _cmd_status(chat_id: int) -> None:
f"🟢 ON @ {b.digest_hour_utc:02d}:00 UTC"
if b.digest_enabled else "🔴 OFF"
)
# Pro-only trading state block — only shown when wallet-linked.
trading_block = ""
if sub:
auto = "🟢 ON" if sub.auto_trade else "🔴 OFF"
mode = "📝 Paper" if sub.paper_mode else "💰 Live"
cb_line = ""
if sub.circuit_breaker_tripped_at:
cb_line = f"\n🚨 Circuit breaker: tripped ({sub.circuit_breaker_reason or 'risk limit'})"
else:
cb_line = "\n✓ Circuit breaker: clear"
trading_block = (
f"\n\n<b>— Auto-Trader —</b>\n"
f"Auto-Trade: {auto}\n"
f"Mode: {mode}{cb_line}"
)
await send_message(
chat_id,
f"📡 <b>Status</b>\n\n"
@@ -425,7 +451,8 @@ async def _cmd_status(chat_id: int) -> None:
f"Alerts: {on}\n"
f"Sources: {src_line}\n"
f"Min confidence: {b.min_confidence}{mute}\n"
f"Daily brief: {digest_state}\n\n"
f"Daily brief: {digest_state}"
f"{trading_block}\n\n"
f"Sent: {b.total_alerts_sent} · Failed: {b.total_alerts_failed}\n\n"
f"Toggle anything with /trump /btc /funding /kol /conf /quiet "
f"/digest /digest_time — send /help for the full list.",
@@ -787,9 +814,17 @@ async def _handle_callback(cb: dict) -> None:
await answer_callback(cb_id)
return
if sub == "dup":
await answer_callback(cb_id,
"This position is already managed.",
show_alert=True)
# Asset is already adopted — tell the user how to release,
# and also edit the picker message so the UI doesn't stay stuck.
asset_dup = parts[2] if len(parts) > 2 else "this position"
await edit_message(
chat_id, msg_id,
f"✅ <b>{asset_dup}</b> is already under bot management.\n\n"
f"To stop managing it and take back manual control:\n"
f"<code>/release</code> — pick from list\n"
f"or send <code>/release &lt;trade_id&gt;</code> directly."
)
await answer_callback(cb_id, "Already managed — see message.", show_alert=False)
return
if sub == "pick" and len(parts) == 3:
asset = parts[2]