From c34d1742a648cde558daad40b70a0f2f90767122 Mon Sep 17 00:00:00 2001
From: hazeone <709547807@qq.com>
Date: Thu, 30 Oct 2025 16:03:33 +0800
Subject: [PATCH 1/4] optimize the autotrading agent output
---
.../agents/auto_trading_agent/agent.py | 22 +++++++---------
.../agents/auto_trading_agent/formatters.py | 25 ++++++++++---------
2 files changed, 22 insertions(+), 25 deletions(-)
diff --git a/python/valuecell/agents/auto_trading_agent/agent.py b/python/valuecell/agents/auto_trading_agent/agent.py
index 79663dba1..f78d65699 100644
--- a/python/valuecell/agents/auto_trading_agent/agent.py
+++ b/python/valuecell/agents/auto_trading_agent/agent.py
@@ -548,35 +548,31 @@ def _get_instance_status_component_data(
output = []
# Header
- output.append(f"š **Trading Portfolio Status** - {instance_id}")
- output.append("\n**Instance Configuration**")
+ output.append("š **Instance Configuration**\n")
output.append(f"- Model: `{config.agent_model}`")
output.append(f"- Symbols: {', '.join(config.crypto_symbols)}")
output.append(
- f"- Status: {'š¢ Active' if instance['active'] else 'š“ Stopped'}"
+ f"- Status: {'š¢ Active' if instance['active'] else 'š“ Stopped'}\n"
)
# Portfolio Summary Section
- output.append("\nš° **Portfolio Summary**")
- output.append("\n**Overall Performance**")
- output.append(f"- Initial Capital: `${config.initial_capital:,.2f}`")
- output.append(f"- Current Value: `${portfolio_value:,.2f}`")
+ output.append("š° **Portfolio Summary**\n")
+ output.append("**Overall Performance**\n")
+ output.append(f"- Current Value: `${portfolio_value:,.2f}`\n")
pnl_emoji = "š¢" if total_pnl >= 0 else "š“"
pnl_sign = "+" if total_pnl >= 0 else ""
output.append(
- f"- Total P&L: {pnl_emoji} **{pnl_sign}${total_pnl:,.2f}** ({pnl_sign}{pnl_pct:.2f}%)"
+ f"- Total P&L: {pnl_emoji} **{pnl_sign}${total_pnl:,.2f}** ({pnl_sign}{pnl_pct:.2f}%)\n"
)
-
- output.append("\n**Cash Position**")
- output.append(f"- Available Cash: `${available_cash:,.2f}`")
+ output.append(f"- Available Cash: `${available_cash:,.2f}`\n")
# Current Positions Section
- output.append(f"\nš **Current Positions ({len(executor.positions)})**")
+ output.append(f"š **Current Positions ({len(executor.positions)})**")
if executor.positions:
output.append(
- "\n| Symbol | Type | Quantity | Avg Price | Current Price | Position Value | Unrealized P&L |"
+ "\n| Symbol | Type | Quantity | Avg | Current | Position | P&L |"
)
output.append(
"|--------|------|----------|-----------|---------------|----------------|----------------|"
diff --git a/python/valuecell/agents/auto_trading_agent/formatters.py b/python/valuecell/agents/auto_trading_agent/formatters.py
index 9e2e9a8eb..79a6e89f8 100644
--- a/python/valuecell/agents/auto_trading_agent/formatters.py
+++ b/python/valuecell/agents/auto_trading_agent/formatters.py
@@ -35,11 +35,11 @@ def format_trade_notification(
if action == "opened":
message = (
- f"{agent_name} opened a {trade_type} position on {symbol}!\n"
- f"{timestamp.strftime('%m/%d, %I:%M %p')}\n"
- f"Price: ${trade_details['entry_price']:,.2f}\n"
- f"Quantity: {trade_details['quantity']:.4f}\n"
- f"Notional: ${trade_details['notional']:,.2f}"
+ f"**{agent_name}** opened a **{trade_type}** position on **{symbol}**!\n\n"
+ f"š
{timestamp.strftime('%m/%d, %I:%M %p')}\n"
+ f"**Price:** `${trade_details['entry_price']:,.2f}`\n"
+ f"**Quantity:** `{trade_details['quantity']:.4f}`\n"
+ f"**Notional:** `${trade_details['notional']:,.2f}`"
)
else: # closed
hours = int(trade_details["holding_time"].total_seconds() // 3600)
@@ -48,15 +48,16 @@ def format_trade_notification(
)
pnl = trade_details["pnl"]
pnl_sign = "+" if pnl >= 0 else ""
+ pnl_emoji = "š¢" if pnl >= 0 else "š“"
message = (
- f"{agent_name} completed a {trade_type} trade on {symbol}!\n"
- f"{timestamp.strftime('%m/%d, %I:%M %p')}\n"
- f"Price: ${trade_details['entry_price']:,.2f} ā ${trade_details['exit_price']:,.2f}\n"
- f"Quantity: {trade_details['quantity']:.4f}\n"
- f"Notional: ${trade_details['entry_notional']:,.2f} ā ${trade_details['exit_notional']:,.2f}\n"
- f"Holding time: {hours}H {minutes}M\n"
- f"Net P&L: {pnl_sign}${pnl:,.2f}"
+ f"**{agent_name}** completed a **{trade_type}** trade on **{symbol}**!\n\n"
+ f"š
{timestamp.strftime('%m/%d, %I:%M %p')}\n"
+ f"**Price:** `${trade_details['entry_price']:,.2f}` ā `${trade_details['exit_price']:,.2f}`\n"
+ f"**Quantity:** `{trade_details['quantity']:.4f}`\n"
+ f"**Notional:** `${trade_details['entry_notional']:,.2f}` ā `${trade_details['exit_notional']:,.2f}`\n"
+ f"**Holding time:** `{hours}H {minutes}M`\n"
+ f"**Net P&L:** {pnl_emoji} **{pnl_sign}${pnl:,.2f}**"
)
return message
From 50d985338f62dacb835d8776dc954f3a22a446f7 Mon Sep 17 00:00:00 2001
From: hazeone <709547807@qq.com>
Date: Thu, 30 Oct 2025 18:35:29 +0800
Subject: [PATCH 2/4] reformat auto trading agent output
---
.../agents/auto_trading_agent/agent.py | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/python/valuecell/agents/auto_trading_agent/agent.py b/python/valuecell/agents/auto_trading_agent/agent.py
index f78d65699..8da76e090 100644
--- a/python/valuecell/agents/auto_trading_agent/agent.py
+++ b/python/valuecell/agents/auto_trading_agent/agent.py
@@ -572,10 +572,10 @@ def _get_instance_status_component_data(
if executor.positions:
output.append(
- "\n| Symbol | Type | Quantity | Avg | Current | Position | P&L |"
+ "\n| Symbol | Type | **Position**/Quantity | **Current**/Avg | **P&L** |"
)
output.append(
- "|--------|------|----------|-----------|---------------|----------------|----------------|"
+ "|--------|------|---------|--------|--------|"
)
for symbol, pos in executor.positions.items():
@@ -599,15 +599,14 @@ def _get_instance_status_component_data(
)
position_value = pos.notional + unrealized_pnl
- # Format row
- pnl_emoji = "š¢" if unrealized_pnl >= 0 else "š“"
+ # Format row with merged columns
pnl_sign = "+" if unrealized_pnl >= 0 else ""
output.append(
f"| **{symbol}** | {pos.trade_type.value.upper()} | "
- f"{abs(pos.quantity):.4f} | ${pos.entry_price:,.2f} | "
- f"${current_price:,.2f} | ${position_value:,.2f} | "
- f"{pnl_emoji} {pnl_sign}${unrealized_pnl:,.2f} |"
+ f"**${position_value:,.2f}**
{abs(pos.quantity):.4f} | "
+ f"**${current_price:,.2f}**
${pos.entry_price:,.2f} | "
+ f"**{pnl_sign}${unrealized_pnl:,.2f}** |"
)
except Exception as e:
@@ -615,8 +614,9 @@ def _get_instance_status_component_data(
# Fallback display with entry price only
output.append(
f"| **{symbol}** | {pos.trade_type.value.upper()} | "
- f"{abs(pos.quantity):.4f} | ${pos.entry_price:,.2f} | "
- f"N/A | ${pos.notional:,.2f} | N/A |"
+ f"**${pos.notional:,.2f}**
{abs(pos.quantity):.4f} | "
+ f"**${pos.entry_price:,.2f}**
${pos.entry_price:,.2f} | "
+ f"**N/A** |"
)
else:
output.append("\n*No open positions*")
From 57d9410d094579123962ee3ae71a39cb9958ddc6 Mon Sep 17 00:00:00 2001
From: hazeone <709547807@qq.com>
Date: Thu, 30 Oct 2025 18:52:58 +0800
Subject: [PATCH 3/4] format as markdown
---
.../valuecell/agents/auto_trading_agent/agent.py | 6 ++----
.../agents/auto_trading_agent/formatters.py | 16 ++++++++--------
2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/python/valuecell/agents/auto_trading_agent/agent.py b/python/valuecell/agents/auto_trading_agent/agent.py
index 8da76e090..aa46892e4 100644
--- a/python/valuecell/agents/auto_trading_agent/agent.py
+++ b/python/valuecell/agents/auto_trading_agent/agent.py
@@ -267,7 +267,7 @@ async def _process_trading_instance(
)
trade_message = FilteredCardPushNotificationComponentData(
title=f"{config.agent_model} Trade",
- data=f"š° **Trade Executed:**\n{trade_message_text}\n",
+ data=f"š° **Trade Executed**\n\n{trade_message_text}\n",
filters=[config.agent_model],
table_title="Trade Detail",
create_time=datetime.now(timezone.utc).strftime(
@@ -574,9 +574,7 @@ def _get_instance_status_component_data(
output.append(
"\n| Symbol | Type | **Position**/Quantity | **Current**/Avg | **P&L** |"
)
- output.append(
- "|--------|------|---------|--------|--------|"
- )
+ output.append("|--------|------|---------|--------|--------|")
for symbol, pos in executor.positions.items():
try:
diff --git a/python/valuecell/agents/auto_trading_agent/formatters.py b/python/valuecell/agents/auto_trading_agent/formatters.py
index 79a6e89f8..6663b7782 100644
--- a/python/valuecell/agents/auto_trading_agent/formatters.py
+++ b/python/valuecell/agents/auto_trading_agent/formatters.py
@@ -36,9 +36,9 @@ def format_trade_notification(
if action == "opened":
message = (
f"**{agent_name}** opened a **{trade_type}** position on **{symbol}**!\n\n"
- f"š
{timestamp.strftime('%m/%d, %I:%M %p')}\n"
- f"**Price:** `${trade_details['entry_price']:,.2f}`\n"
- f"**Quantity:** `{trade_details['quantity']:.4f}`\n"
+ f"š
{timestamp.strftime('%m/%d, %I:%M %p')}\n\n"
+ f"**Price:** `${trade_details['entry_price']:,.2f}`\n\n"
+ f"**Quantity:** `{trade_details['quantity']:.4f}`\n\n"
f"**Notional:** `${trade_details['notional']:,.2f}`"
)
else: # closed
@@ -52,11 +52,11 @@ def format_trade_notification(
message = (
f"**{agent_name}** completed a **{trade_type}** trade on **{symbol}**!\n\n"
- f"š
{timestamp.strftime('%m/%d, %I:%M %p')}\n"
- f"**Price:** `${trade_details['entry_price']:,.2f}` ā `${trade_details['exit_price']:,.2f}`\n"
- f"**Quantity:** `{trade_details['quantity']:.4f}`\n"
- f"**Notional:** `${trade_details['entry_notional']:,.2f}` ā `${trade_details['exit_notional']:,.2f}`\n"
- f"**Holding time:** `{hours}H {minutes}M`\n"
+ f"š
{timestamp.strftime('%m/%d, %I:%M %p')}\n\n"
+ f"**Price:** `${trade_details['entry_price']:,.2f}` ā `${trade_details['exit_price']:,.2f}`\n\n"
+ f"**Quantity:** `{trade_details['quantity']:.4f}`\n\n"
+ f"**Notional:** `${trade_details['entry_notional']:,.2f}` ā `${trade_details['exit_notional']:,.2f}`\n\n"
+ f"**Holding time:** `{hours}H {minutes}M`\n\n"
f"**Net P&L:** {pnl_emoji} **{pnl_sign}${pnl:,.2f}**"
)
From 6824fa82925c910ce99b74f88b821e5c9bd63edb Mon Sep 17 00:00:00 2001
From: hazeone <709547807@qq.com>
Date: Thu, 30 Oct 2025 19:14:28 +0800
Subject: [PATCH 4/4] add time formatter
---
.../agents/auto_trading_agent/formatters.py | 79 ++++++++++++++++++-
1 file changed, 75 insertions(+), 4 deletions(-)
diff --git a/python/valuecell/agents/auto_trading_agent/formatters.py b/python/valuecell/agents/auto_trading_agent/formatters.py
index 6663b7782..12cbed843 100644
--- a/python/valuecell/agents/auto_trading_agent/formatters.py
+++ b/python/valuecell/agents/auto_trading_agent/formatters.py
@@ -5,6 +5,7 @@
from datetime import datetime, timezone
from typing import Any, Dict, Optional
+from ...utils.i18n_utils import convert_timezone, get_current_timezone
from .models import Position, TechnicalIndicators, TradeAction, TradeType
logger = logging.getLogger(__name__)
@@ -13,6 +14,63 @@
class MessageFormatter:
"""Formats various messages and notifications"""
+ @staticmethod
+ def _convert_and_format_timestamp(
+ dt: datetime, format_str: str = "%m/%d, %I:%M %p", include_tz: bool = False
+ ) -> str:
+ """
+ Convert timestamp to user's timezone and format it.
+
+ Args:
+ dt: DateTime to convert and format
+ format_str: Format string for strftime
+ include_tz: Whether to include timezone abbreviation
+
+ Returns:
+ Formatted timestamp string
+ """
+ try:
+ # Get user's configured timezone
+ user_tz = get_current_timezone()
+
+ # Convert from UTC to user's timezone
+ # Assume input is UTC if no timezone info
+ if dt.tzinfo is None:
+ dt = datetime(
+ dt.year,
+ dt.month,
+ dt.day,
+ dt.hour,
+ dt.minute,
+ dt.second,
+ tzinfo=timezone.utc,
+ )
+
+ converted_dt = convert_timezone(dt, "UTC", user_tz)
+
+ # Format the datetime
+ formatted = converted_dt.strftime(format_str)
+
+ # Optionally append timezone info
+ if include_tz:
+ formatted += f" ({user_tz})"
+
+ return formatted
+ except Exception as e:
+ logger.warning(f"Failed to convert timezone: {e}, using UTC")
+ # Fallback to UTC format
+ if dt.tzinfo is None:
+ dt = datetime(
+ dt.year,
+ dt.month,
+ dt.day,
+ dt.hour,
+ dt.minute,
+ dt.second,
+ tzinfo=timezone.utc,
+ )
+ return dt.strftime(format_str)
+
@staticmethod
def format_trade_notification(
trade_details: Dict[str, Any], agent_name: str = "AutoTrading"
@@ -33,10 +91,13 @@ def format_trade_notification(
trade_type = trade_details["trade_type"]
timestamp = trade_details["timestamp"]
+ # Convert timestamp to user's timezone
+ formatted_time = MessageFormatter._convert_and_format_timestamp(timestamp)
+
if action == "opened":
message = (
f"**{agent_name}** opened a **{trade_type}** position on **{symbol}**!\n\n"
- f"š
{timestamp.strftime('%m/%d, %I:%M %p')}\n\n"
+ f"š
{formatted_time}\n\n"
f"**Price:** `${trade_details['entry_price']:,.2f}`\n\n"
f"**Quantity:** `{trade_details['quantity']:.4f}`\n\n"
f"**Notional:** `${trade_details['notional']:,.2f}`"
@@ -52,7 +113,7 @@ def format_trade_notification(
message = (
f"**{agent_name}** completed a **{trade_type}** trade on **{symbol}**!\n\n"
- f"š
{timestamp.strftime('%m/%d, %I:%M %p')}\n\n"
+ f"š
{formatted_time}\n\n"
f"**Price:** `${trade_details['entry_price']:,.2f}` ā `${trade_details['exit_price']:,.2f}`\n\n"
f"**Quantity:** `{trade_details['quantity']:.4f}`\n\n"
f"**Notional:** `${trade_details['entry_notional']:,.2f}` ā `${trade_details['exit_notional']:,.2f}`\n\n"
@@ -107,9 +168,14 @@ def format_portfolio_notification(
"data": {"Portfolio": portfolio_value},
}
+ # Convert timestamp to user's timezone for display
+ formatted_time = MessageFormatter._convert_and_format_timestamp(
+ timestamp, format_str="%m/%d, %I:%M %p", include_tz=True
+ )
+
display_message = (
f"š° Portfolio Update\n"
- f"Time: {timestamp.strftime('%m/%d, %I:%M %p UTC')}\n"
+ f"Time: {formatted_time}\n"
f"Total Value: ${portfolio_value:,.2f}\n"
f"Open Positions: {positions_count}\n"
f"Available Capital: ${current_capital:,.2f}"
@@ -147,6 +213,11 @@ def format_market_analysis_notification(
try:
timestamp = datetime.now(timezone.utc)
+ # Convert timestamp to user's timezone for display
+ formatted_time = MessageFormatter._convert_and_format_timestamp(
+ timestamp, format_str="%m/%d, %I:%M %p", include_tz=True
+ )
+
# Format action with emoji
action_emoji = {
TradeAction.BUY: "š¢",
@@ -156,7 +227,7 @@ def format_market_analysis_notification(
message = (
f"š **Market Analysis - {symbol}**\n"
- f"Time: {timestamp.strftime('%m/%d, %I:%M %p UTC')}\n\n"
+ f"Time: {formatted_time}\n\n"
f"**Current Price:** ${indicators.close_price:,.2f}\n"
f"**Decision:** {action_emoji.get(action, '')} {action.value.upper()}"
)