mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-17 01:14:40 +08:00
feat: implement GetOpenOrders for Aster, OKX, Bitget exchanges
- Aster: uses /fapi/v3/openOrders endpoint - OKX: uses /api/v5/trade/orders-pending and orders-algo-pending - Bitget: uses /api/v2/mix/order/orders-pending and orders-plan-pending
This commit is contained in:
@@ -1417,8 +1417,52 @@ func (t *AsterTrader) GetTrades(startTime time.Time, limit int) ([]TradeRecord,
|
|||||||
|
|
||||||
// GetOpenOrders gets all open/pending orders for a symbol
|
// GetOpenOrders gets all open/pending orders for a symbol
|
||||||
func (t *AsterTrader) GetOpenOrders(symbol string) ([]OpenOrder, error) {
|
func (t *AsterTrader) GetOpenOrders(symbol string) ([]OpenOrder, error) {
|
||||||
// TODO: Implement Aster open orders
|
params := map[string]interface{}{
|
||||||
return []OpenOrder{}, nil
|
"symbol": symbol,
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := t.request("GET", "/fapi/v3/openOrders", params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get open orders: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var orders []struct {
|
||||||
|
OrderID int64 `json:"orderId"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Side string `json:"side"`
|
||||||
|
PositionSide string `json:"positionSide"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Price string `json:"price"`
|
||||||
|
StopPrice string `json:"stopPrice"`
|
||||||
|
OrigQty string `json:"origQty"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(body, &orders); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse open orders: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []OpenOrder
|
||||||
|
for _, order := range orders {
|
||||||
|
price, _ := strconv.ParseFloat(order.Price, 64)
|
||||||
|
stopPrice, _ := strconv.ParseFloat(order.StopPrice, 64)
|
||||||
|
quantity, _ := strconv.ParseFloat(order.OrigQty, 64)
|
||||||
|
|
||||||
|
result = append(result, OpenOrder{
|
||||||
|
OrderID: fmt.Sprintf("%d", order.OrderID),
|
||||||
|
Symbol: order.Symbol,
|
||||||
|
Side: order.Side,
|
||||||
|
PositionSide: order.PositionSide,
|
||||||
|
Type: order.Type,
|
||||||
|
Price: price,
|
||||||
|
StopPrice: stopPrice,
|
||||||
|
Quantity: quantity,
|
||||||
|
Status: order.Status,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("✓ ASTER GetOpenOrders: found %d open orders for %s", len(result), symbol)
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlaceLimitOrder places a limit order for grid trading
|
// PlaceLimitOrder places a limit order for grid trading
|
||||||
|
|||||||
@@ -1099,8 +1099,105 @@ func genBitgetClientOid() string {
|
|||||||
|
|
||||||
// GetOpenOrders gets all open/pending orders for a symbol
|
// GetOpenOrders gets all open/pending orders for a symbol
|
||||||
func (t *BitgetTrader) GetOpenOrders(symbol string) ([]OpenOrder, error) {
|
func (t *BitgetTrader) GetOpenOrders(symbol string) ([]OpenOrder, error) {
|
||||||
// TODO: Implement Bitget open orders
|
symbol = t.convertSymbol(symbol)
|
||||||
return []OpenOrder{}, nil
|
var result []OpenOrder
|
||||||
|
|
||||||
|
// 1. Get pending limit orders
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"symbol": symbol,
|
||||||
|
"productType": "USDT-FUTURES",
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := t.doRequest("GET", bitgetPendingPath, params)
|
||||||
|
if err == nil {
|
||||||
|
var orders struct {
|
||||||
|
EntrustedList []struct {
|
||||||
|
OrderId string `json:"orderId"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Side string `json:"side"` // buy/sell
|
||||||
|
TradeSide string `json:"tradeSide"` // open/close
|
||||||
|
PosSide string `json:"posSide"` // long/short
|
||||||
|
OrderType string `json:"orderType"` // limit/market
|
||||||
|
Price string `json:"price"`
|
||||||
|
Size string `json:"size"`
|
||||||
|
State string `json:"state"`
|
||||||
|
} `json:"entrustedList"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &orders); err == nil {
|
||||||
|
for _, order := range orders.EntrustedList {
|
||||||
|
price, _ := strconv.ParseFloat(order.Price, 64)
|
||||||
|
quantity, _ := strconv.ParseFloat(order.Size, 64)
|
||||||
|
|
||||||
|
// Convert side to standard format
|
||||||
|
side := strings.ToUpper(order.Side)
|
||||||
|
positionSide := strings.ToUpper(order.PosSide)
|
||||||
|
|
||||||
|
result = append(result, OpenOrder{
|
||||||
|
OrderID: order.OrderId,
|
||||||
|
Symbol: symbol,
|
||||||
|
Side: side,
|
||||||
|
PositionSide: positionSide,
|
||||||
|
Type: strings.ToUpper(order.OrderType),
|
||||||
|
Price: price,
|
||||||
|
StopPrice: 0,
|
||||||
|
Quantity: quantity,
|
||||||
|
Status: "NEW",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Get pending plan orders (stop-loss/take-profit)
|
||||||
|
planParams := map[string]interface{}{
|
||||||
|
"symbol": symbol,
|
||||||
|
"productType": "USDT-FUTURES",
|
||||||
|
}
|
||||||
|
|
||||||
|
planData, err := t.doRequest("GET", "/api/v2/mix/order/orders-plan-pending", planParams)
|
||||||
|
if err == nil {
|
||||||
|
var planOrders struct {
|
||||||
|
EntrustedList []struct {
|
||||||
|
OrderId string `json:"orderId"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Side string `json:"side"`
|
||||||
|
PosSide string `json:"posSide"`
|
||||||
|
PlanType string `json:"planType"` // normal_plan/profit_plan/loss_plan
|
||||||
|
TriggerPrice string `json:"triggerPrice"`
|
||||||
|
Size string `json:"size"`
|
||||||
|
State string `json:"state"`
|
||||||
|
} `json:"entrustedList"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(planData, &planOrders); err == nil {
|
||||||
|
for _, order := range planOrders.EntrustedList {
|
||||||
|
triggerPrice, _ := strconv.ParseFloat(order.TriggerPrice, 64)
|
||||||
|
quantity, _ := strconv.ParseFloat(order.Size, 64)
|
||||||
|
|
||||||
|
side := strings.ToUpper(order.Side)
|
||||||
|
positionSide := strings.ToUpper(order.PosSide)
|
||||||
|
|
||||||
|
// Map Bitget plan type to order type
|
||||||
|
orderType := "STOP_MARKET"
|
||||||
|
if order.PlanType == "profit_plan" {
|
||||||
|
orderType = "TAKE_PROFIT_MARKET"
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, OpenOrder{
|
||||||
|
OrderID: order.OrderId,
|
||||||
|
Symbol: symbol,
|
||||||
|
Side: side,
|
||||||
|
PositionSide: positionSide,
|
||||||
|
Type: orderType,
|
||||||
|
Price: 0,
|
||||||
|
StopPrice: triggerPrice,
|
||||||
|
Quantity: quantity,
|
||||||
|
Status: "NEW",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("✓ BITGET GetOpenOrders: found %d open orders for %s", len(result), symbol)
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlaceLimitOrder places a limit order for grid trading
|
// PlaceLimitOrder places a limit order for grid trading
|
||||||
|
|||||||
@@ -1390,8 +1390,98 @@ func (t *OKXTrader) GetClosedPnL(startTime time.Time, limit int) ([]ClosedPnLRec
|
|||||||
|
|
||||||
// GetOpenOrders gets all open/pending orders for a symbol
|
// GetOpenOrders gets all open/pending orders for a symbol
|
||||||
func (t *OKXTrader) GetOpenOrders(symbol string) ([]OpenOrder, error) {
|
func (t *OKXTrader) GetOpenOrders(symbol string) ([]OpenOrder, error) {
|
||||||
// TODO: Implement OKX open orders
|
instId := t.convertSymbol(symbol)
|
||||||
return []OpenOrder{}, nil
|
var result []OpenOrder
|
||||||
|
|
||||||
|
// 1. Get pending limit orders
|
||||||
|
path := fmt.Sprintf("%s?instId=%s&instType=SWAP", okxPendingOrdersPath, instId)
|
||||||
|
data, err := t.doRequest("GET", path, nil)
|
||||||
|
if err == nil {
|
||||||
|
var orders []struct {
|
||||||
|
OrdId string `json:"ordId"`
|
||||||
|
InstId string `json:"instId"`
|
||||||
|
Side string `json:"side"` // buy/sell
|
||||||
|
PosSide string `json:"posSide"` // long/short/net
|
||||||
|
OrdType string `json:"ordType"` // limit/market/post_only
|
||||||
|
Px string `json:"px"` // price
|
||||||
|
Sz string `json:"sz"` // size
|
||||||
|
State string `json:"state"` // live/partially_filled
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &orders); err == nil {
|
||||||
|
for _, order := range orders {
|
||||||
|
price, _ := strconv.ParseFloat(order.Px, 64)
|
||||||
|
quantity, _ := strconv.ParseFloat(order.Sz, 64)
|
||||||
|
|
||||||
|
// Convert OKX side to standard format
|
||||||
|
side := strings.ToUpper(order.Side)
|
||||||
|
positionSide := strings.ToUpper(order.PosSide)
|
||||||
|
if positionSide == "NET" {
|
||||||
|
positionSide = "BOTH"
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, OpenOrder{
|
||||||
|
OrderID: order.OrdId,
|
||||||
|
Symbol: symbol,
|
||||||
|
Side: side,
|
||||||
|
PositionSide: positionSide,
|
||||||
|
Type: strings.ToUpper(order.OrdType),
|
||||||
|
Price: price,
|
||||||
|
StopPrice: 0,
|
||||||
|
Quantity: quantity,
|
||||||
|
Status: "NEW",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Get pending algo orders (stop-loss/take-profit)
|
||||||
|
algoPath := fmt.Sprintf("%s?instId=%s&instType=SWAP", okxAlgoPendingPath, instId)
|
||||||
|
algoData, err := t.doRequest("GET", algoPath, nil)
|
||||||
|
if err == nil {
|
||||||
|
var algoOrders []struct {
|
||||||
|
AlgoId string `json:"algoId"`
|
||||||
|
InstId string `json:"instId"`
|
||||||
|
Side string `json:"side"`
|
||||||
|
PosSide string `json:"posSide"`
|
||||||
|
OrdType string `json:"ordType"` // conditional/oco/trigger
|
||||||
|
TriggerPx string `json:"triggerPx"`
|
||||||
|
Sz string `json:"sz"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(algoData, &algoOrders); err == nil {
|
||||||
|
for _, order := range algoOrders {
|
||||||
|
triggerPrice, _ := strconv.ParseFloat(order.TriggerPx, 64)
|
||||||
|
quantity, _ := strconv.ParseFloat(order.Sz, 64)
|
||||||
|
|
||||||
|
side := strings.ToUpper(order.Side)
|
||||||
|
positionSide := strings.ToUpper(order.PosSide)
|
||||||
|
if positionSide == "NET" {
|
||||||
|
positionSide = "BOTH"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map OKX algo order type
|
||||||
|
orderType := "STOP_MARKET"
|
||||||
|
if order.OrdType == "oco" {
|
||||||
|
orderType = "TAKE_PROFIT_MARKET"
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, OpenOrder{
|
||||||
|
OrderID: order.AlgoId,
|
||||||
|
Symbol: symbol,
|
||||||
|
Side: side,
|
||||||
|
PositionSide: positionSide,
|
||||||
|
Type: orderType,
|
||||||
|
Price: 0,
|
||||||
|
StopPrice: triggerPrice,
|
||||||
|
Quantity: quantity,
|
||||||
|
Status: "NEW",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("✓ OKX GetOpenOrders: found %d open orders for %s", len(result), symbol)
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlaceLimitOrder places a limit order for grid trading
|
// PlaceLimitOrder places a limit order for grid trading
|
||||||
|
|||||||
Reference in New Issue
Block a user