Skip to content

Commit a167221

Browse files
Balance Button Cross-Asset Compatibility, PERFORMANCE FIX: Momentum Check Optimization, Diagnose Function Cross-Asset Support
1 parent 4ca653e commit a167221

File tree

1 file changed

+152
-58
lines changed

1 file changed

+152
-58
lines changed

Trading-Automation/trading_automation.py

Lines changed: 152 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,9 @@ def add_symbol(self, symbol):
340340
return
341341
try:
342342
if symbol not in self.symbols_to_monitor:
343-
# Validate symbol format
344-
if not symbol or not isinstance(symbol, str) or not symbol.endswith('USDC'):
345-
print(f"[WEBSOCKET] ❌ Invalid symbol format: {symbol}")
343+
# Validate symbol format - support ALLOWED_SYMBOLS including BTCETH
344+
if not symbol or not isinstance(symbol, str) or symbol not in ALLOWED_SYMBOLS:
345+
print(f"[WEBSOCKET] ❌ Symbol not in ALLOWED_SYMBOLS: {symbol}")
346346
return
347347
# Add to monitoring list
348348
self.symbols_to_monitor.add(symbol)
@@ -834,12 +834,12 @@ def update_websocket_symbols():
834834
except Exception as e:
835835
print(f"[WEBSOCKET UPDATE] YAML error: {e}")
836836

837-
# Filter to valid symbols and limit total count
837+
# Filter to valid symbols (ALLOWED_SYMBOLS) and limit total count
838838
valid_symbols = [s for s in symbols_to_monitor
839-
if s and isinstance(s, str) and s.endswith('USDC')]
839+
if s and isinstance(s, str) and s in ALLOWED_SYMBOLS]
840840

841-
# Limit to maximum 5 symbols for deployment performance
842-
valid_symbols = valid_symbols[:5]
841+
# Limit to maximum 3 symbols for deployment performance (BTCUSDC, ETHUSDC, BTCETH)
842+
valid_symbols = valid_symbols[:3]
843843

