From b9ca145bbc7b91bbdc75bbddcc408b85e1706a68 Mon Sep 17 00:00:00 2001 From: yanweidong Date: Mon, 11 May 2026 16:24:13 +0800 Subject: [PATCH] feat. --- etc/coin_prod.yaml | 8 ++++++++ internal/logic/close.go | 7 ++++--- internal/logic/open.go | 25 +++++++++++++------------ internal/logic/run.go | 2 +- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/etc/coin_prod.yaml b/etc/coin_prod.yaml index 5b96aa5..4237faa 100644 --- a/etc/coin_prod.yaml +++ b/etc/coin_prod.yaml @@ -19,6 +19,14 @@ BinanceApiSecret: "YqTpRybnBWllS0fA1yk0T1MEx0RxRazc2bH2iZuPEI8QJKesUueq3saCDdDj7 SpotWatchList: - Symbol: BTCUSDT OrderQtyUsdt: 10 + - Symbol: ETHUSDT + OrderQtyUsdt: 10 + - Symbol: SOLUSDT + OrderQtyUsdt: 10 + - Symbol: ADAUSDT + OrderQtyUsdt: 10 + - Symbol: XRPUSDT + OrderQtyUsdt: 10 # 日志配置 Log: diff --git a/internal/logic/close.go b/internal/logic/close.go index 3a1326f..d3bb015 100644 --- a/internal/logic/close.go +++ b/internal/logic/close.go @@ -7,6 +7,7 @@ import ( "git.apinb.com/quant/coin/internal/impl" "git.apinb.com/quant/coin/internal/models" "github.com/adshao/go-binance/v2" + "github.com/shopspring/decimal" ) var ( @@ -15,7 +16,7 @@ var ( // trySpotRallySell 跟踪止盈:浮盈≥profitArmPct 后记录阶段峰值 PnL;继续上涨则刷新峰值; // 当未实现盈亏较峰值回落≥gridStartPct 时市价卖出(数量来自 RefreshAccount 写入的 account[sym])。 -func trySpotRallySell(pos *models.SpotPosition, pnlPct float64) error { +func trySpotRallySell(pos *models.SpotPosition, pnlPct float64, price float64) error { if val, ok := CloseCache[pos.Symbol]; !ok || val == 0 { CloseCache[pos.Symbol] = pnlPct return nil @@ -45,9 +46,9 @@ func trySpotRallySell(pos *models.SpotPosition, pnlPct float64) error { if err != nil { return err } - orderPrice, err := strconv.ParseFloat(order.Price, 64) + pos.SellQuantity += parseFloat(order.ExecutedQuantity) - pos.SellPrice = (pos.SellQuantity*pos.SellPrice + parseFloat(order.ExecutedQuantity)*orderPrice) / pos.SellQuantity + pos.SellPrice = decimal.NewFromFloat(price).Round(2).InexactFloat64() pos.Status = 1 impl.DBService.Save(pos) diff --git a/internal/logic/open.go b/internal/logic/open.go index befc3d0..5e129b9 100644 --- a/internal/logic/open.go +++ b/internal/logic/open.go @@ -10,6 +10,7 @@ import ( "git.apinb.com/quant/coin/internal/impl" "git.apinb.com/quant/coin/internal/models" binance "github.com/adshao/go-binance/v2" + "github.com/shopspring/decimal" ) var ( @@ -31,7 +32,7 @@ func CreateNewSpotPosition(symbol string) error { } } - qty, err := CalculateQty(symbol) + qty, price, err := CalculateQty(symbol) if err != nil { return err } @@ -50,7 +51,7 @@ func CreateNewSpotPosition(symbol string) error { position := &models.SpotPosition{ Symbol: symbol, BuyQuantity: parseFloat(order.ExecutedQuantity), - BuyCostPrice: parseFloat(order.Price), + BuyCostPrice: decimal.NewFromFloat(price).Round(2).InexactFloat64(), } if err := impl.DBService.Create(position).Error; err != nil { @@ -95,9 +96,9 @@ func AddSpotPosition(pos *models.SpotPosition, pnlPct, price float64) error { } // 更新数据库 - orderPrice, err := strconv.ParseFloat(order.Price, 64) + price = decimal.NewFromFloat(price).Round(2).InexactFloat64() pos.BuyQuantity += parseFloat(order.ExecutedQuantity) - pos.BuyCostPrice = (pos.BuyQuantity*pos.BuyCostPrice + parseFloat(order.ExecutedQuantity)*orderPrice) / pos.BuyQuantity + pos.BuyCostPrice = decimal.NewFromFloat((pos.BuyCostPrice + price) / 2).Round(2).InexactFloat64() pos.DipAddsDone++ impl.DBService.Save(pos) @@ -109,34 +110,34 @@ func AddSpotPosition(pos *models.SpotPosition, pnlPct, price float64) error { return nil } -func CalculateQty(symbol string) (string, error) { +func CalculateQty(symbol string) (string, float64, error) { ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second) defer cancel() prices, err := BinanceClient.NewListPricesService().Symbol(symbol).Do(ctx) if err != nil || len(prices) == 0 { - return "", err + return "", 0, err } price, err := strconv.ParseFloat(prices[0].Price, 64) if err != nil || price <= 0 { - return "", errors.New("现价无效") + return "", 0, errors.New("现价无效") } cfg := getSymbolInfo(symbol) if cfg == nil { - return "", errors.New("交易对不存在") + return "", 0, errors.New("交易对不存在") } want := InvestUsdt[cfg.Symbol] / price lot := cfg.LotSizeFilter() if lot == nil { - return "", errors.New("交易对无 LOT_SIZE 规则") + return "", 0, errors.New("交易对无 LOT_SIZE 规则") } qtyStr, ok, err := formatQtyToLotStep(want, lot.StepSize) if err != nil { - return "", err + return "", 0, err } if !ok { - return "", errors.New("数量不足") + return "", 0, errors.New("数量不足") } - return qtyStr, nil + return qtyStr, price, nil } func CalculateQtyByPrice(symbol string, price float64) string { diff --git a/internal/logic/run.go b/internal/logic/run.go index 58420e4..a4d661d 100644 --- a/internal/logic/run.go +++ b/internal/logic/run.go @@ -61,7 +61,7 @@ func Run(ctx context.Context) error { pnl := spotUnrealizedPnLPct(pos, price) if pnl >= profitArmPct { - trySpotRallySell(pos, pnl) + trySpotRallySell(pos, pnl, price) continue } if pos.DipAddsDone >= maxDipAdds {