mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-17 09:24:36 +08:00
refactor: split large files and clean up project structure
- 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)
This commit is contained in:
121
trader/aster/trader_positions.go
Normal file
121
trader/aster/trader_positions.go
Normal file
@@ -0,0 +1,121 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user