mirror of
https://github.com/laoxong/nofx.git
synced 2026-06-07 11:17:56 +08:00
cb31782be4
- Rename experience/ to telemetry/ for clarity - Split 15+ large Go files (800-2200 lines) into focused modules: kernel/engine.go, backtest/runner.go, market/data.go, store/position.go, api/handler_trader.go, trader/auto_trader_grid.go, and 9 exchange traders - Split frontend monoliths: types.ts, api.ts, AITradersPage.tsx, BacktestPage.tsx into domain-specific modules with barrel re-exports - Remove stale files: screenshots, .yml.old, pyproject.toml - Remove unused scripts/ and cmd/ directories - Remove broken/outdated test files (network-dependent, stale expectations)
122 lines
3.7 KiB
Go
122 lines
3.7 KiB
Go
package aster
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"nofx/logger"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// GetPositions Get position information
|
|
func (t *AsterTrader) GetPositions() ([]map[string]interface{}, error) {
|
|
params := make(map[string]interface{})
|
|
body, err := t.request("GET", "/fapi/v3/positionRisk", params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var positions []map[string]interface{}
|
|
if err := json.Unmarshal(body, &positions); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := []map[string]interface{}{}
|
|
for _, pos := range positions {
|
|
posAmtStr, ok := pos["positionAmt"].(string)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
posAmt, _ := strconv.ParseFloat(posAmtStr, 64)
|
|
if posAmt == 0 {
|
|
continue // Skip empty positions
|
|
}
|
|
|
|
entryPrice, _ := strconv.ParseFloat(pos["entryPrice"].(string), 64)
|
|
markPrice, _ := strconv.ParseFloat(pos["markPrice"].(string), 64)
|
|
unRealizedProfit, _ := strconv.ParseFloat(pos["unRealizedProfit"].(string), 64)
|
|
leverageVal, _ := strconv.ParseFloat(pos["leverage"].(string), 64)
|
|
liquidationPrice, _ := strconv.ParseFloat(pos["liquidationPrice"].(string), 64)
|
|
|
|
// Determine direction (consistent with Binance)
|
|
side := "long"
|
|
if posAmt < 0 {
|
|
side = "short"
|
|
posAmt = -posAmt
|
|
}
|
|
|
|
// Return same field names as Binance
|
|
result = append(result, map[string]interface{}{
|
|
"symbol": pos["symbol"],
|
|
"side": side,
|
|
"positionAmt": posAmt,
|
|
"entryPrice": entryPrice,
|
|
"markPrice": markPrice,
|
|
"unRealizedProfit": unRealizedProfit,
|
|
"leverage": leverageVal,
|
|
"liquidationPrice": liquidationPrice,
|
|
})
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// SetMarginMode Set margin mode
|
|
func (t *AsterTrader) SetMarginMode(symbol string, isCrossMargin bool) error {
|
|
// Aster supports margin mode settings
|
|
// API format similar to Binance: CROSSED (cross margin) / ISOLATED (isolated margin)
|
|
marginType := "CROSSED"
|
|
if !isCrossMargin {
|
|
marginType = "ISOLATED"
|
|
}
|
|
|
|
params := map[string]interface{}{
|
|
"symbol": symbol,
|
|
"marginType": marginType,
|
|
}
|
|
|
|
// Use request method to call API
|
|
_, err := t.request("POST", "/fapi/v3/marginType", params)
|
|
if err != nil {
|
|
// Ignore error if it indicates no need to change
|
|
if strings.Contains(err.Error(), "No need to change") ||
|
|
strings.Contains(err.Error(), "Margin type cannot be changed") {
|
|
logger.Infof(" ✓ %s margin mode is already %s or cannot be changed due to existing positions", symbol, marginType)
|
|
return nil
|
|
}
|
|
// Detect multi-assets mode (error code -4168)
|
|
if strings.Contains(err.Error(), "Multi-Assets mode") ||
|
|
strings.Contains(err.Error(), "-4168") ||
|
|
strings.Contains(err.Error(), "4168") {
|
|
logger.Infof(" ⚠️ %s detected multi-assets mode, forcing cross margin mode", symbol)
|
|
logger.Infof(" 💡 Tip: To use isolated margin mode, please disable multi-assets mode on the exchange")
|
|
return nil
|
|
}
|
|
// Detect unified account API
|
|
if strings.Contains(err.Error(), "unified") ||
|
|
strings.Contains(err.Error(), "portfolio") ||
|
|
strings.Contains(err.Error(), "Portfolio") {
|
|
logger.Infof(" ❌ %s detected unified account API, cannot perform futures trading", symbol)
|
|
return fmt.Errorf("please use 'Spot & Futures Trading' API permission, not 'Unified Account API'")
|
|
}
|
|
logger.Infof(" ⚠️ Failed to set margin mode: %v", err)
|
|
// Don't return error, let trading continue
|
|
return nil
|
|
}
|
|
|
|
logger.Infof(" ✓ %s margin mode has been set to %s", symbol, marginType)
|
|
return nil
|
|
}
|
|
|
|
// SetLeverage Set leverage multiplier
|
|
func (t *AsterTrader) SetLeverage(symbol string, leverage int) error {
|
|
params := map[string]interface{}{
|
|
"symbol": symbol,
|
|
"leverage": leverage,
|
|
}
|
|
|
|
_, err := t.request("POST", "/fapi/v3/leverage", params)
|
|
return err
|
|
}
|