From 887899749fb4d52ef7bc69e96265cbf3842c2826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=20=E5=BF=97?= Date: Thu, 30 Oct 2025 08:28:42 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20hyperliquid=E4=BD=99=E9=A2=9D=E4=B8=8D?= =?UTF-8?q?=E5=87=86=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config.go | 45 +++++++++++++++++----------------- go.sum | 2 ++ manager/trader_manager.go | 1 + trader/auto_trader.go | 3 ++- trader/hyperliquid_trader.go | 47 ++++++++++++++++++------------------ web/vite.config.ts | 1 + 6 files changed, 52 insertions(+), 47 deletions(-) diff --git a/config/config.go b/config/config.go index 7c3626ae..8b843b53 100644 --- a/config/config.go +++ b/config/config.go @@ -9,19 +9,20 @@ import ( // TraderConfig 单个trader的配置 type TraderConfig struct { - ID string `json:"id"` - Name string `json:"name"` - AIModel string `json:"ai_model"` // "qwen" or "deepseek" + ID string `json:"id"` + Name string `json:"name"` + AIModel string `json:"ai_model"` // "qwen" or "deepseek" // 交易平台选择(二选一) - Exchange string `json:"exchange"` // "binance" or "hyperliquid" + Exchange string `json:"exchange"` // "binance" or "hyperliquid" // 币安配置 - BinanceAPIKey string `json:"binance_api_key,omitempty"` - BinanceSecretKey string `json:"binance_secret_key,omitempty"` + BinanceAPIKey string `json:"binance_api_key,omitempty"` + BinanceSecretKey string `json:"binance_secret_key,omitempty"` // Hyperliquid配置 HyperliquidPrivateKey string `json:"hyperliquid_private_key,omitempty"` + HyperliquidWalletAddr string `json:"hyperliquid_wallet_addr,omitempty"` HyperliquidTestnet bool `json:"hyperliquid_testnet,omitempty"` // Aster配置 @@ -30,13 +31,13 @@ type TraderConfig struct { AsterPrivateKey string `json:"aster_private_key,omitempty"` // Aster API钱包私钥 // AI配置 - QwenKey string `json:"qwen_key,omitempty"` - DeepSeekKey string `json:"deepseek_key,omitempty"` + QwenKey string `json:"qwen_key,omitempty"` + DeepSeekKey string `json:"deepseek_key,omitempty"` // 自定义AI API配置(支持任何OpenAI格式的API) - CustomAPIURL string `json:"custom_api_url,omitempty"` - CustomAPIKey string `json:"custom_api_key,omitempty"` - CustomModelName string `json:"custom_model_name,omitempty"` + CustomAPIURL string `json:"custom_api_url,omitempty"` + CustomAPIKey string `json:"custom_api_key,omitempty"` + CustomModelName string `json:"custom_model_name,omitempty"` InitialBalance float64 `json:"initial_balance"` ScanIntervalMinutes int `json:"scan_interval_minutes"` @@ -44,15 +45,15 @@ type TraderConfig struct { // LeverageConfig 杠杆配置 type LeverageConfig struct { - BTCETHLeverage int `json:"btc_eth_leverage"` // BTC和ETH的杠杆倍数(主账户建议5-50,子账户≤5) - AltcoinLeverage int `json:"altcoin_leverage"` // 山寨币的杠杆倍数(主账户建议5-20,子账户≤5) + BTCETHLeverage int `json:"btc_eth_leverage"` // BTC和ETH的杠杆倍数(主账户建议5-50,子账户≤5) + AltcoinLeverage int `json:"altcoin_leverage"` // 山寨币的杠杆倍数(主账户建议5-20,子账户≤5) } // Config 总配置 type Config struct { Traders []TraderConfig `json:"traders"` - UseDefaultCoins bool `json:"use_default_coins"` // 是否使用默认主流币种列表 - DefaultCoins []string `json:"default_coins"` // 默认主流币种池 + UseDefaultCoins bool `json:"use_default_coins"` // 是否使用默认主流币种列表 + DefaultCoins []string `json:"default_coins"` // 默认主流币种池 CoinPoolAPIURL string `json:"coin_pool_api_url"` OITopAPIURL string `json:"oi_top_api_url"` APIServerPort int `json:"api_server_port"` @@ -83,13 +84,13 @@ func LoadConfig(filename string) (*Config, error) { if len(config.DefaultCoins) == 0 { config.DefaultCoins = []string{ "BTCUSDT", - "ETHUSDT", - "SOLUSDT", - "BNBUSDT", - "XRPUSDT", - "DOGEUSDT", - "ADAUSDT", - "HYPEUSDT", + "ETHUSDT", + "SOLUSDT", + "BNBUSDT", + "XRPUSDT", + "DOGEUSDT", + "ADAUSDT", + "HYPEUSDT", } } diff --git a/go.sum b/go.sum index c30f7b02..2cd01ad0 100644 --- a/go.sum +++ b/go.sum @@ -74,6 +74,8 @@ github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= diff --git a/manager/trader_manager.go b/manager/trader_manager.go index cb01508e..20b61c46 100644 --- a/manager/trader_manager.go +++ b/manager/trader_manager.go @@ -40,6 +40,7 @@ func (tm *TraderManager) AddTrader(cfg config.TraderConfig, coinPoolURL string, BinanceAPIKey: cfg.BinanceAPIKey, BinanceSecretKey: cfg.BinanceSecretKey, HyperliquidPrivateKey: cfg.HyperliquidPrivateKey, + HyperliquidWalletAddr: cfg.HyperliquidWalletAddr, HyperliquidTestnet: cfg.HyperliquidTestnet, AsterUser: cfg.AsterUser, AsterSigner: cfg.AsterSigner, diff --git a/trader/auto_trader.go b/trader/auto_trader.go index 30437933..0d53ea3d 100644 --- a/trader/auto_trader.go +++ b/trader/auto_trader.go @@ -29,6 +29,7 @@ type AutoTraderConfig struct { // Hyperliquid配置 HyperliquidPrivateKey string + HyperliquidWalletAddr string HyperliquidTestnet bool // Aster配置 @@ -138,7 +139,7 @@ func NewAutoTrader(config AutoTraderConfig) (*AutoTrader, error) { trader = NewFuturesTrader(config.BinanceAPIKey, config.BinanceSecretKey) case "hyperliquid": log.Printf("🏦 [%s] 使用Hyperliquid交易", config.Name) - trader, err = NewHyperliquidTrader(config.HyperliquidPrivateKey, config.HyperliquidTestnet) + trader, err = NewHyperliquidTrader(config.HyperliquidPrivateKey, config.HyperliquidWalletAddr, config.HyperliquidTestnet) if err != nil { return nil, fmt.Errorf("初始化Hyperliquid交易器失败: %w", err) } diff --git a/trader/hyperliquid_trader.go b/trader/hyperliquid_trader.go index a9402209..c37494d6 100644 --- a/trader/hyperliquid_trader.go +++ b/trader/hyperliquid_trader.go @@ -2,7 +2,6 @@ package trader import ( "context" - "crypto/ecdsa" "fmt" "log" "strconv" @@ -20,7 +19,7 @@ type HyperliquidTrader struct { } // NewHyperliquidTrader 创建Hyperliquid交易器 -func NewHyperliquidTrader(privateKeyHex string, testnet bool) (*HyperliquidTrader, error) { +func NewHyperliquidTrader(privateKeyHex string, walletAddr string, testnet bool) (*HyperliquidTrader, error) { // 解析私钥 privateKey, err := crypto.HexToECDSA(privateKeyHex) if err != nil { @@ -33,13 +32,13 @@ func NewHyperliquidTrader(privateKeyHex string, testnet bool) (*HyperliquidTrade apiURL = hyperliquid.TestnetAPIURL } - // 从私钥生成钱包地址 - pubKey := privateKey.Public() - publicKeyECDSA, ok := pubKey.(*ecdsa.PublicKey) - if !ok { - return nil, fmt.Errorf("无法转换公钥") - } - walletAddr := crypto.PubkeyToAddress(*publicKeyECDSA).Hex() + // // 从私钥生成钱包地址 + // pubKey := privateKey.Public() + // publicKeyECDSA, ok := pubKey.(*ecdsa.PublicKey) + // if !ok { + // return nil, fmt.Errorf("无法转换公钥") + // } + // walletAddr := crypto.PubkeyToAddress(*publicKeyECDSA).Hex() ctx := context.Background() @@ -99,9 +98,9 @@ func (t *HyperliquidTrader) GetBalance() (map[string]interface{}, error) { // 钱包余额(已实现)= AccountValue - 未实现盈亏 walletBalance := accountValue - totalUnrealizedPnl - result["totalWalletBalance"] = walletBalance // 钱包余额(已实现部分) - result["availableBalance"] = accountValue - totalMarginUsed // 可用余额 - result["totalUnrealizedProfit"] = totalUnrealizedPnl // 未实现盈亏 + result["totalWalletBalance"] = walletBalance // 钱包余额(已实现部分) + result["availableBalance"] = accountValue - totalMarginUsed // 可用余额 + result["totalUnrealizedProfit"] = totalUnrealizedPnl // 未实现盈亏 log.Printf("✓ Hyperliquid API返回: 账户净值=%.2f, 钱包余额=%.2f, 可用=%.2f, 未实现盈亏=%.2f", accountValue, @@ -515,8 +514,8 @@ func (t *HyperliquidTrader) SetStopLoss(symbol string, positionSide string, quan order := hyperliquid.CreateOrderRequest{ Coin: coin, IsBuy: isBuy, - Size: roundedQuantity, // 使用四舍五入后的数量 - Price: roundedStopPrice, // 使用处理后的价格 + Size: roundedQuantity, // 使用四舍五入后的数量 + Price: roundedStopPrice, // 使用处理后的价格 OrderType: hyperliquid.OrderType{ Trigger: &hyperliquid.TriggerOrderType{ TriggerPx: roundedStopPrice, @@ -552,8 +551,8 @@ func (t *HyperliquidTrader) SetTakeProfit(symbol string, positionSide string, qu order := hyperliquid.CreateOrderRequest{ Coin: coin, IsBuy: isBuy, - Size: roundedQuantity, // 使用四舍五入后的数量 - Price: roundedTakeProfitPrice, // 使用处理后的价格 + Size: roundedQuantity, // 使用四舍五入后的数量 + Price: roundedTakeProfitPrice, // 使用处理后的价格 OrderType: hyperliquid.OrderType{ Trigger: &hyperliquid.TriggerOrderType{ TriggerPx: roundedTakeProfitPrice, @@ -577,7 +576,7 @@ func (t *HyperliquidTrader) SetTakeProfit(symbol string, positionSide string, qu func (t *HyperliquidTrader) FormatQuantity(symbol string, quantity float64) (string, error) { coin := convertSymbolToHyperliquid(symbol) szDecimals := t.getSzDecimals(coin) - + // 使用szDecimals格式化数量 formatStr := fmt.Sprintf("%%.%df", szDecimals) return fmt.Sprintf(formatStr, quantity), nil @@ -604,13 +603,13 @@ func (t *HyperliquidTrader) getSzDecimals(coin string) int { // roundToSzDecimals 将数量四舍五入到正确的精度 func (t *HyperliquidTrader) roundToSzDecimals(coin string, quantity float64) float64 { szDecimals := t.getSzDecimals(coin) - + // 计算倍数(10^szDecimals) multiplier := 1.0 for i := 0; i < szDecimals; i++ { multiplier *= 10.0 } - + // 四舍五入 return float64(int(quantity*multiplier+0.5)) / multiplier } @@ -621,9 +620,9 @@ func (t *HyperliquidTrader) roundPriceToSigfigs(price float64) float64 { if price == 0 { return 0 } - + const sigfigs = 5 // Hyperliquid标准:5位有效数字 - + // 计算价格的数量级 var magnitude float64 if price < 0 { @@ -631,7 +630,7 @@ func (t *HyperliquidTrader) roundPriceToSigfigs(price float64) float64 { } else { magnitude = price } - + // 计算需要的倍数 multiplier := 1.0 for magnitude >= 10 { @@ -642,12 +641,12 @@ func (t *HyperliquidTrader) roundPriceToSigfigs(price float64) float64 { magnitude *= 10 multiplier *= 10 } - + // 应用有效数字精度 for i := 0; i < sigfigs-1; i++ { multiplier *= 10 } - + // 四舍五入 rounded := float64(int(price*multiplier+0.5)) / multiplier return rounded diff --git a/web/vite.config.ts b/web/vite.config.ts index 3e35b475..150bbec9 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -4,6 +4,7 @@ import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], server: { + host: '0.0.0.0', port: 3000, proxy: { '/api': {