stock-ai-agent/backend/test_hyperliquid.py
aaron a22dfe459c feat: Add Hyperliquid trading integration with ClawFi
- Add hyperliquid_trading_service.py with position management and TP/SL
- Implement dual-track trading (paper trading + Hyperliquid)
- Add position size calculation based on available margin
- Support net position mode (Hyperliquid) vs order mode (paper)
- Add risk controls: 10% circuit breaker, 10x max leverage
- Add test script for Hyperliquid SDK validation
2026-03-22 11:42:25 +08:00

308 lines
9.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Hyperliquid SDK 测试脚本
用于验证 Hyperliquid 集成是否正常工作
⚠️ 警告:此脚本仅执行查询操作,不会执行任何交易
"""
import os
import sys
from typing import Dict, Any
# 添加项目路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
def test_sdk_import():
"""测试 SDK 导入"""
print("\n" + "="*60)
print("📦 测试 1: SDK 导入")
print("="*60)
try:
from hyperliquid.info import Info
from hyperliquid.exchange import Exchange
from eth_account import Account
print("✅ SDK 导入成功")
return True
except ImportError as e:
print(f"❌ SDK 导入失败: {e}")
print("\n请运行以下命令安装 SDK:")
print(" npx clawfi-hyperliquid-skill --wallet=YOUR_WALLET --key=YOUR_KEY")
return False
def test_env_variables():
"""测试环境变量"""
print("\n" + "="*60)
print("🔑 测试 2: 环境变量")
print("="*60)
wallet = os.getenv("CLAWFI_WALLET_ADDRESS")
private_key = os.getenv("CLAWFI_PRIVATE_KEY")
if not wallet:
print("❌ CLAWFI_WALLET_ADDRESS 未设置")
print("\n请运行以下命令设置环境变量:")
print(" npx clawfi-hyperliquid-skill --wallet=YOUR_WALLET --key=YOUR_KEY")
return False
if not private_key:
print("❌ CLAWFI_PRIVATE_KEY 未设置")
print("\n请运行以下命令设置环境变量:")
print(" npx clawfi-hyperliquid-skill --wallet=YOUR_WALLET --key=YOUR_KEY")
return False
print(f"✅ CLAWFI_WALLET_ADDRESS: {wallet}")
print(f"✅ CLAWFI_PRIVATE_KEY: {private_key[:10]}...{private_key[-4:]}")
return True
def test_connection(wallet: str, private_key: str):
"""测试连接和基础查询"""
print("\n" + "="*60)
print("🔗 测试 3: 连接 Hyperliquid")
print("="*60)
try:
from hyperliquid.info import Info
from hyperliquid.exchange import Exchange
from eth_account import Account
# 初始化
account = Account.from_key(private_key)
info = Info(base_url="https://api.hyperliquid.xyz", skip_ws=True)
exchange = Exchange(account, base_url="https://api.hyperliquid.xyz",
account_address=wallet)
print(f"✅ Agent 地址: {account.address}")
print(f"✅ 目标钱包: {wallet}")
# 测试查询账户状态
print("\n📊 查询账户状态...")
user_state = info.user_state(wallet)
if not user_state:
print("❌ 无法获取账户状态")
return False
# 账户价值
margin_summary = user_state.get("marginSummary", {})
account_value = float(margin_summary.get("accountValue", 0))
withdrawable = float(margin_summary.get("withdrawable", 0))
total_margin_used = float(margin_summary.get("totalMarginUsed", 0))
print(f"✅ 账户价值: ${account_value:,.2f}")
print(f"✅ 可提取: ${withdrawable:,.2f}")
print(f"✅ 已用保证金: ${total_margin_used:,.2f}")
# 查询持仓
print("\n📈 查询持仓...")
positions = user_state.get("assetPositions", [])
if not positions:
print("✅ 无持仓")
else:
open_positions = []
for pos in positions:
p = pos.get("position", {})
size = float(p.get("szi", 0))
if size != 0:
open_positions.append({
"coin": p.get("coin"),
"size": size,
"entry_px": float(p.get("entryPx", 0)),
"unrealized_pnl": float(p.get("unrealizedPnl", 0))
})
if not open_positions:
print("✅ 无活跃持仓")
else:
print(f"✅ 活跃持仓数: {len(open_positions)}")
for pos in open_positions:
side = "做多" if pos["size"] > 0 else "做空"
print(f" {pos['coin']}: {side} {abs(pos['size'])} @ ${pos['entry_px']:,.2f} | "
f"PnL: ${pos['unrealized_pnl']:,.2f}")
# 查询挂单
print("\n📋 查询挂单...")
open_orders = user_state.get("openOrders", [])
if not open_orders:
print("✅ 无挂单")
else:
print(f"✅ 挂单数: {len(open_orders)}")
for order in open_orders:
coin = order.get("coin")
side = order.get("side")
size = float(order.get("totalSz", 0))
limit_px = float(order.get("limitPx", 0))
print(f" {coin}: {side} {size} @ ${limit_px:,.2f}")
return True
except Exception as e:
print(f"❌ 连接失败: {e}")
import traceback
traceback.print_exc()
return False
def test_tick_size():
"""测试获取 tick size"""
print("\n" + "="*60)
print("📏 测试 4: 获取 Tick Size")
print("="*60)
try:
from hyperliquid.info import Info
info = Info(base_url="https://api.hyperliquid.xyz", skip_ws=True)
# 获取元数据
meta = info.meta()
universe = meta.get("universe", [])
print(f"✅ 可交易币种数: {len(universe)}")
# 显示前几个币种的 tick size
for asset in universe[:5]:
name = asset.get("name")
tick_size = float(asset.get("tickSize", 1.0))
sz_decimals = asset.get("szDecimals", 5)
print(f" {name}: tick_size={tick_size}, sz_decimals={sz_decimals}")
return True
except Exception as e:
print(f"❌ 获取 tick size 失败: {e}")
return False
def test_service_initialization():
"""测试服务初始化"""
print("\n" + "="*60)
print("🔧 测试 5: 服务初始化")
print("="*60)
try:
from app.services.hyperliquid_trading_service import get_hyperliquid_service
# 尝试获取服务(如果未启用会返回 None
service = get_hyperliquid_service()
if service is None:
print("⚠️ Hyperliquid 服务未启用hyperliquid_trading_enabled=False")
print(" 要启用服务,请在 .env 文件中设置: hyperliquid_trading_enabled=true")
return False
print("✅ Hyperliquid 服务初始化成功")
print(f" 钱包地址: {service.wallet_address}")
print(f" 最大杠杆: {service.max_total_leverage}x")
print(f" 熔断阈值: {service.circuit_breaker_drawdown * 100}%")
print(f" 单笔最大持仓: ${service.max_single_position}")
# 测试获取账户状态
print("\n📊 测试获取账户状态...")
state = service.get_account_state()
print(f"✅ 账户价值: ${state['account_value']:,.2f}")
print(f"✅ 可用余额: ${state['available_balance']:,.2f}")
# 测试获取持仓
print("\n📈 测试获取持仓...")
positions = service.get_open_positions()
if positions:
print(f"✅ 活跃持仓: {len(positions)}")
for pos in positions:
side = "做多" if pos["size"] > 0 else "做空"
print(f" {pos['coin']}: {side} {abs(pos['size'])}")
else:
print("✅ 无活跃持仓")
# 测试获取止盈止损价格
print("\n🛡️ 测试获取止盈止损...")
if positions:
for pos in positions:
tp_sl = service.get_tp_sl_prices(pos["coin"])
print(f" {pos['coin']}: TP={tp_sl['take_profit']}, SL={tp_sl['stop_loss']}")
else:
# 测试 BTC 的止盈止损(即使没有持仓)
tp_sl = service.get_tp_sl_prices("BTC")
print(f" BTC: TP={tp_sl['take_profit']}, SL={tp_sl['stop_loss']}")
return True
except Exception as e:
print(f"❌ 服务初始化失败: {e}")
import traceback
traceback.print_exc()
return False
def main():
"""主测试流程"""
print("\n" + "🦅"*30)
print(" Hyperliquid 集成测试")
print("🦅"*30)
results = {}
# 测试 1: SDK 导入
results["sdk_import"] = test_sdk_import()
if not results["sdk_import"]:
print("\n❌ SDK 导入失败,无法继续测试")
return False
# 测试 2: 环境变量
results["env_vars"] = test_env_variables()
if not results["env_vars"]:
print("\n❌ 环境变量未设置,无法继续测试")
return False
# 获取环境变量
wallet = os.getenv("CLAWFI_WALLET_ADDRESS")
private_key = os.getenv("CLAWFI_PRIVATE_KEY")
# 测试 3: 连接
results["connection"] = test_connection(wallet, private_key)
if not results["connection"]:
print("\n⚠️ 连接测试失败,但继续测试其他功能")
# 测试 4: Tick size
results["tick_size"] = test_tick_size()
# 测试 5: 服务初始化
results["service"] = test_service_initialization()
# 总结
print("\n" + "="*60)
print("📊 测试结果总结")
print("="*60)
for test_name, result in results.items():
status = "✅ 通过" if result else "❌ 失败"
print(f" {test_name}: {status}")
all_passed = all(results.values())
if all_passed:
print("\n🎉 所有测试通过Hyperliquid 集成正常工作")
else:
print("\n⚠️ 部分测试失败,请检查上述错误信息")
return all_passed
if __name__ == "__main__":
try:
success = main()
sys.exit(0 if success else 1)
except KeyboardInterrupt:
print("\n\n⚠️ 测试被用户中断")
sys.exit(1)
except Exception as e:
print(f"\n\n❌ 测试过程中发生异常: {e}")
import traceback
traceback.print_exc()
sys.exit(1)