Skip to content

Commit 5c3085d

Browse files
alerts for buy, sell, 2/3 momentum and start
1 parent 7e4abc3 commit 5c3085d

File tree

1 file changed

+110
-25
lines changed

1 file changed

+110
-25
lines changed

β€ŽTrading-Automation/trading_automation.pyβ€Ž

Lines changed: 110 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,21 @@ def buy(symbol, amount=None):
461461
'trade_time': time.time()
462462
}
463463
print(f"[DEBUG] Actual USDC balance after buy attempt: {balance['usd']}")
464+
465+
# Send investment alert
466+
import asyncio
467+
try:
468+
asyncio.create_task(send_alarm_message(
469+
f"πŸ’° INVESTMENT MADE\n\n"
470+
f"πŸ“Š {symbol}\n"
471+
f"πŸ’΅ Amount: ${trade_amount:.2f}\n"
472+
f"πŸ“ˆ Price: ${price:.6f}\n"
473+
f"πŸ”’ Quantity: {qty:.6f}\n"
474+
f"πŸ’Ό Remaining USDC: ${balance['usd']:.2f}"
475+
))
476+
except Exception as e:
477+
print(f"[ALERT ERROR] Could not send investment alert: {e}")
478+
464479
return positions[symbol]
465480
except BinanceAPIException as e:
466481
print(f"[BUY ERROR] {symbol}: {e}")
@@ -578,21 +593,41 @@ def auto_sell_momentum_positions(min_profit=MIN_PROFIT, trailing_stop=TRAIL_STOP
578593

579594
if should_sell:
580595
exit_price, fee, _ = sell(symbol, qty)
581-
exit_time = time.time()
582-
tax = estimate_trade_tax(entry, exit_price, qty, trade_time, exit_time)
583-
log_trade(
584-
symbol=symbol,
585-
entry=entry,
586-
exit_price=exit_price,
587-
qty=qty,
588-
trade_time=trade_time,
589-
exit_time=exit_time,
590-
fees=fee,
591-
tax=tax,
592-
action="sell"
593-
)
594-
print(f"[MOMENTUM SELL] {symbol}: {reason}")
595-
del positions[symbol]
596+
if exit_price is not None:
597+
exit_time = time.time()
598+
tax = estimate_trade_tax(entry, exit_price, qty, trade_time, exit_time)
599+
pnl_dollar = (exit_price - entry) * qty
600+
601+
log_trade(
602+
symbol=symbol,
603+
entry=entry,
604+
exit_price=exit_price,
605+
qty=qty,
606+
trade_time=trade_time,
607+
exit_time=exit_time,
608+
fees=fee,
609+
tax=tax,
610+
action="sell"
611+
)
612+
613+
# Send sell alert
614+
import asyncio
615+
try:
616+
asyncio.create_task(send_alarm_message(
617+
f"πŸ’Έ POSITION SOLD\n\n"
618+
f"πŸ“Š {symbol}\n"
619+
f"πŸ“‰ Entry: ${entry:.6f}\n"
620+
f"πŸ“ˆ Exit: ${exit_price:.6f}\n"
621+
f"πŸ”’ Quantity: {qty:.6f}\n"
622+
f"πŸ’° PnL: ${pnl_dollar:.2f} ({pnl_pct:.2f}%)\n"
623+
f"⏱️ Hold Time: {held_for/60:.1f} min\n"
624+
f"πŸ“‹ Reason: {reason}"
625+
))
626+
except Exception as e:
627+
print(f"[ALERT ERROR] Could not send sell alert: {e}")
628+
629+
print(f"[MOMENTUM SELL] {symbol}: {reason}")
630+
del positions[symbol]
596631
except Exception as e:
597632
print(f"[AUTO-SELL ERROR] {symbol}: {e}")
598633

@@ -1461,6 +1496,8 @@ async def check_and_alarm_high_volume(context=None):
14611496
if not stats:
14621497
return
14631498
alarmed = []
1499+
full_momentum_alerts = []
1500+
14641501
for symbol, s in stats.items():
14651502
vol = s.get("volume_1d", 0) or 0
14661503
if vol > MIN_VOLUME:
@@ -1471,18 +1508,42 @@ async def check_and_alarm_high_volume(context=None):
14711508
m5, ind5 = check_advanced_momentum(symbol, '5m', d5)
14721509
m15,ind15= check_advanced_momentum(symbol, '15m', d15)
14731510

1474-
pct1 = ind1.get('pct_change', 0) if ind1 else 0
1475-
pct5 = ind5.get('pct_change', 0) if ind5 else 0
1476-
pct15 = ind15.get('pct_change', 0) if ind15 else 0
1477-
1478-
diff1 = (d1*100) - pct1
1479-
diff5 = (d5*100) - pct5
1480-
diff15 = (d15*100) - pct15
1481-
1482-
alarmed.append((symbol, vol, m1, m5, m15, pct1, pct5, pct15, diff1, diff5, diff15, d1, d5, d15))
1511+
# Count momentum stages met
1512+
momentum_count = sum([m1, m5, m15])
1513+
1514+
# Full momentum alert (all 3 stages)
1515+
if momentum_count == 3:
1516+
pct1 = ind1.get('pct_change', 0) if ind1 else 0
1517+
pct5 = ind5.get('pct_change', 0) if ind5 else 0
1518+
pct15 = ind15.get('pct_change', 0) if ind15 else 0
1519+
1520+
full_momentum_alerts.append((symbol, vol, pct1, pct5, pct15, d1, d5, d15))
1521+
1522+
# Partial momentum alert (2 out of 3 stages)
1523+
elif momentum_count >= 2:
1524+
pct1 = ind1.get('pct_change', 0) if ind1 else 0
1525+
pct5 = ind5.get('pct_change', 0) if ind5 else 0
1526+
pct15 = ind15.get('pct_change', 0) if ind15 else 0
1527+
1528+
diff1 = (d1*100) - pct1
1529+
diff5 = (d5*100) - pct5
1530+
diff15 = (d15*100) - pct15
1531+
1532+
alarmed.append((symbol, vol, m1, m5, m15, pct1, pct5, pct15, diff1, diff5, diff15, d1, d5, d15))
1533+
1534+
# Send full momentum alerts first (highest priority)
1535+
if full_momentum_alerts:
1536+
msg = "πŸš€ FULL MOMENTUM ALERT - ALL 3 STAGES MET! πŸš€\n\n"
1537+
for (symbol, vol, pct1, pct5, pct15, d1, d5, d15) in full_momentum_alerts:
1538+
msg += f"🎯 {symbol}: Volume = {vol:,.0f}\n"
1539+
msg += f" 1m: βœ… {pct1:.2f}% (Target {d1*100:.2f}%)\n"
1540+
msg += f" 5m: βœ… {pct5:.2f}% (Target {d5*100:.2f}%)\n"
1541+
msg += f" 15m: βœ… {pct15:.2f}% (Target {d15*100:.2f}%)\n\n"
1542+
await send_alarm_message(msg)
14831543

1544+
# Send partial momentum alerts (2/3 stages)
14841545
if alarmed:
1485-
msg = "🚨 High Volume Alert (dynamic thresholds):\n\n"
1546+
msg = "🚨 High Volume Alert (2/3 momentum stages reached):\n\n"
14861547
for (symbol, vol, m1, m5, m15, pct1, pct5, pct15, diff1, diff5, diff15, d1, d5, d15) in alarmed:
14871548
msg += f"πŸ“Š {symbol}: Volume = {vol:,.0f}\n"
14881549
msg += f" 1m: {'βœ…' if m1 else '❌'} {pct1:.2f}% (Target {d1*100:.2f}%, need {max(0,diff1):.2f}%)\n"
@@ -1501,6 +1562,30 @@ async def alarm_job(context: CallbackContext):
15011562
positions.update(rebuild_cost_basis(trade_log))
15021563
reconcile_positions_with_binance(client, positions)
15031564
print(f"[INFO] Bot paused state on startup: {is_paused()}")
1565+
1566+
# Send startup alert
1567+
import asyncio
1568+
try:
1569+
async def send_startup_alert():
1570+
fetch_usdc_balance()
1571+
total_positions = len([p for p in positions.items() if get_latest_price(p[0]) and p[1]['qty'] * get_latest_price(p[0]) > DUST_LIMIT])
1572+
1573+
await send_alarm_message(
1574+
f"πŸ€– BOT STARTED\n\n"
1575+
f"βœ… System initialized successfully\n"
1576+
f"πŸ’° USDC Balance: ${balance['usd']:.2f}\n"
1577+
f"πŸ“Š Active Positions: {total_positions}\n"
1578+
f"⏸️ Trading Status: {'PAUSED' if is_paused() else 'ACTIVE'}\n"
1579+
f"πŸ• Startup Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
1580+
)
1581+
1582+
loop = asyncio.new_event_loop()
1583+
asyncio.set_event_loop(loop)
1584+
loop.run_until_complete(send_startup_alert())
1585+
loop.close()
1586+
except Exception as e:
1587+
print(f"[ALERT ERROR] Could not send startup alert: {e}")
1588+
15041589
try:
15051590
trading_thread = threading.Thread(target=trading_loop, daemon=True)
15061591
trading_thread.start()

0 commit comments

Comments
Β (0)