币安自动量化脚本
Jason 发布于 阅读:64
模拟账户余额5000美金实测,2.16下午7时至次日上午10时,总收益990美金。
"""
🐜 蚂蚁搬家 v3.0 PRO - 专业版
===============================================
✨ 现代化科技感界面
✅ 修复手续费计算
✅ 实时数据可视化
✅ 性能监控仪表板
===============================================
"""
import os
import time
import json
import hmac
import hashlib
import requests
import threading
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Set
from dataclasses import dataclass
from urllib.parse import urlencode
from decimal import Decimal, ROUND_DOWN
# ============ 配置 ============
BINANCE_API_KEY = 'KEY'
BINANCE_SECRET_KEY = 'KEY'
SYMBOL = 'ETHUSDT'
LEVERAGE = 8
GRID_SPREAD = 0.002 # 0.2%
NUM_GRIDS = 10
ORDER_AMOUNT_USDT = 200
# 手续费设置
MAKER_FEE = 0.0002 # 0.02% Maker费用
TAKER_FEE = 0.0004 # 0.04% Taker费用
DEFAULT_FEE = TAKER_FEE # 保守估计使用Taker费用
CHECK_INTERVAL = 5.0
DISPLAY_INTERVAL = 15
BINANCE_BASE_URL = 'https://testnet.binancefuture.com' # 模拟账户
PRICE_PRECISION = 2
QUANTITY_PRECISION = 3
# ANSI颜色代码
class Colors:
RESET = '\033[0m'
BOLD = '\033[1m'
DIM = '\033[2m'
# 前景色
BLACK = '\033[30m'
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
MAGENTA = '\033[35m'
CYAN = '\033[36m'
WHITE = '\033[37m'
# 亮色
BRIGHT_BLACK = '\033[90m'
BRIGHT_RED = '\033[91m'
BRIGHT_GREEN = '\033[92m'
BRIGHT_YELLOW = '\033[93m'
BRIGHT_BLUE = '\033[94m'
BRIGHT_MAGENTA = '\033[95m'
BRIGHT_CYAN = '\033[96m'
BRIGHT_WHITE = '\033[97m'
# 背景色
BG_BLACK = '\033[40m'
BG_BLUE = '\033[44m'
BG_GREEN = '\033[42m'
BG_RED = '\033[41m'
class UI:
"""现代化UI组件"""
@staticmethod
def clear_screen():
"""清屏"""
os.system('clear' if os.name != 'nt' else 'cls')
@staticmethod
def box(text: str, color=Colors.CYAN, width=80):
"""绘制边框盒子"""
lines = text.split('\n')
print(f"{color}╔{'═' * (width-2)}╗{Colors.RESET}")
for line in lines:
padding = width - len(line) - 4
print(f"{color}║{Colors.RESET} {line}{' ' * padding} {color}║{Colors.RESET}")
print(f"{color}╚{'═' * (width-2)}╝{Colors.RESET}")
@staticmethod
def separator(char='─', width=80, color=Colors.BRIGHT_BLACK):
"""分隔线"""
print(f"{color}{char * width}{Colors.RESET}")
@staticmethod
def header(text: str, color=Colors.BRIGHT_CYAN):
"""标题"""
print(f"\n{color}{Colors.BOLD}▶ {text}{Colors.RESET}")
@staticmethod
def success(text: str):
"""成功消息"""
print(f"{Colors.BRIGHT_GREEN}✓{Colors.RESET} {text}")
@staticmethod
def error(text: str):
"""错误消息"""
print(f"{Colors.BRIGHT_RED}✗{Colors.RESET} {text}")
@staticmethod
def warning(text: str):
"""警告消息"""
print(f"{Colors.BRIGHT_YELLOW}⚠{Colors.RESET} {text}")
@staticmethod
def info(text: str):
"""信息消息"""
print(f"{Colors.BRIGHT_BLUE}ℹ{Colors.RESET} {text}")
@staticmethod
def metric(label: str, value: str, color=Colors.BRIGHT_WHITE):
"""指标显示"""
print(f"{Colors.DIM}{label}:{Colors.RESET} {color}{value}{Colors.RESET}")
@staticmethod
def progress_bar(percentage: float, width=30, color=Colors.BRIGHT_GREEN):
"""进度条"""
filled = int(width * percentage)
bar = '█' * filled + '░' * (width - filled)
print(f"{color}{bar}{Colors.RESET} {percentage*100:.1f}%")
@staticmethod
def price_change(current: float, previous: float):
"""价格变化显示"""
change = current - previous
change_pct = (change / previous * 100) if previous > 0 else 0
if change > 0:
return f"{Colors.BRIGHT_GREEN}↑ ${current:.2f} (+{change_pct:.2f}%){Colors.RESET}"
elif change < 0:
return f"{Colors.BRIGHT_RED}↓ ${current:.2f} ({change_pct:.2f}%){Colors.RESET}"
else:
return f"{Colors.BRIGHT_WHITE}→ ${current:.2f} (0.00%){Colors.RESET}"
@staticmethod
def sparkline(values: List[float], width=20, height=5):
"""迷你图表"""
if not values or len(values) < 2:
return
min_val = min(values)
max_val = max(values)
range_val = max_val - min_val if max_val > min_val else 1
# 简化版本:使用ASCII字符
chars = ['_', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']
line = ""
for val in values[-width:]:
normalized = (val - min_val) / range_val
idx = int(normalized * (len(chars) - 1))
line += chars[idx]
print(f"{Colors.BRIGHT_CYAN}{line}{Colors.RESET}")
@dataclass
class Order:
order_id: str
side: str
price: float
quantity: float
@dataclass
class TradeStats:
"""交易统计"""
total_trades: int = 0
win_trades: int = 0
loss_trades: int = 0
total_profit: float = 0.0
total_fees: float = 0.0
net_profit: float = 0.0
max_profit: float = 0.0
max_loss: float = 0.0
# 价格历史
price_history: List[float] = None
profit_history: List[float] = None
def __post_init__(self):
if self.price_history is None:
self.price_history = []
if self.profit_history is None:
self.profit_history = []
def add_price(self, price: float):
self.price_history.append(price)
if len(self.price_history) > 50:
self.price_history.pop(0)
def add_profit(self, profit: float):
self.profit_history.append(self.net_profit)
if len(self.profit_history) > 50:
self.profit_history.pop(0)
class OptimizedClient:
"""优化客户端"""
def __init__(self, api_key: str, secret_key: str, base_url: str):
self.api_key = api_key
self.secret_key = secret_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({'X-MBX-APIKEY': api_key})
self.symbol_info = {}
# 本地缓存
self.price_cache = 0.0
self.price_cache_time = 0
self.balance_cache = {}
self.balance_cache_time = 0
# API权重监控
self.api_weight = 0
self.api_weight_reset_time = time.time() + 60
def _sign(self, params: Dict) -> str:
query_string = urlencode(params)
return hmac.new(
self.secret_key.encode('utf-8'),
query_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
def _request(self, method: str, endpoint: str, params: Dict = None, signed: bool = False):
if params is None:
params = {}
if signed:
params['timestamp'] = int(time.time() * 1000)
params['signature'] = self._sign(params)
try:
url = f"{self.base_url}{endpoint}"
if method == 'GET':
response = self.session.get(url, params=params, timeout=5)
elif method == 'POST':
response = self.session.post(url, params=params, timeout=5)
elif method == 'DELETE':
response = self.session.delete(url, params=params, timeout=5)
else:
return None
# 监控API权重
if 'x-mbx-used-weight-1m' in response.headers:
self.api_weight = int(response.headers['x-mbx-used-weight-1m'])
if self.api_weight > 1000:
UI.warning(f"API权重高: {self.api_weight}/1200")
time.sleep(1)
response.raise_for_status()
return response.json()
except Exception as e:
if 'marginType' not in endpoint:
UI.error(f"API错误: {e}")
return None
def get_exchange_info(self, symbol: str) -> bool:
data = self._request('GET', '/fapi/v1/exchangeInfo')
if not data:
return False
for s in data.get('symbols', []):
if s['symbol'] == symbol:
self.symbol_info[symbol] = {
'pricePrecision': s['pricePrecision'],
'quantityPrecision': s['quantityPrecision'],
}
return True
return False
def format_price(self, symbol: str, price: float) -> str:
precision = self.symbol_info.get(symbol, {}).get('pricePrecision', PRICE_PRECISION)
price_decimal = Decimal(str(price))
quantize_str = '0.' + '0' * (precision - 1) + '1'
formatted = price_decimal.quantize(Decimal(quantize_str), rounding=ROUND_DOWN)
return str(formatted)
def format_quantity(self, symbol: str, quantity: float) -> str:
precision = self.symbol_info.get(symbol, {}).get('quantityPrecision', QUANTITY_PRECISION)
qty_decimal = Decimal(str(quantity))
quantize_str = '0.' + '0' * (precision - 1) + '1'
formatted = qty_decimal.quantize(Decimal(quantize_str), rounding=ROUND_DOWN)
result = str(formatted).rstrip('0').rstrip('.')
return result
def set_leverage(self, symbol: str, leverage: int) -> bool:
result = self._request('POST', '/fapi/v1/leverage',
{'symbol': symbol, 'leverage': leverage}, signed=True)
return result is not None
def get_current_price(self, symbol: str) -> float:
"""带缓存的价格获取"""
now = time.time()
if now - self.price_cache_time < 5 and self.price_cache > 0:
return self.price_cache
data = self._request('GET', '/fapi/v1/ticker/price', {'symbol': symbol})
if data:
self.price_cache = float(data['price'])
self.price_cache_time = now
return self.price_cache
return self.price_cache if self.price_cache > 0 else 0.0
def get_account_balance(self) -> Dict:
"""带缓存的余额获取"""
now = time.time()
if now - self.balance_cache_time < 30 and self.balance_cache:
return self.balance_cache
data = self._request('GET', '/fapi/v2/balance', signed=True)
if not data:
return self.balance_cache
for item in data:
if item['asset'] == 'USDT':
self.balance_cache = {
'total': float(item['balance']),
'available': float(item['availableBalance'])
}
self.balance_cache_time = now
return self.balance_cache
return {}
def get_position(self, symbol: str) -> Dict:
data = self._request('GET', '/fapi/v2/positionRisk', {'symbol': symbol}, signed=True)
if not data or len(data) == 0:
return {}
pos = data[0]
return {
'positionAmt': float(pos['positionAmt']),
'entryPrice': float(pos['entryPrice']),
'unRealizedProfit': float(pos['unRealizedProfit'])
}
def place_limit_order(self, symbol: str, side: str, price: float, quantity: float) -> Optional[str]:
formatted_price = self.format_price(symbol, price)
formatted_qty = self.format_quantity(symbol, quantity)
params = {
'symbol': symbol,
'side': side,
'type': 'LIMIT',
'timeInForce': 'GTC',
'quantity': formatted_qty,
'price': formatted_price,
}
result = self._request('POST', '/fapi/v1/order', params, signed=True)
time.sleep(0.05)
return str(result['orderId']) if result else None
def place_batch_orders(self, orders: List[Dict]) -> List[Optional[str]]:
"""批量下单"""
if len(orders) == 0:
return []
if len(orders) > 5:
result_ids = []
for i in range(0, len(orders), 5):
batch = orders[i:i+5]
ids = self._place_batch_internal(batch)
result_ids.extend(ids)
time.sleep(0.1)
return result_ids
else:
return self._place_batch_internal(orders)
def _place_batch_internal(self, orders: List[Dict]) -> List[Optional[str]]:
batch_orders = []
for order in orders:
formatted_price = self.format_price(order['symbol'], order['price'])
formatted_qty = self.format_quantity(order['symbol'], order['quantity'])
batch_orders.append({
'symbol': order['symbol'],
'side': order['side'],
'type': 'LIMIT',
'timeInForce': 'GTC',
'quantity': formatted_qty,
'price': formatted_price,
})
params = {'batchOrders': json.dumps(batch_orders)}
result = self._request('POST', '/fapi/v1/batchOrders', params, signed=True)
if not result:
return [None] * len(orders)
return [str(r['orderId']) if 'orderId' in r else None for r in result]
def get_open_orders(self, symbol: str) -> List[Dict]:
data = self._request('GET', '/fapi/v1/openOrders', {'symbol': symbol}, signed=True)
return data if data else []
def cancel_order(self, symbol: str, order_id: str) -> bool:
result = self._request('DELETE', '/fapi/v1/order',
{'symbol': symbol, 'orderId': order_id}, signed=True)
return result is not None
def cancel_all_orders(self, symbol: str) -> bool:
result = self._request('DELETE', '/fapi/v1/allOpenOrders',
{'symbol': symbol}, signed=True)
return result is not None
class SmartGridEngine:
"""智能网格引擎 - 带手续费计算"""
def __init__(self, client: OptimizedClient, symbol: str):
self.client = client
self.symbol = symbol
self.active_orders: Dict[str, Order] = {}
self.pending_orders: List[Dict] = []
# 统计数据
self.stats = TradeStats()
self.last_buy_price = 0.0
self.last_sell_price = 0.0
self.previous_price = 0.0
def setup_grid(self, center_price: float):
"""设置网格"""
UI.info(f"设置网格中心: ${center_price:.2f}")
self.client.cancel_all_orders(self.symbol)
self.active_orders.clear()
quantity = ORDER_AMOUNT_USDT / center_price
orders_to_place = []
for i in range(1, NUM_GRIDS + 1):
# 买单
buy_price = center_price * (1 - GRID_SPREAD * i)
orders_to_place.append({
'symbol': self.symbol,
'side': 'BUY',
'price': buy_price,
'quantity': quantity
})
# 卖单
sell_price = center_price * (1 + GRID_SPREAD * i)
orders_to_place.append({
'symbol': self.symbol,
'side': 'SELL',
'price': sell_price,
'quantity': quantity
})
UI.info(f"批量下单 {len(orders_to_place)} 个订单...")
order_ids = self.client.place_batch_orders(orders_to_place)
success_count = 0
for i, order_id in enumerate(order_ids):
if order_id:
order_data = orders_to_place[i]
self.active_orders[order_id] = Order(
order_id=order_id,
side=order_data['side'],
price=order_data['price'],
quantity=order_data['quantity']
)
success_count += 1
UI.success(f"网格设置完成: {success_count}/{len(orders_to_place)} 订单激活")
def check_and_refill(self):
"""检查并补充订单"""
open_orders = self.client.get_open_orders(self.symbol)
open_order_ids = {str(o['orderId']) for o in open_orders}
filled_orders = []
for order_id, order in list(self.active_orders.items()):
if order_id not in open_order_ids:
filled_orders.append(order)
del self.active_orders[order_id]
if filled_orders:
self._handle_filled(filled_orders)
if len(self.pending_orders) >= 4:
self._flush_pending_orders()
def _calculate_fees(self, price: float, quantity: float) -> float:
"""计算手续费"""
trade_value = price * quantity
return trade_value * DEFAULT_FEE
def _handle_filled(self, filled: List[Order]):
"""处理成交 - 带手续费计算"""
for order in filled:
# 计算手续费
fee = self._calculate_fees(order.price, order.quantity)
self.stats.total_fees += fee
self.stats.total_trades += 1
side_icon = f"{Colors.BRIGHT_GREEN}BUY{Colors.RESET}" if order.side == 'BUY' else f"{Colors.BRIGHT_MAGENTA}SELL{Colors.RESET}"
print(f"\n{side_icon} @ ${order.price:.2f} | 手续费: ${fee:.4f}")
if order.side == 'BUY':
self.last_buy_price = order.price
if self.last_sell_price > 0:
# 毛利润
gross_profit = (self.last_sell_price - order.price) * order.quantity
# 扣除两次手续费 (之前的SELL + 现在的BUY)
previous_sell_fee = self._calculate_fees(self.last_sell_price, order.quantity)
net_profit = gross_profit - fee - previous_sell_fee
self.stats.total_profit += gross_profit
self.stats.net_profit += net_profit
if net_profit > 0:
self.stats.win_trades += 1
self.stats.max_profit = max(self.stats.max_profit, net_profit)
print(f" {Colors.BRIGHT_GREEN}💰 净利润: ${net_profit:.4f}{Colors.RESET} (毛利: ${gross_profit:.4f}, 费用: ${fee + previous_sell_fee:.4f})")
else:
self.stats.loss_trades += 1
self.stats.max_loss = min(self.stats.max_loss, net_profit)
print(f" {Colors.BRIGHT_RED}📉 亏损: ${net_profit:.4f}{Colors.RESET}")
# 加入待补充队列
self.pending_orders.append({
'symbol': self.symbol,
'side': 'SELL',
'price': order.price * (1 + GRID_SPREAD),
'quantity': order.quantity
})
self.pending_orders.append({
'symbol': self.symbol,
'side': 'BUY',
'price': order.price,
'quantity': order.quantity
})
elif order.side == 'SELL':
self.last_sell_price = order.price
if self.last_buy_price > 0:
# 毛利润
gross_profit = (order.price - self.last_buy_price) * order.quantity
# 扣除两次手续费 (之前的BUY + 现在的SELL)
previous_buy_fee = self._calculate_fees(self.last_buy_price, order.quantity)
net_profit = gross_profit - fee - previous_buy_fee
self.stats.total_profit += gross_profit
self.stats.net_profit += net_profit
if net_profit > 0:
self.stats.win_trades += 1
self.stats.max_profit = max(self.stats.max_profit, net_profit)
print(f" {Colors.BRIGHT_GREEN}💰 净利润: ${net_profit:.4f}{Colors.RESET} (毛利: ${gross_profit:.4f}, 费用: ${fee + previous_buy_fee:.4f})")
else:
self.stats.loss_trades += 1
self.stats.max_loss = min(self.stats.max_loss, net_profit)
print(f" {Colors.BRIGHT_RED}📉 亏损: ${net_profit:.4f}{Colors.RESET}")
# 加入待补充队列
self.pending_orders.append({
'symbol': self.symbol,
'side': 'BUY',
'price': order.price * (1 - GRID_SPREAD),
'quantity': order.quantity
})
self.pending_orders.append({
'symbol': self.symbol,
'side': 'SELL',
'price': order.price,
'quantity': order.quantity
})
# 立即批量补充
self._flush_pending_orders()
# 更新统计
self.stats.add_profit(self.stats.net_profit)
# 显示简要统计
win_rate = (self.stats.win_trades / self.stats.total_trades * 100) if self.stats.total_trades > 0 else 0
print(f"{Colors.BRIGHT_CYAN}📊 {self.stats.total_trades}笔 | 净利: ${self.stats.net_profit:.2f} | 胜率: {win_rate:.1f}% | {len(self.active_orders)}单{Colors.RESET}")
def _flush_pending_orders(self):
"""批量补充订单"""
if not self.pending_orders:
return
print(f" {Colors.DIM}↻ 批量补充{len(self.pending_orders)}单...{Colors.RESET}")
order_ids = self.client.place_batch_orders(self.pending_orders)
for i, order_id in enumerate(order_ids):
if order_id:
order_data = self.pending_orders[i]
self.active_orders[order_id] = Order(
order_id=order_id,
side=order_data['side'],
price=order_data['price'],
quantity=order_data['quantity']
)
self.pending_orders.clear()
class ProBot:
"""专业机器人"""
def __init__(self, client: OptimizedClient, grid: SmartGridEngine):
self.client = client
self.grid = grid
self.is_running = False
self.session_start = datetime.now()
self.last_rebalance = time.time()
def initialize(self) -> bool:
UI.header("初始化系统")
if not self.client.get_exchange_info(SYMBOL):
UI.error("无法获取交易对信息")
return False
# 检查持仓模式
current_mode = self.client._request('GET', '/fapi/v1/positionSide/dual', signed=True)
if current_mode:
is_dual = current_mode.get('dualSidePosition', False)
UI.success(f"持仓模式: {'双向' if is_dual else '单向'}")
# 设置杠杆
if self.client.set_leverage(SYMBOL, LEVERAGE):
UI.success(f"杠杆设置: {LEVERAGE}x")
# 检查余额
balance = self.client.get_account_balance()
if balance.get('total', 0) < 100:
UI.error("余额不足 $100")
return False
UI.success(f"账户余额: ${balance['total']:.2f} USDT")
# 获取当前价格
price = self.client.get_current_price(SYMBOL)
if price == 0:
UI.error("无法获取价格")
return False
UI.success(f"{SYMBOL} 当前价格: ${price:.2f}")
# 设置网格
self.grid.setup_grid(price)
self.grid.previous_price = price
return True
def display_dashboard(self):
"""显示仪表板"""
UI.clear_screen()
# 标题
print(f"\n{Colors.BOLD}{Colors.BRIGHT_CYAN}╔════════════════════════════════════════════════════════════════════════════╗")
print(f"║ 🐜 蚂蚁搬家 v3.0 PRO - 交易仪表板 ║")
print(f"╚════════════════════════════════════════════════════════════════════════════╝{Colors.RESET}\n")
# 获取数据
balance = self.client.get_account_balance()
position = self.client.get_position(SYMBOL)
price = self.client.get_current_price(SYMBOL)
# 更新价格历史
self.grid.stats.add_price(price)
runtime = datetime.now() - self.session_start
hours = runtime.total_seconds() / 3600
# 系统状态
UI.header("系统状态")
UI.metric("运行时间", str(runtime).split('.')[0])
UI.metric("API权重", f"{self.client.api_weight}/1200")
# API权重进度条
weight_pct = self.client.api_weight / 1200
if weight_pct > 0.8:
bar_color = Colors.BRIGHT_RED
elif weight_pct > 0.6:
bar_color = Colors.BRIGHT_YELLOW
else:
bar_color = Colors.BRIGHT_GREEN
UI.progress_bar(weight_pct, width=40, color=bar_color)
print()
UI.separator()
# 市场数据
UI.header("市场数据")
print(f"{Colors.DIM}当前价格:{Colors.RESET} {UI.price_change(price, self.grid.previous_price)}")
# 价格迷你图
if len(self.grid.stats.price_history) > 1:
print(f"{Colors.DIM}价格趋势:{Colors.RESET} ", end="")
UI.sparkline(self.grid.stats.price_history, width=30)
self.grid.previous_price = price
print()
UI.separator()
# 账户信息
UI.header("账户信息")
UI.metric("总余额", f"${balance.get('total', 0):.2f} USDT")
UI.metric("可用余额", f"${balance.get('available', 0):.2f} USDT")
UI.metric("持仓数量", f"{position.get('positionAmt', 0):.4f} ETH")
UI.metric("持仓均价", f"${position.get('entryPrice', 0):.2f}")
unrealized = position.get('unRealizedProfit', 0)
if unrealized > 0:
print(f"{Colors.DIM}未实现盈亏:{Colors.RESET} {Colors.BRIGHT_GREEN}+${unrealized:.2f}{Colors.RESET}")
elif unrealized < 0:
print(f"{Colors.DIM}未实现盈亏:{Colors.RESET} {Colors.BRIGHT_RED}${unrealized:.2f}{Colors.RESET}")
else:
print(f"{Colors.DIM}未实现盈亏:{Colors.RESET} ${unrealized:.2f}")
print()
UI.separator()
# 交易统计
UI.header("交易统计")
UI.metric("总交易次数", f"{self.grid.stats.total_trades}")
win_rate = (self.grid.stats.win_trades / self.grid.stats.total_trades * 100) if self.grid.stats.total_trades > 0 else 0
if win_rate >= 60:
wr_color = Colors.BRIGHT_GREEN
elif win_rate >= 40:
wr_color = Colors.BRIGHT_YELLOW
else:
wr_color = Colors.BRIGHT_RED
print(f"{Colors.DIM}盈利/亏损:{Colors.RESET} {Colors.BRIGHT_GREEN}{self.grid.stats.win_trades}{Colors.RESET} / {Colors.BRIGHT_RED}{self.grid.stats.loss_trades}{Colors.RESET} ({wr_color}{win_rate:.1f}%{Colors.RESET})")
# 利润显示
gross = self.grid.stats.total_profit
fees = self.grid.stats.total_fees
net = self.grid.stats.net_profit
if gross > 0:
print(f"{Colors.DIM}毛利润:{Colors.RESET} {Colors.BRIGHT_GREEN}+${gross:.4f}{Colors.RESET}")
else:
print(f"{Colors.DIM}毛利润:{Colors.RESET} {Colors.BRIGHT_RED}${gross:.4f}{Colors.RESET}")
print(f"{Colors.DIM}总手续费:{Colors.RESET} {Colors.BRIGHT_RED}-${fees:.4f}{Colors.RESET}")
if net > 0:
print(f"{Colors.DIM}净利润:{Colors.RESET} {Colors.BOLD}{Colors.BRIGHT_GREEN}+${net:.4f}{Colors.RESET}")
else:
print(f"{Colors.DIM}净利润:{Colors.RESET} {Colors.BOLD}{Colors.BRIGHT_RED}${net:.4f}{Colors.RESET}")
# 利润趋势
if len(self.grid.stats.profit_history) > 1:
print(f"{Colors.DIM}利润趋势:{Colors.RESET} ", end="")
UI.sparkline(self.grid.stats.profit_history, width=30)
UI.metric("最大单笔盈利", f"${self.grid.stats.max_profit:.4f}")
UI.metric("最大单笔亏损", f"${self.grid.stats.max_loss:.4f}")
print()
UI.separator()
# 网格状态
UI.header("网格状态")
UI.metric("活跃订单", f"{len(self.grid.active_orders)}/{NUM_GRIDS * 2}")
# 订单健康度
order_health = len(self.grid.active_orders) / (NUM_GRIDS * 2)
if order_health > 0.8:
health_color = Colors.BRIGHT_GREEN
health_text = "健康"
elif order_health > 0.5:
health_color = Colors.BRIGHT_YELLOW
health_text = "良好"
else:
health_color = Colors.BRIGHT_RED
health_text = "需要重新平衡"
print(f"{Colors.DIM}网格健康度:{Colors.RESET} {health_color}{health_text}{Colors.RESET}")
UI.progress_bar(order_health, width=40, color=health_color)
print()
UI.separator()
# 性能指标
if hours > 0:
UI.header("性能指标")
trades_per_hour = self.grid.stats.total_trades / hours
profit_per_hour = net / hours
UI.metric("交易频率", f"{trades_per_hour:.2f} 笔/小时")
if profit_per_hour > 0:
print(f"{Colors.DIM}时均利润:{Colors.RESET} {Colors.BRIGHT_GREEN}+${profit_per_hour:.4f}/小时{Colors.RESET}")
else:
print(f"{Colors.DIM}时均利润:{Colors.RESET} {Colors.BRIGHT_RED}${profit_per_hour:.4f}/小时{Colors.RESET}")
# 预估日收益
daily_profit = profit_per_hour * 24
if daily_profit > 0:
print(f"{Colors.DIM}预估日收益:{Colors.RESET} {Colors.BRIGHT_GREEN}+${daily_profit:.4f}{Colors.RESET}")
else:
print(f"{Colors.DIM}预估日收益:{Colors.RESET} {Colors.BRIGHT_RED}${daily_profit:.4f}{Colors.RESET}")
print(f"\n{Colors.BRIGHT_BLACK}{'─' * 80}{Colors.RESET}")
print(f"{Colors.DIM}最后更新: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} | 按 Ctrl+C 停止{Colors.RESET}\n")
def run(self):
if not self.initialize():
return
self.is_running = True
# 显示启动信息
UI.clear_screen()
UI.box(
f"🚀 蚂蚁搬家 v3.0 PRO 已启动\n\n"
f"交易对: {SYMBOL}\n"
f"杠杆: {LEVERAGE}x\n"
f"网格间距: {GRID_SPREAD*100:.2f}%\n"
f"网格数量: {NUM_GRIDS}\n"
f"订单金额: ${ORDER_AMOUNT_USDT}\n\n"
f"✅ 手续费已计入计算 (Taker: {TAKER_FEE*100:.2f}%)\n"
f"✅ 批量下单优化\n"
f"✅ 智能缓存\n\n"
f"正在运行...",
color=Colors.BRIGHT_GREEN,
width=80
)
time.sleep(3)
last_check = time.time()
last_display = time.time()
while self.is_running:
try:
current_time = time.time()
# 检查订单
if current_time - last_check >= CHECK_INTERVAL:
last_check = current_time
self.grid.check_and_refill()
# 更新显示
if current_time - last_display >= DISPLAY_INTERVAL:
last_display = current_time
self.display_dashboard()
# 重新平衡
if current_time - self.last_rebalance >= 60:
self.last_rebalance = current_time
if len(self.grid.active_orders) < NUM_GRIDS:
UI.warning("网格订单不足,重新平衡...")
price = self.client.get_current_price(SYMBOL)
self.grid.setup_grid(price)
time.sleep(0.5)
except KeyboardInterrupt:
print(f"\n\n{Colors.BRIGHT_YELLOW}⚠ 收到停止信号...{Colors.RESET}")
break
except Exception as e:
UI.error(f"错误: {e}")
time.sleep(5)
self.stop()
def stop(self):
UI.header("停止交易")
self.is_running = False
self.client.cancel_all_orders(SYMBOL)
runtime = datetime.now() - self.session_start
# 最终统计
print()
UI.box(
f"交易会话结束\n\n"
f"运行时间: {str(runtime).split('.')[0]}\n"
f"总交易: {self.grid.stats.total_trades} 笔\n"
f"盈利交易: {self.grid.stats.win_trades} 笔\n"
f"亏损交易: {self.grid.stats.loss_trades} 笔\n\n"
f"毛利润: ${self.grid.stats.total_profit:.4f}\n"
f"手续费: ${self.grid.stats.total_fees:.4f}\n"
f"净利润: ${self.grid.stats.net_profit:.4f}",
color=Colors.BRIGHT_CYAN,
width=80
)
UI.success("系统已安全停止")
def main():
UI.clear_screen()
# 欢迎界面
print(f"""
{Colors.BRIGHT_CYAN}{Colors.BOLD}
╔════════════════════════════════════════════════════════════════════════════╗
║ ║
║ 🐜 蚂蚁搬家 v3.0 PRO 专业版 ║
║ ║
║ 现代化 · 可视化 · 智能化 ║
║ ║
╚════════════════════════════════════════════════════════════════════════════╝
{Colors.RESET}
""")
UI.header("系统特性")
print(f"{Colors.BRIGHT_GREEN}✓{Colors.RESET} 现代化科技感界面")
print(f"{Colors.BRIGHT_GREEN}✓{Colors.RESET} 实时数据可视化")
print(f"{Colors.BRIGHT_GREEN}✓{Colors.RESET} 手续费精确计算 (Maker: {MAKER_FEE*100:.2f}%, Taker: {TAKER_FEE*100:.2f}%)")
print(f"{Colors.BRIGHT_GREEN}✓{Colors.RESET} 批量下单优化 (降低90% API调用)")
print(f"{Colors.BRIGHT_GREEN}✓{Colors.RESET} 智能缓存机制")
print(f"{Colors.BRIGHT_GREEN}✓{Colors.RESET} 性能监控仪表板")
print()
UI.separator()
client = OptimizedClient(BINANCE_API_KEY, BINANCE_SECRET_KEY, BINANCE_BASE_URL)
grid = SmartGridEngine(client, SYMBOL)
UI.header("连接测试")
price = client.get_current_price(SYMBOL)
if price == 0:
UI.error("无法连接到交易所")
return
UI.success(f"连接成功 - {SYMBOL} 价格: ${price:.2f}")
print()
UI.separator()
UI.header("交易配置")
UI.metric("交易对", SYMBOL)
UI.metric("杠杆", f"{LEVERAGE}x")
UI.metric("网格间距", f"{GRID_SPREAD*100:.2f}%")
UI.metric("网格数量", f"{NUM_GRIDS}")
UI.metric("订单金额", f"${ORDER_AMOUNT_USDT}")
UI.metric("Maker手续费", f"{MAKER_FEE*100:.2f}%")
UI.metric("Taker手续费", f"{TAKER_FEE*100:.2f}%")
print()
UI.separator()
print()
confirm = input(f"{Colors.BRIGHT_YELLOW}启动交易机器人? (yes/no): {Colors.RESET}")
if confirm.lower() != 'yes':
UI.info("已取消")
return
bot = ProBot(client, grid)
try:
bot.run()
except KeyboardInterrupt:
pass
finally:
print(f"\n{Colors.BRIGHT_GREEN}✓ 程序退出{Colors.RESET}\n")
if __name__ == '__main__':
main()