feat(trader): wire Hyperliquid wallet and quick trade flow

- Add wallet API endpoints and exchange storage fields for Hyperliquid

- Normalize quick trade order paths, symbols, and builder fee coverage

- Add frontend wallet connect and quick trade helpers
This commit is contained in:
tinklefund
2026-05-25 01:24:58 +08:00
parent f37fc9f887
commit c7c003cc3c
16 changed files with 1731 additions and 253 deletions

View File

@@ -7,6 +7,7 @@ import (
"nofx/store"
"nofx/trader"
"sort"
"strings"
"sync"
"time"
)
@@ -410,6 +411,34 @@ func (tm *TraderManager) RemoveTrader(traderID string) {
}
}
func ensureHyperliquidNativeStrategy(traderName, exchangeType string, cfg *store.StrategyConfig) {
if cfg == nil || strings.ToLower(strings.TrimSpace(exchangeType)) != "hyperliquid" {
return
}
source := strings.ToLower(strings.TrimSpace(cfg.CoinSource.SourceType))
if source == "hyper_rank" || source == "static" || source == "hyper_all" || source == "hyper_main" {
return
}
logger.Warnf("⚠️ Trader %s uses legacy coin source %q on Hyperliquid; forcing native stock ranking to avoid crypto fallback", traderName, cfg.CoinSource.SourceType)
cfg.CoinSource.SourceType = "hyper_rank"
cfg.CoinSource.UseAI500 = false
cfg.CoinSource.UseOITop = false
cfg.CoinSource.UseOILow = false
cfg.CoinSource.UseHyperAll = false
cfg.CoinSource.UseHyperMain = false
if cfg.CoinSource.HyperRankCategory == "" {
cfg.CoinSource.HyperRankCategory = "stock"
}
if cfg.CoinSource.HyperRankDirection == "" {
cfg.CoinSource.HyperRankDirection = "gainers"
}
if cfg.CoinSource.HyperRankLimit <= 0 {
cfg.CoinSource.HyperRankLimit = 5
}
}
// LoadUserTradersFromStore loads traders from store for a specific user to memory
func (tm *TraderManager) LoadUserTradersFromStore(st *store.Store, userID string) error {
tm.mu.Lock()
@@ -627,10 +656,15 @@ func (tm *TraderManager) addTraderFromStore(traderCfg *store.Trader, aiModelCfg
return fmt.Errorf("failed to parse strategy config for trader %s: %w", traderCfg.Name, err)
}
logger.Infof("✓ Trader %s loaded strategy config: %s", traderCfg.Name, strategy.Name)
ensureHyperliquidNativeStrategy(traderCfg.Name, exchangeCfg.ExchangeType, strategyConfig)
} else {
return fmt.Errorf("trader %s has no strategy configured", traderCfg.Name)
}
if exchangeCfg.ExchangeType == "hyperliquid" && !exchangeCfg.HyperliquidBuilderApproved {
return fmt.Errorf("Hyperliquid trading authorization is incomplete for exchange %s; reconnect Hyperliquid wallet and complete trading authorization before starting trader %s", exchangeCfg.AccountName, traderCfg.Name)
}
// Build AutoTraderConfig (ai500APIURL/oiTopAPIURL obtained from strategy config, used in StrategyEngine)
traderConfig := trader.AutoTraderConfig{
ID: traderCfg.ID,