mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-18 01:44:38 +08:00
refactor: standardize code comments
This commit is contained in:
@@ -12,92 +12,92 @@ import (
|
||||
"github.com/elliottech/lighter-go/types"
|
||||
)
|
||||
|
||||
// SetStopLoss 設置止損單(實現 Trader 接口)
|
||||
// SetStopLoss Set stop-loss order (implements Trader interface)
|
||||
func (t *LighterTraderV2) SetStopLoss(symbol string, positionSide string, quantity, stopPrice float64) error {
|
||||
if t.txClient == nil {
|
||||
return fmt.Errorf("TxClient 未初始化")
|
||||
return fmt.Errorf("TxClient not initialized")
|
||||
}
|
||||
|
||||
logger.Infof("🛑 LIGHTER 設置止損: %s %s qty=%.4f, stop=%.2f", symbol, positionSide, quantity, stopPrice)
|
||||
logger.Infof("🛑 LIGHTER Setting stop-loss: %s %s qty=%.4f, stop=%.2f", symbol, positionSide, quantity, stopPrice)
|
||||
|
||||
// 確定訂單方向(做空止損用買單,做多止損用賣單)
|
||||
// Determine order direction (short position uses buy order, long position uses sell order)
|
||||
isAsk := (positionSide == "LONG" || positionSide == "long")
|
||||
|
||||
// 創建限價止損單
|
||||
// Create limit stop-loss order
|
||||
_, err := t.CreateOrder(symbol, isAsk, quantity, stopPrice, "limit")
|
||||
if err != nil {
|
||||
return fmt.Errorf("設置止損失敗: %w", err)
|
||||
return fmt.Errorf("failed to set stop-loss: %w", err)
|
||||
}
|
||||
|
||||
logger.Infof("✓ LIGHTER 止損已設置: %.2f", stopPrice)
|
||||
logger.Infof("✓ LIGHTER stop-loss set: %.2f", stopPrice)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTakeProfit 設置止盈單(實現 Trader 接口)
|
||||
// SetTakeProfit Set take-profit order (implements Trader interface)
|
||||
func (t *LighterTraderV2) SetTakeProfit(symbol string, positionSide string, quantity, takeProfitPrice float64) error {
|
||||
if t.txClient == nil {
|
||||
return fmt.Errorf("TxClient 未初始化")
|
||||
return fmt.Errorf("TxClient not initialized")
|
||||
}
|
||||
|
||||
logger.Infof("🎯 LIGHTER 設置止盈: %s %s qty=%.4f, tp=%.2f", symbol, positionSide, quantity, takeProfitPrice)
|
||||
logger.Infof("🎯 LIGHTER Setting take-profit: %s %s qty=%.4f, tp=%.2f", symbol, positionSide, quantity, takeProfitPrice)
|
||||
|
||||
// 確定訂單方向(做空止盈用買單,做多止盈用賣單)
|
||||
// Determine order direction (short position uses buy order, long position uses sell order)
|
||||
isAsk := (positionSide == "LONG" || positionSide == "long")
|
||||
|
||||
// 創建限價止盈單
|
||||
// Create limit take-profit order
|
||||
_, err := t.CreateOrder(symbol, isAsk, quantity, takeProfitPrice, "limit")
|
||||
if err != nil {
|
||||
return fmt.Errorf("設置止盈失敗: %w", err)
|
||||
return fmt.Errorf("failed to set take-profit: %w", err)
|
||||
}
|
||||
|
||||
logger.Infof("✓ LIGHTER 止盈已設置: %.2f", takeProfitPrice)
|
||||
logger.Infof("✓ LIGHTER take-profit set: %.2f", takeProfitPrice)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CancelAllOrders 取消所有訂單(實現 Trader 接口)
|
||||
// CancelAllOrders Cancel all orders (implements Trader interface)
|
||||
func (t *LighterTraderV2) CancelAllOrders(symbol string) error {
|
||||
if t.txClient == nil {
|
||||
return fmt.Errorf("TxClient 未初始化")
|
||||
return fmt.Errorf("TxClient not initialized")
|
||||
}
|
||||
|
||||
if err := t.ensureAuthToken(); err != nil {
|
||||
return fmt.Errorf("認證令牌無效: %w", err)
|
||||
return fmt.Errorf("invalid auth token: %w", err)
|
||||
}
|
||||
|
||||
// 獲取所有活躍訂單
|
||||
// Get all active orders
|
||||
orders, err := t.GetActiveOrders(symbol)
|
||||
if err != nil {
|
||||
return fmt.Errorf("獲取活躍訂單失敗: %w", err)
|
||||
return fmt.Errorf("failed to get active orders: %w", err)
|
||||
}
|
||||
|
||||
if len(orders) == 0 {
|
||||
logger.Infof("✓ LIGHTER - 無需取消訂單(無活躍訂單)")
|
||||
logger.Infof("✓ LIGHTER - No orders to cancel (no active orders)")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 批量取消
|
||||
// Batch cancel
|
||||
canceledCount := 0
|
||||
for _, order := range orders {
|
||||
if err := t.CancelOrder(symbol, order.OrderID); err != nil {
|
||||
logger.Infof("⚠️ 取消訂單失敗 (ID: %s): %v", order.OrderID, err)
|
||||
logger.Infof("⚠️ Failed to cancel order (ID: %s): %v", order.OrderID, err)
|
||||
} else {
|
||||
canceledCount++
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof("✓ LIGHTER - 已取消 %d 個訂單", canceledCount)
|
||||
logger.Infof("✓ LIGHTER - Canceled %d orders", canceledCount)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOrderStatus 獲取訂單狀態(實現 Trader 接口)
|
||||
// GetOrderStatus Get order status (implements Trader interface)
|
||||
func (t *LighterTraderV2) GetOrderStatus(symbol string, orderID string) (map[string]interface{}, error) {
|
||||
// LIGHTER 使用市價單通常立即成交
|
||||
// 嘗試查詢訂單狀態
|
||||
// LIGHTER market orders are usually filled immediately
|
||||
// Try to query order status
|
||||
if err := t.ensureAuthToken(); err != nil {
|
||||
return nil, fmt.Errorf("認證令牌無效: %w", err)
|
||||
return nil, fmt.Errorf("invalid auth token: %w", err)
|
||||
}
|
||||
|
||||
// 構建請求 URL
|
||||
// Build request URL
|
||||
endpoint := fmt.Sprintf("%s/api/v1/order/%s", t.baseURL, orderID)
|
||||
|
||||
req, err := http.NewRequest("GET", endpoint, nil)
|
||||
@@ -110,7 +110,7 @@ func (t *LighterTraderV2) GetOrderStatus(symbol string, orderID string) (map[str
|
||||
|
||||
resp, err := t.client.Do(req)
|
||||
if err != nil {
|
||||
// 如果查詢失敗,假設訂單已完成
|
||||
// If query fails, assume order is filled
|
||||
return map[string]interface{}{
|
||||
"orderId": orderID,
|
||||
"status": "FILLED",
|
||||
@@ -143,7 +143,7 @@ func (t *LighterTraderV2) GetOrderStatus(symbol string, orderID string) (map[str
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 轉換狀態為統一格式
|
||||
// Convert status to unified format
|
||||
unifiedStatus := order.Status
|
||||
switch order.Status {
|
||||
case "filled":
|
||||
@@ -163,89 +163,89 @@ func (t *LighterTraderV2) GetOrderStatus(symbol string, orderID string) (map[str
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CancelStopLossOrders 僅取消止損單(實現 Trader 接口)
|
||||
// CancelStopLossOrders Cancel only stop-loss orders (implements Trader interface)
|
||||
func (t *LighterTraderV2) CancelStopLossOrders(symbol string) error {
|
||||
// LIGHTER 暫時無法區分止損和止盈單,取消所有止盈止損單
|
||||
logger.Infof("⚠️ LIGHTER 無法區分止損/止盈單,將取消所有止盈止損單")
|
||||
// LIGHTER cannot distinguish between stop-loss and take-profit orders yet, will cancel all stop orders
|
||||
logger.Infof("⚠️ LIGHTER cannot distinguish stop-loss/take-profit orders, will cancel all stop orders")
|
||||
return t.CancelStopOrders(symbol)
|
||||
}
|
||||
|
||||
// CancelTakeProfitOrders 僅取消止盈單(實現 Trader 接口)
|
||||
// CancelTakeProfitOrders Cancel only take-profit orders (implements Trader interface)
|
||||
func (t *LighterTraderV2) CancelTakeProfitOrders(symbol string) error {
|
||||
// LIGHTER 暫時無法區分止損和止盈單,取消所有止盈止損單
|
||||
logger.Infof("⚠️ LIGHTER 無法區分止損/止盈單,將取消所有止盈止損單")
|
||||
// LIGHTER cannot distinguish between stop-loss and take-profit orders yet, will cancel all stop orders
|
||||
logger.Infof("⚠️ LIGHTER cannot distinguish stop-loss/take-profit orders, will cancel all stop orders")
|
||||
return t.CancelStopOrders(symbol)
|
||||
}
|
||||
|
||||
// CancelStopOrders 取消該幣種的止盈/止損單(實現 Trader 接口)
|
||||
// CancelStopOrders Cancel stop-loss/take-profit orders for this symbol (implements Trader interface)
|
||||
func (t *LighterTraderV2) CancelStopOrders(symbol string) error {
|
||||
if t.txClient == nil {
|
||||
return fmt.Errorf("TxClient 未初始化")
|
||||
return fmt.Errorf("TxClient not initialized")
|
||||
}
|
||||
|
||||
if err := t.ensureAuthToken(); err != nil {
|
||||
return fmt.Errorf("認證令牌無效: %w", err)
|
||||
return fmt.Errorf("invalid auth token: %w", err)
|
||||
}
|
||||
|
||||
// 獲取活躍訂單
|
||||
// Get active orders
|
||||
orders, err := t.GetActiveOrders(symbol)
|
||||
if err != nil {
|
||||
return fmt.Errorf("獲取活躍訂單失敗: %w", err)
|
||||
return fmt.Errorf("failed to get active orders: %w", err)
|
||||
}
|
||||
|
||||
canceledCount := 0
|
||||
for _, order := range orders {
|
||||
// TODO: 檢查訂單類型,只取消止盈止損單
|
||||
// 暫時取消所有訂單
|
||||
// TODO: Check order type, only cancel stop orders
|
||||
// For now, cancel all orders
|
||||
if err := t.CancelOrder(symbol, order.OrderID); err != nil {
|
||||
logger.Infof("⚠️ 取消訂單失敗 (ID: %s): %v", order.OrderID, err)
|
||||
logger.Infof("⚠️ Failed to cancel order (ID: %s): %v", order.OrderID, err)
|
||||
} else {
|
||||
canceledCount++
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof("✓ LIGHTER - 已取消 %d 個止盈止損單", canceledCount)
|
||||
logger.Infof("✓ LIGHTER - Canceled %d stop orders", canceledCount)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetActiveOrders 獲取活躍訂單
|
||||
// GetActiveOrders Get active orders
|
||||
func (t *LighterTraderV2) GetActiveOrders(symbol string) ([]OrderResponse, error) {
|
||||
if err := t.ensureAuthToken(); err != nil {
|
||||
return nil, fmt.Errorf("認證令牌無效: %w", err)
|
||||
return nil, fmt.Errorf("invalid auth token: %w", err)
|
||||
}
|
||||
|
||||
// 獲取市場索引
|
||||
// Get market index
|
||||
marketIndex, err := t.getMarketIndex(symbol)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("獲取市場索引失敗: %w", err)
|
||||
return nil, fmt.Errorf("failed to get market index: %w", err)
|
||||
}
|
||||
|
||||
// 構建請求 URL
|
||||
// Build request URL
|
||||
endpoint := fmt.Sprintf("%s/api/v1/accountActiveOrders?account_index=%d&market_id=%d",
|
||||
t.baseURL, t.accountIndex, marketIndex)
|
||||
|
||||
// 發送 GET 請求
|
||||
// Send GET request
|
||||
req, err := http.NewRequest("GET", endpoint, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("創建請求失敗: %w", err)
|
||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
// 添加認證頭
|
||||
// Add authentication header
|
||||
req.Header.Set("Authorization", t.authToken)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := t.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("請求失敗: %w", err)
|
||||
return nil, fmt.Errorf("request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("讀取響應失敗: %w", err)
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
// 解析響應
|
||||
// Parse response
|
||||
var apiResp struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
@@ -253,83 +253,83 @@ func (t *LighterTraderV2) GetActiveOrders(symbol string) ([]OrderResponse, error
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||
return nil, fmt.Errorf("解析響應失敗: %w, body: %s", err, string(body))
|
||||
return nil, fmt.Errorf("failed to parse response: %w, body: %s", err, string(body))
|
||||
}
|
||||
|
||||
if apiResp.Code != 200 {
|
||||
return nil, fmt.Errorf("獲取活躍訂單失敗 (code %d): %s", apiResp.Code, apiResp.Message)
|
||||
return nil, fmt.Errorf("failed to get active orders (code %d): %s", apiResp.Code, apiResp.Message)
|
||||
}
|
||||
|
||||
logger.Infof("✓ LIGHTER - 獲取到 %d 個活躍訂單", len(apiResp.Data))
|
||||
logger.Infof("✓ LIGHTER - Retrieved %d active orders", len(apiResp.Data))
|
||||
return apiResp.Data, nil
|
||||
}
|
||||
|
||||
// CancelOrder 取消單個訂單
|
||||
// CancelOrder Cancel a single order
|
||||
func (t *LighterTraderV2) CancelOrder(symbol, orderID string) error {
|
||||
if t.txClient == nil {
|
||||
return fmt.Errorf("TxClient 未初始化")
|
||||
return fmt.Errorf("TxClient not initialized")
|
||||
}
|
||||
|
||||
// 獲取市場索引
|
||||
// Get market index
|
||||
marketIndex, err := t.getMarketIndex(symbol)
|
||||
if err != nil {
|
||||
return fmt.Errorf("獲取市場索引失敗: %w", err)
|
||||
return fmt.Errorf("failed to get market index: %w", err)
|
||||
}
|
||||
|
||||
// 將 orderID 轉換為 int64
|
||||
// Convert orderID to int64
|
||||
orderIndex, err := strconv.ParseInt(orderID, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("無效的訂單ID: %w", err)
|
||||
return fmt.Errorf("invalid order ID: %w", err)
|
||||
}
|
||||
|
||||
// 構建取消訂單請求
|
||||
// Build cancel order request
|
||||
txReq := &types.CancelOrderTxReq{
|
||||
MarketIndex: marketIndex,
|
||||
Index: orderIndex,
|
||||
}
|
||||
|
||||
// 使用 SDK 簽名交易
|
||||
nonce := int64(-1) // -1 表示自動獲取
|
||||
// Sign transaction using SDK
|
||||
nonce := int64(-1) // -1 means auto-fetch
|
||||
tx, err := t.txClient.GetCancelOrderTransaction(txReq, &types.TransactOpts{
|
||||
Nonce: &nonce,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("簽名取消訂單失敗: %w", err)
|
||||
return fmt.Errorf("failed to sign cancel order: %w", err)
|
||||
}
|
||||
|
||||
// 序列化交易
|
||||
// Serialize transaction
|
||||
txBytes, err := json.Marshal(tx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("序列化交易失敗: %w", err)
|
||||
return fmt.Errorf("failed to serialize transaction: %w", err)
|
||||
}
|
||||
|
||||
// 提交取消訂單到 LIGHTER API
|
||||
// Submit cancel order to LIGHTER API
|
||||
_, err = t.submitCancelOrder(txBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("提交取消訂單失敗: %w", err)
|
||||
return fmt.Errorf("failed to submit cancel order: %w", err)
|
||||
}
|
||||
|
||||
logger.Infof("✓ LIGHTER訂單已取消 - ID: %s", orderID)
|
||||
logger.Infof("✓ LIGHTER order canceled - ID: %s", orderID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// submitCancelOrder 提交已簽名的取消訂單到 LIGHTER API
|
||||
// submitCancelOrder Submit signed cancel order to LIGHTER API
|
||||
func (t *LighterTraderV2) submitCancelOrder(signedTx []byte) (map[string]interface{}, error) {
|
||||
const TX_TYPE_CANCEL_ORDER = 15
|
||||
|
||||
// 構建請求
|
||||
// Build request
|
||||
req := SendTxRequest{
|
||||
TxType: TX_TYPE_CANCEL_ORDER,
|
||||
TxInfo: string(signedTx),
|
||||
PriceProtection: false, // 取消訂單不需要價格保護
|
||||
PriceProtection: false, // Cancel order doesn't need price protection
|
||||
}
|
||||
|
||||
reqBody, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("序列化請求失敗: %w", err)
|
||||
return nil, fmt.Errorf("failed to serialize request: %w", err)
|
||||
}
|
||||
|
||||
// 發送 POST 請求到 /api/v1/sendTx
|
||||
// Send POST request to /api/v1/sendTx
|
||||
endpoint := fmt.Sprintf("%s/api/v1/sendTx", t.baseURL)
|
||||
httpReq, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(reqBody))
|
||||
if err != nil {
|
||||
@@ -349,15 +349,15 @@ func (t *LighterTraderV2) submitCancelOrder(signedTx []byte) (map[string]interfa
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 解析響應
|
||||
// Parse response
|
||||
var sendResp SendTxResponse
|
||||
if err := json.Unmarshal(body, &sendResp); err != nil {
|
||||
return nil, fmt.Errorf("解析響應失敗: %w, body: %s", err, string(body))
|
||||
return nil, fmt.Errorf("failed to parse response: %w, body: %s", err, string(body))
|
||||
}
|
||||
|
||||
// 檢查響應碼
|
||||
// Check response code
|
||||
if sendResp.Code != 200 {
|
||||
return nil, fmt.Errorf("提交取消訂單失敗 (code %d): %s", sendResp.Code, sendResp.Message)
|
||||
return nil, fmt.Errorf("failed to submit cancel order (code %d): %s", sendResp.Code, sendResp.Message)
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
@@ -365,6 +365,6 @@ func (t *LighterTraderV2) submitCancelOrder(signedTx []byte) (map[string]interfa
|
||||
"status": "cancelled",
|
||||
}
|
||||
|
||||
logger.Infof("✓ 取消訂單已提交到 LIGHTER - tx_hash: %v", sendResp.Data["tx_hash"])
|
||||
logger.Infof("✓ Cancel order submitted to LIGHTER - tx_hash: %v", sendResp.Data["tx_hash"])
|
||||
return result, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user