844844
if valid_symbols:
845845
print(f"[WEBSOCKET UPDATE] Updating to monitor {len(valid_symbols)} symbols: {valid_symbols}")
@@ -1458,13 +1458,22 @@ async def telegram_handle_message(update: Update, context: ContextTypes.DEFAULT_
14581458
sync_positions_with_binance(client, positions)
14591459

14601460
# Support both button text and commands
1461-
if text in ["📊 Balance", "/balance", "/bal"]:
1462-
fetch_usdc_balance()
1461+
if text in ["� Portfolio", "�📊 Balance", "/balance", "/bal"]:
1462+
fetch_all_balances() # ✅ Use cross-asset balance fetching
14631463

1464+
btc = balance['btc']
1465+
eth = balance['eth']
14641466
usdc = balance['usd']
14651467
total_invested = 0.0
14661468
invested_details = []
14671469

1470+
# Calculate USD values for BTC and ETH
1471+
btc_price = get_latest_price('BTCUSDC') or 0
1472+
eth_price = get_latest_price('ETHUSDC') or 0
1473+
btc_value = btc * btc_price
1474+
eth_value = eth * eth_price
1475+
1476+
# Calculate total invested in positions
14681477
for s, p in positions.items():
14691478
price = get_latest_price(s)
14701479
if price is None:
@@ -1476,22 +1485,31 @@ async def telegram_handle_message(update: Update, context: ContextTypes.DEFAULT_
14761485
total_invested += value
14771486
invested_details.append(f"{s}: {qty:.6f} @ ${price:.2f} = ${value:.2f}")
14781487

1488+
# Cross-asset portfolio message
14791489
msg = (
1480-
f"USDC Balance: **${usdc:.2f}**\n"
1481-
f"Total Invested: **${total_invested:.2f}**\n"
1482-
f"Portfolio Value: **${usdc + total_invested:.2f} USDC**"
1490+
f"**💰 Cross-Asset Portfolio Balance:**\n\n"
1491+
f"**Available Assets:**\n"
1492+
f"• BTC: **{btc:.6f}** (~${btc_value:.2f})\n"
1493+
f"• ETH: **{eth:.6f}** (~${eth_value:.2f})\n"
1494+
f"• USDC: **${usdc:.2f}**\n\n"
1495+
f"**Portfolio Summary:**\n"
1496+
f"• Available: **${btc_value + eth_value + usdc:.2f}**\n"
1497+
f"• Invested: **${total_invested:.2f}**\n"
1498+
f"• **Total Portfolio Value: ${btc_value + eth_value + usdc + total_invested:.2f}**"
14831499
)
14841500

14851501
if invested_details:
1486-
msg += "\n\n*Investments:*"
1487-
for line in invested_details:
1488-
msg += f"\n- {line}"
1502+
msg += "\n\n*Active Investments:*"
1503+
for line in invested_details[:5]: # Limit to first 5 to avoid message length
1504+
msg += f"\n{line}"
1505+
if len(invested_details) > 5:
1506+
msg += f"\n• ... and {len(invested_details) - 5} more positions"
14891507

14901508
await send_with_keyboard(update, msg, parse_mode='Markdown')
14911509

14921510

14931511

1494-
elif text in ["💼 Investments", "/investments", "/inv", "/positions"]:
1512+
elif text in ["💼 Positions", "💼 Investments", "/investments", "/inv", "/positions"]:
14951513
msg = format_investments_message(positions, get_latest_price, DUST_LIMIT)
14961514
await send_with_keyboard(update, msg)
14971515

@@ -1531,8 +1549,8 @@ async def telegram_handle_message(update: Update, context: ContextTypes.DEFAULT_
15311549
continue
15321550
await send_with_keyboard(update, f"```{msg}```", parse_mode='Markdown')
15331551

1534-
elif text in ["🔍 Diagnose", "/diagnose", "/diag"]:
1535-
await send_with_keyboard(update, "🔍 Running investment diagnostic for ETHUSDC...")
1552+
elif text in ["🔍 Diagnostics", "🔍 Diagnose", "/diagnose", "/diag"]:
1553+
await send_with_keyboard(update, "🔍 Running cross-asset investment diagnostic...")
15361554

15371555
# Capture diagnostic output
15381556
import io
@@ -1542,21 +1560,34 @@ async def telegram_handle_message(update: Update, context: ContextTypes.DEFAULT_
15421560
sys.stdout = captured_output = io.StringIO()
15431561

15441562
try:
1545-
diagnose_investment_failure("ETHUSDC")
1563+
# Run diagnostic for all allowed symbols instead of just ETHUSDC
1564+
for i, symbol in enumerate(ALLOWED_SYMBOLS):
1565+
if i > 0:
1566+
print("\n" + "="*50 + "\n") # Separator between symbols
1567+
diagnose_investment_failure(symbol)
15461568
diagnostic_text = captured_output.getvalue()
15471569
finally:
15481570
sys.stdout = old_stdout
15491571

1550-
# Split into chunks if too long for Telegram
1551-
max_length = 4000
1572+
# Enhanced diagnostic summary
1573+
summary_msg = f"🔍 **Cross-Asset Diagnostic Summary**\n\n"
1574+
summary_msg += f"**Checked Symbols:** {', '.join(ALLOWED_SYMBOLS)}\n"
1575+
summary_msg += f"**Bot Status:** {'⏸️ PAUSED' if is_paused() else '▶️ ACTIVE'}\n"
1576+
summary_msg += f"**Market Risk:** {'🔴 HIGH' if 'market_is_risky' in globals() and market_is_risky() else '🟢 NORMAL'}\n"
1577+
summary_msg += f"**Positions:** {len([p for s, p in positions.items() if get_latest_price(s) and p.get('qty', 0) * get_latest_price(s) > DUST_LIMIT])}/{MAX_POSITIONS}\n\n"
1578+
1579+
await send_with_keyboard(update, summary_msg, parse_mode='Markdown')
1580+
1581+
# Split detailed diagnostic into chunks if too long for Telegram
1582+
max_length = 3500 # Shorter chunks to ensure delivery
15521583
if len(diagnostic_text) > max_length:
15531584
chunks = [diagnostic_text[i:i+max_length] for i in range(0, len(diagnostic_text), max_length)]
15541585
for i, chunk in enumerate(chunks):
1555-
await send_with_keyboard(update, f"```\nDiagnostic Report ({i+1}/{len(chunks)}):\n{chunk}\n```", parse_mode='Markdown')
1586+
await send_with_keyboard(update, f"```\nDetailed Report ({i+1}/{len(chunks)}):\n{chunk}\n```", parse_mode='Markdown')
15561587
else:
1557-
await send_with_keyboard(update, f"```\nDiagnostic Report:\n{diagnostic_text}\n```", parse_mode='Markdown')
1588+
await send_with_keyboard(update, f"```\nDetailed Diagnostic Report:\n{diagnostic_text}\n```", parse_mode='Markdown')
15581589

1559-
elif text in ["🔄 WebSocket Status", "/websocket", "/ws"]:
1590+
elif text in ["🔄 Connection", "🔄 WebSocket Status", "/websocket", "/ws", "/connection"]:
15601591
status = get_realtime_price_summary()
15611592
msg = (
15621593
f"🔄 **WebSocket Price Monitoring Status**\n\n"
@@ -1582,45 +1613,109 @@ async def telegram_handle_message(update: Update, context: ContextTypes.DEFAULT_
15821613

15831614
await send_with_keyboard(update, msg, parse_mode='Markdown')
15841615

1585-
elif text in ["⚡ Check Momentum", "/momentum", "/check"]:
1586-
await send_with_keyboard(update, "⚡ Running manual momentum check...")
1616+
elif text in ["⚡ Quick Check", "⚡ Check Momentum", "/momentum", "/check", "/quick"]:
1617+
await send_with_keyboard(update, "⚡ Quick momentum check for top symbols...")
15871618

15881619
try:
1589-
# Run the quick momentum check manually
15901620
start_time = time.time()
1591-
await alarm_job(context)
1592-
end_time = time.time()
15931621

1622+
# Quick check of only ALLOWED_SYMBOLS for performance
1623+
results = []
1624+
1625+
for symbol in ALLOWED_SYMBOLS:
1626+
try:
1627+
# Get current price
1628+
current_price = get_latest_price(symbol)
1629+
if not current_price:
1630+
results.append(f"• {symbol}: ❌ No price data")
1631+
continue
1632+
1633+
# Quick momentum check using has_recent_momentum if available
1634+
try:
1635+
has_momentum = has_recent_momentum(symbol) if 'has_recent_momentum' in globals() else False
1636+
momentum_status = "✅ Strong" if has_momentum else "⚪ Weak"
1637+
except:
1638+
# Fallback: simple 1m price change check
1639+
try:
1640+
klines = client.get_klines(symbol=symbol, interval='1m', limit=2)
1641+
if len(klines) >= 2:
1642+
prev_close = float(klines[-2][4])
1643+
current_close = float(klines[-1][4])
1644+
pct_change = ((current_close - prev_close) / prev_close) * 100
1645+
momentum_status = "✅ Rising" if pct_change > 0.3 else "⚪ Stable" if pct_change > -0.3 else "🔴 Falling"
1646+
else:
1647+
momentum_status = "❓ No data"
1648+
except:
1649+
momentum_status = "❌ Error"
1650+
1651+
results.append(f"• {symbol}: {momentum_status} @ ${current_price:.4f}")
1652+
1653+
except Exception as e:
1654+
results.append(f"• {symbol}: ❌ Error - {str(e)[:30]}")
1655+
1656+
end_time = time.time()
15941657
processing_time = end_time - start_time
1595-
await send_with_keyboard(update,
1596-
f"✅ Manual momentum check completed in {processing_time:.2f} seconds")
1658+
1659+
msg = (
1660+
f"⚡ **Quick Momentum Check Results:**\n"
1661+
f"⏱️ Completed in {processing_time:.2f}s\n\n"
1662+
+ "\n".join(results) +
1663+
f"\n\n💡 *This is a fast check of allowed symbols only.*"
1664+
)
1665+
1666+
await send_with_keyboard(update, msg, parse_mode='Markdown')
1667+
15971668
except Exception as e:
1598-
await send_with_keyboard(update, f"❌ Momentum check failed: {str(e)}")
1669+
await send_with_keyboard(update, f"❌ Quick momentum check failed: {str(e)}")
15991670

1600-
elif text in ["📊 Trading Status", "/status", "/trading"]:
1601-
await send_with_keyboard(update, "📊 Getting trading status...")
1671+
elif text in ["� Overview", "📈 Status", "�📊 Trading Status", "/status", "/trading", "/overview"]:
1672+
await send_with_keyboard(update, " Getting complete cross-asset overview...")
16021673

1603-
# Capture debug output
1604-
import io
1605-
import sys
1674+
fetch_all_balances() # Get all asset balances
1675+
btc = balance['btc']
1676+
eth = balance['eth']
1677+
usdc = balance['usd']
16061678

1607-
old_stdout = sys.stdout
1608-
sys.stdout = captured_output = io.StringIO()
1679+
# Calculate USD values
1680+
btc_price = get_latest_price('BTCUSDC') or 0
1681+
eth_price = get_latest_price('ETHUSDC') or 0
1682+
btc_value = btc * btc_price
1683+
eth_value = eth * eth_price
1684+
available_value = btc_value + eth_value + usdc
16091685

1610-
try:
1611-
get_trading_status()
1612-
debug_text = captured_output.getvalue()
1613-
finally:
1614-
sys.stdout = old_stdout
1686+
# Calculate total invested
1687+
total_invested = sum(get_latest_price(s) * p.get('qty', 0)
1688+
for s, p in positions.items()
1689+
if get_latest_price(s) and p.get('qty', 0) * get_latest_price(s) > DUST_LIMIT)
16151690

1616-
# Send debug info
1617-
if len(debug_text) > 4000:
1618-
# Split long messages
1619-
chunks = [debug_text[i:i+4000] for i in range(0, len(debug_text), 4000)]
1620-
for i, chunk in enumerate(chunks):
1621-
await send_with_keyboard(update, f"```\nTrading Status ({i+1}/{len(chunks)}):\n{chunk}\n```", parse_mode='Markdown')
1622-
else:
1623-
await send_with_keyboard(update, f"```\nTrading Status:\n{debug_text}\n```", parse_mode='Markdown')
1691+
# Get trading mode
1692+
trading_mode = get_effective_trading_mode()
1693+
1694+
status_msg = f"""**📈 Cross-Asset Trading Bot Overview**
1695+
1696+
**💰 Available Assets:**
1697+
• BTC: {btc:.6f} (~${btc_value:.2f})
1698+
• ETH: {eth:.6f} (~${eth_value:.2f})
1699+
• USDC: ${usdc:.2f}
1700+
• **Available Total: ${available_value:.2f}**
1701+
1702+
**💼 Investment Status:**
1703+
• Total Invested: ${total_invested:.2f}
1704+
• **Portfolio Value: ${available_value + total_invested:.2f}**
1705+
• Active Positions: {len([p for s, p in positions.items() if get_latest_price(s) and p.get('qty', 0) * get_latest_price(s) > DUST_LIMIT])}/{MAX_POSITIONS}
1706+
1707+
**⚙️ Trading Status:**
1708+
• Bot State: {'⏸️ PAUSED' if is_paused() else '▶️ ACTIVE'}
1709+
• Trading Mode: {trading_mode}
1710+
• Market Risk: {'🔴 HIGH' if 'market_is_risky' in globals() and market_is_risky() else '🟢 NORMAL'}
1711+
• Cross-Asset Symbols: {', '.join(ALLOWED_SYMBOLS)}
1712+
1713+
**🔄 Connection Status:**
1714+
• WebSocket: {'🟢 Active' if ws_price_manager and ws_price_manager._running else '🔴 Inactive'}
1715+
• Monitored: {len(ws_price_manager.get_monitored_symbols()) if ws_price_manager else 0} symbols
1716+
1717+
Type `/help` for all available commands."""
1718+
await send_with_keyboard(update, status_msg, parse_mode='Markdown')
16241719

16251720
elif text in ["⚡ Fast Check", "/fast", "/quick"]:
16261721
await send_with_keyboard(update, "⚡ Running fast momentum check for immediate opportunities...")
@@ -1891,12 +1986,11 @@ def is_paused():
18911986
return state.get("paused", False)
18921987

18931988
main_keyboard = [
1894-
["📊 Balance", "💼 Investments"],
1895-
["⏸ Pause Trading", "▶️ Resume Trading"],
1896-
["📝 Trade Log", "🔍 Diagnose"],
1897-
["🔄 WebSocket Status", "⚡ Check Momentum"],
1898-
["📊 Trading Status", "⚡ Fast Check"],
1899-
["🔧 API Test", "📈 Status"]
1989+
["� Portfolio", "💼 Positions"], # Clear financial info
1990+
["⏸ Pause Trading", "▶️ Resume Trading"], # Trading control
1991+
["📝 Trade Log", "🔍 Diagnostics"], # History & enhanced diagnostics
1992+
["🔄 Connection", "⚡ Quick Check"], # WebSocket + fast momentum
1993+
["🔧 API Test", "📈 Overview"], # Technical test + complete status
19001994
]
19011995

19021996
async def start_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):

0 commit comments

Comments
 (0)