129 lines
4.3 KiB
Python
129 lines
4.3 KiB
Python
"""
|
|
Hyperliquid 接入测试脚本
|
|
|
|
用法:
|
|
source venv/bin/activate
|
|
HL_API_PRIVATE_KEY="0x你的API钱包私钥" \
|
|
HL_ACCOUNT_ADDRESS="0x你的MetaMask地址" \
|
|
python scripts/test_hyperliquid.py
|
|
|
|
会做以下验证(只读,不下单):
|
|
1. 连通性检查
|
|
2. 账户 USDC 余额
|
|
3. BTC-PERP 当前价格
|
|
4. 当前持仓
|
|
5. 模拟开仓参数(不实际下单)
|
|
|
|
加 --trade 参数才会真正下一个 0.001 BTC 的小仓位并立即平掉(mainnet 慎用)
|
|
"""
|
|
|
|
import asyncio
|
|
import argparse
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from app.services.hyperliquid import HyperliquidTrader
|
|
|
|
|
|
async def main(do_trade: bool):
|
|
api_key = os.getenv("HL_API_PRIVATE_KEY") or os.getenv("HL_API_KEY", "")
|
|
account = os.getenv("HL_ACCOUNT_ADDRESS", "")
|
|
|
|
if not api_key:
|
|
print("❌ 缺少 HL_API_PRIVATE_KEY 环境变量")
|
|
print(" export HL_API_PRIVATE_KEY='0x你的API钱包私钥'")
|
|
sys.exit(1)
|
|
if not account:
|
|
print("❌ 缺少 HL_ACCOUNT_ADDRESS 环境变量")
|
|
print(" export HL_ACCOUNT_ADDRESS='0x你的MetaMask地址'")
|
|
sys.exit(1)
|
|
|
|
mainnet = os.getenv("HL_MAINNET", "true").lower() != "false"
|
|
net_label = "MAINNET" if mainnet else "TESTNET"
|
|
print(f"\n=== Hyperliquid 接入测试 ({net_label}) ===\n")
|
|
|
|
trader = HyperliquidTrader(
|
|
api_private_key=api_key,
|
|
account_address=account,
|
|
leverage=3,
|
|
mainnet=mainnet,
|
|
)
|
|
|
|
# 1. USDC 余额
|
|
print("① 查询 USDC 余额...")
|
|
balance = await trader.get_balance()
|
|
print(f" 可提取余额: ${balance:.2f} USDC")
|
|
if balance < 10:
|
|
print(" ⚠️ 余额不足 $10,交易可能失败")
|
|
else:
|
|
print(" ✅ 余额充足")
|
|
|
|
# 2. BTC mid price
|
|
print("\n② 查询 BTC-PERP 价格...")
|
|
try:
|
|
from hyperliquid.info import Info
|
|
base_url = "https://api.hyperliquid.xyz" if mainnet else "https://api.hyperliquid-testnet.xyz"
|
|
info = Info(base_url, skip_ws=True)
|
|
mids = info.all_mids()
|
|
btc_price = float(mids.get("BTC", 0))
|
|
print(f" BTC mid price: ${btc_price:,.2f}")
|
|
print(" ✅ 价格获取正常")
|
|
except Exception as e:
|
|
print(f" ❌ 价格获取失败: {e}")
|
|
|
|
# 3. 当前持仓
|
|
print("\n③ 查询当前持仓...")
|
|
positions = await trader.get_open_positions()
|
|
if positions:
|
|
for p in positions:
|
|
side = "多" if p["szi"] > 0 else "空"
|
|
print(f" {p['coin']} {side}仓: {abs(p['szi'])} 张 @ 均价 ${p['entry_px']:,.2f} 未实现盈亏: ${p['unrealized_pnl']:.2f}")
|
|
print(f" 共 {len(positions)} 个持仓")
|
|
else:
|
|
print(" 无持仓 ✅")
|
|
|
|
# 4. 模拟开仓参数
|
|
print("\n④ 模拟开仓参数(不实际下单)...")
|
|
sz_dec = await trader._get_sz_decimals("BTC")
|
|
mid = await trader._mid_price("BTC")
|
|
size_usd = 100
|
|
size_coins = round(size_usd / mid, sz_dec)
|
|
limit_buy = round(mid * 1.01, 1)
|
|
print(f" 开多 $100 notional:")
|
|
print(f" → 数量: {size_coins} BTC")
|
|
print(f" → 限价(1%滑点): ${limit_buy:,.1f}")
|
|
print(f" → 杠杆: 3x 隔离保证金")
|
|
print(f" → 所需保证金: ${size_usd / 3:.2f} USDC")
|
|
|
|
# 5. 真实测试下单(需要 --trade 参数)
|
|
if do_trade:
|
|
print(f"\n⑤ 真实下单测试 (0.001 BTC long → 立即平仓)...")
|
|
if not mainnet:
|
|
print(" 使用 testnet,无需担心资金损失")
|
|
else:
|
|
print(" ⚠️ MAINNET 真实资金!继续中...")
|
|
|
|
try:
|
|
result = await trader.open_position("BTC", "long", size_usd=50)
|
|
print(f" ✅ 开仓成功: fill_price=${result['fill_price']:,.2f}, size={result['size_coins']} BTC")
|
|
|
|
await asyncio.sleep(2)
|
|
|
|
close = await trader.close_position("BTC")
|
|
print(f" ✅ 平仓成功: fill_price=${close['fill_price']:,.2f}")
|
|
except Exception as e:
|
|
print(f" ❌ 下单失败: {e}")
|
|
else:
|
|
print("\n提示: 加 --trade 参数进行真实下单+平仓测试")
|
|
|
|
print("\n=== 测试完成 ===")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--trade", action="store_true", help="执行真实下单+平仓测试")
|
|
args = parser.parse_args()
|
|
asyncio.run(main(args.trade))
|