mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-15 16:56:56 +08:00
feat(gate): complete Gate.io exchange integration with trader refactoring
Gate.io Integration: - Add Gate trader with full Trader interface implementation - Add order_sync.go for background trade synchronization - Fix quantity display (convert contracts to actual tokens via quanto_multiplier) - Fix fill price return in OpenLong/OpenShort/CloseLong/CloseShort - Add Gate-specific CoinAnk K-line data source support - Add Gate to supported exchanges in frontend and backend - Add Gate/KuCoin logo SVG icons Trader Package Refactoring: - Move exchange-specific code into subdirectories (binance/, bybit/, okx/, bitget/, hyperliquid/, aster/, lighter/, gate/) - Create types/ package for shared types to avoid circular dependencies - Move TraderTestSuite to trader/testutil package to avoid import cycles - Update market.GetWithExchange to support exchange-specific data
This commit is contained in:
@@ -4,12 +4,20 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"nofx/kernel"
|
||||
"nofx/experience"
|
||||
"nofx/kernel"
|
||||
"nofx/logger"
|
||||
"nofx/market"
|
||||
"nofx/mcp"
|
||||
"nofx/store"
|
||||
"nofx/trader/aster"
|
||||
"nofx/trader/binance"
|
||||
"nofx/trader/bitget"
|
||||
"nofx/trader/bybit"
|
||||
"nofx/trader/gate"
|
||||
"nofx/trader/hyperliquid"
|
||||
"nofx/trader/lighter"
|
||||
"nofx/trader/okx"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -23,7 +31,7 @@ type AutoTraderConfig struct {
|
||||
AIModel string // AI model: "qwen" or "deepseek"
|
||||
|
||||
// Trading platform selection
|
||||
Exchange string // Exchange type: "binance", "bybit", "okx", "bitget", "hyperliquid", "aster" or "lighter"
|
||||
Exchange string // Exchange type: "binance", "bybit", "okx", "bitget", "gate", "hyperliquid", "aster" or "lighter"
|
||||
ExchangeID string // Exchange account UUID (for multi-account support)
|
||||
|
||||
// Binance API configuration
|
||||
@@ -44,6 +52,10 @@ type AutoTraderConfig struct {
|
||||
BitgetSecretKey string
|
||||
BitgetPassphrase string
|
||||
|
||||
// Gate API configuration
|
||||
GateAPIKey string
|
||||
GateSecretKey string
|
||||
|
||||
// Hyperliquid configuration
|
||||
HyperliquidPrivateKey string
|
||||
HyperliquidWalletAddr string
|
||||
@@ -224,25 +236,28 @@ func NewAutoTrader(config AutoTraderConfig, st *store.Store, userID string) (*Au
|
||||
switch config.Exchange {
|
||||
case "binance":
|
||||
logger.Infof("🏦 [%s] Using Binance Futures trading", config.Name)
|
||||
trader = NewFuturesTrader(config.BinanceAPIKey, config.BinanceSecretKey, userID)
|
||||
trader = binance.NewFuturesTrader(config.BinanceAPIKey, config.BinanceSecretKey, userID)
|
||||
case "bybit":
|
||||
logger.Infof("🏦 [%s] Using Bybit Futures trading", config.Name)
|
||||
trader = NewBybitTrader(config.BybitAPIKey, config.BybitSecretKey)
|
||||
trader = bybit.NewBybitTrader(config.BybitAPIKey, config.BybitSecretKey)
|
||||
case "okx":
|
||||
logger.Infof("🏦 [%s] Using OKX Futures trading", config.Name)
|
||||
trader = NewOKXTrader(config.OKXAPIKey, config.OKXSecretKey, config.OKXPassphrase)
|
||||
trader = okx.NewOKXTrader(config.OKXAPIKey, config.OKXSecretKey, config.OKXPassphrase)
|
||||
case "bitget":
|
||||
logger.Infof("🏦 [%s] Using Bitget Futures trading", config.Name)
|
||||
trader = NewBitgetTrader(config.BitgetAPIKey, config.BitgetSecretKey, config.BitgetPassphrase)
|
||||
trader = bitget.NewBitgetTrader(config.BitgetAPIKey, config.BitgetSecretKey, config.BitgetPassphrase)
|
||||
case "gate":
|
||||
logger.Infof("🏦 [%s] Using Gate.io Futures trading", config.Name)
|
||||
trader = gate.NewGateTrader(config.GateAPIKey, config.GateSecretKey)
|
||||
case "hyperliquid":
|
||||
logger.Infof("🏦 [%s] Using Hyperliquid trading", config.Name)
|
||||
trader, err = NewHyperliquidTrader(config.HyperliquidPrivateKey, config.HyperliquidWalletAddr, config.HyperliquidTestnet)
|
||||
trader, err = hyperliquid.NewHyperliquidTrader(config.HyperliquidPrivateKey, config.HyperliquidWalletAddr, config.HyperliquidTestnet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize Hyperliquid trader: %w", err)
|
||||
}
|
||||
case "aster":
|
||||
logger.Infof("🏦 [%s] Using Aster trading", config.Name)
|
||||
trader, err = NewAsterTrader(config.AsterUser, config.AsterSigner, config.AsterPrivateKey)
|
||||
trader, err = aster.NewAsterTrader(config.AsterUser, config.AsterSigner, config.AsterPrivateKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize Aster trader: %w", err)
|
||||
}
|
||||
@@ -254,7 +269,7 @@ func NewAutoTrader(config AutoTraderConfig, st *store.Store, userID string) (*Au
|
||||
}
|
||||
|
||||
// Lighter only supports mainnet (testnet disabled)
|
||||
trader, err = NewLighterTraderV2(
|
||||
trader, err = lighter.NewLighterTraderV2(
|
||||
config.LighterWalletAddr,
|
||||
config.LighterAPIKeyPrivateKey,
|
||||
config.LighterAPIKeyIndex,
|
||||
@@ -363,7 +378,7 @@ func (at *AutoTrader) Run() error {
|
||||
|
||||
// Start Lighter order sync if using Lighter exchange
|
||||
if at.exchange == "lighter" {
|
||||
if lighterTrader, ok := at.trader.(*LighterTraderV2); ok && at.store != nil {
|
||||
if lighterTrader, ok := at.trader.(*lighter.LighterTraderV2); ok && at.store != nil {
|
||||
lighterTrader.StartOrderSync(at.id, at.exchangeID, at.exchange, at.store, 30*time.Second)
|
||||
logger.Infof("🔄 [%s] Lighter order+position sync enabled (every 30s)", at.name)
|
||||
}
|
||||
@@ -371,7 +386,7 @@ func (at *AutoTrader) Run() error {
|
||||
|
||||
// Start Hyperliquid order sync if using Hyperliquid exchange
|
||||
if at.exchange == "hyperliquid" {
|
||||
if hyperliquidTrader, ok := at.trader.(*HyperliquidTrader); ok && at.store != nil {
|
||||
if hyperliquidTrader, ok := at.trader.(*hyperliquid.HyperliquidTrader); ok && at.store != nil {
|
||||
hyperliquidTrader.StartOrderSync(at.id, at.exchangeID, at.exchange, at.store, 30*time.Second)
|
||||
logger.Infof("🔄 [%s] Hyperliquid order+position sync enabled (every 30s)", at.name)
|
||||
}
|
||||
@@ -379,7 +394,7 @@ func (at *AutoTrader) Run() error {
|
||||
|
||||
// Start Bybit order sync if using Bybit exchange
|
||||
if at.exchange == "bybit" {
|
||||
if bybitTrader, ok := at.trader.(*BybitTrader); ok && at.store != nil {
|
||||
if bybitTrader, ok := at.trader.(*bybit.BybitTrader); ok && at.store != nil {
|
||||
bybitTrader.StartOrderSync(at.id, at.exchangeID, at.exchange, at.store, 30*time.Second)
|
||||
logger.Infof("🔄 [%s] Bybit order+position sync enabled (every 30s)", at.name)
|
||||
}
|
||||
@@ -387,7 +402,7 @@ func (at *AutoTrader) Run() error {
|
||||
|
||||
// Start OKX order sync if using OKX exchange
|
||||
if at.exchange == "okx" {
|
||||
if okxTrader, ok := at.trader.(*OKXTrader); ok && at.store != nil {
|
||||
if okxTrader, ok := at.trader.(*okx.OKXTrader); ok && at.store != nil {
|
||||
okxTrader.StartOrderSync(at.id, at.exchangeID, at.exchange, at.store, 30*time.Second)
|
||||
logger.Infof("🔄 [%s] OKX order+position sync enabled (every 30s)", at.name)
|
||||
}
|
||||
@@ -395,7 +410,7 @@ func (at *AutoTrader) Run() error {
|
||||
|
||||
// Start Bitget order sync if using Bitget exchange
|
||||
if at.exchange == "bitget" {
|
||||
if bitgetTrader, ok := at.trader.(*BitgetTrader); ok && at.store != nil {
|
||||
if bitgetTrader, ok := at.trader.(*bitget.BitgetTrader); ok && at.store != nil {
|
||||
bitgetTrader.StartOrderSync(at.id, at.exchangeID, at.exchange, at.store, 30*time.Second)
|
||||
logger.Infof("🔄 [%s] Bitget order+position sync enabled (every 30s)", at.name)
|
||||
}
|
||||
@@ -403,7 +418,7 @@ func (at *AutoTrader) Run() error {
|
||||
|
||||
// Start Aster order sync if using Aster exchange
|
||||
if at.exchange == "aster" {
|
||||
if asterTrader, ok := at.trader.(*AsterTrader); ok && at.store != nil {
|
||||
if asterTrader, ok := at.trader.(*aster.AsterTrader); ok && at.store != nil {
|
||||
asterTrader.StartOrderSync(at.id, at.exchangeID, at.exchange, at.store, 30*time.Second)
|
||||
logger.Infof("🔄 [%s] Aster order+position sync enabled (every 30s)", at.name)
|
||||
}
|
||||
@@ -411,12 +426,20 @@ func (at *AutoTrader) Run() error {
|
||||
|
||||
// Start Binance order sync if using Binance exchange
|
||||
if at.exchange == "binance" {
|
||||
if binanceTrader, ok := at.trader.(*FuturesTrader); ok && at.store != nil {
|
||||
if binanceTrader, ok := at.trader.(*binance.FuturesTrader); ok && at.store != nil {
|
||||
binanceTrader.StartOrderSync(at.id, at.exchangeID, at.exchange, at.store, 30*time.Second)
|
||||
logger.Infof("🔄 [%s] Binance order+position sync enabled (every 30s)", at.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Start Gate order sync if using Gate exchange
|
||||
if at.exchange == "gate" {
|
||||
if gateTrader, ok := at.trader.(*gate.GateTrader); ok && at.store != nil {
|
||||
gateTrader.StartOrderSync(at.id, at.exchangeID, at.exchange, at.store, 30*time.Second)
|
||||
logger.Infof("🔄 [%s] Gate order+position sync enabled (every 30s)", at.name)
|
||||
}
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(at.config.ScanInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
@@ -1050,7 +1073,7 @@ func (at *AutoTrader) executeOpenLongWithRecord(decision *kernel.Decision, actio
|
||||
}
|
||||
|
||||
// Get current price
|
||||
marketData, err := market.Get(decision.Symbol)
|
||||
marketData, err := market.GetWithExchange(decision.Symbol, at.exchange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1167,7 +1190,7 @@ func (at *AutoTrader) executeOpenShortWithRecord(decision *kernel.Decision, acti
|
||||
}
|
||||
|
||||
// Get current price
|
||||
marketData, err := market.Get(decision.Symbol)
|
||||
marketData, err := market.GetWithExchange(decision.Symbol, at.exchange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1266,7 +1289,7 @@ func (at *AutoTrader) executeCloseLongWithRecord(decision *kernel.Decision, acti
|
||||
logger.Infof(" 🔄 Close long: %s", decision.Symbol)
|
||||
|
||||
// Get current price
|
||||
marketData, err := market.Get(decision.Symbol)
|
||||
marketData, err := market.GetWithExchange(decision.Symbol, at.exchange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1330,7 +1353,7 @@ func (at *AutoTrader) executeCloseShortWithRecord(decision *kernel.Decision, act
|
||||
logger.Infof(" 🔄 Close short: %s", decision.Symbol)
|
||||
|
||||
// Get current price
|
||||
marketData, err := market.Get(decision.Symbol)
|
||||
marketData, err := market.GetWithExchange(decision.Symbol, at.exchange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user