Files
exchange_go/services/positionservice/position_management.go
2025-03-03 17:35:41 +08:00

132 lines
3.6 KiB
Go

package positionservice
import (
"context"
"fmt"
"go-admin/common/const/rediskey"
"go-admin/common/helper"
"go-admin/common/service"
"go-admin/models/positiondto"
"time"
"github.com/bytedance/sonic"
"github.com/go-admin-team/go-admin-core/logger"
"github.com/shopspring/decimal"
)
type BinancePositionManagement struct {
service.Service
}
// 保存仓位信息
// return 仓位信息
// return 错误信息
func (e *BinancePositionManagement) SavePosition(data *positiondto.PositionAddReq, exchangeType string) (positiondto.PositionDto, error) {
var key string
result := positiondto.PositionDto{}
switch data.SymbolType {
case 1:
key = fmt.Sprintf(rediskey.SpotPosition, exchangeType, data.ApiId, data.Symbol, data.Side)
case 2:
key = fmt.Sprintf(rediskey.FuturePosition, exchangeType, data.ApiId, data.Symbol, data.Side)
default:
return result, fmt.Errorf("symbol type error")
}
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotPositionLock, data.ApiId, data.Symbol, data.Side), 200, 5, 200*time.Millisecond)
if ok, err := lock.AcquireWait(context.Background()); err != nil {
logger.Debug("获取锁失败", err)
return result, err
} else if ok {
defer lock.Release()
val, _ := helper.DefaultRedis.GetString(key)
if val != "" {
sonic.Unmarshal([]byte(val), &result)
}
if result.Symbol == "" {
result.Symbol = data.Symbol
result.Side = data.Side
result.ApiId = data.ApiId
result.SymbolType = data.SymbolType
result.PositionSide = data.PositionSide
}
var totalLoss decimal.Decimal
if result.LastPrice.Cmp(decimal.Zero) > 0 {
switch {
//多 买入
case data.PositionSide == "LONG":
totalLoss = result.LastPrice.Sub(data.Price).Mul(result.Quantity)
if data.Price.Cmp(result.LastPrice) < 0 {
result.LastPrice = data.Price
}
case data.PositionSide == "SHORT":
totalLoss = data.Price.Sub(result.LastPrice).Mul(result.Quantity)
if data.Price.Cmp(result.LastPrice) > 0 {
result.LastPrice = data.Price
}
}
} else {
//默认没有金额的时候
result.LastPrice = data.Price
}
if totalLoss.Cmp(decimal.Zero) > 0 {
result.TotalLoss = result.TotalLoss.Add(totalLoss)
}
result.Quantity = data.Quantity.Add(result.Quantity)
dataVal, _ := sonic.MarshalString(result)
if err := helper.DefaultRedis.SetString(key, dataVal); err != nil {
logger.Errorf("保存仓位信息失败,val:%s err:%v", dataVal, err)
}
}
return result, nil
}
// 获取系统内仓位信息
func (e *BinancePositionManagement) GetPosition(apiId, symbolType int, exchangeTyp, symbol, side string) (positiondto.PositionDto, error) {
result := positiondto.PositionDto{}
var key string
switch symbolType {
case 1:
key = fmt.Sprintf(rediskey.SpotPosition, exchangeTyp, apiId, symbol, side)
case 2:
key = fmt.Sprintf(rediskey.FuturePosition, exchangeTyp, apiId, symbol, side)
default:
return result, fmt.Errorf("symbol type error")
}
val, _ := helper.DefaultRedis.GetString(key)
if val != "" {
sonic.Unmarshal([]byte(val), &result)
}
return result, nil
}
// 移除仓位信息
func (e *BinancePositionManagement) RemovePosition(req *positiondto.LinePreOrderPositioinDelReq) error {
var key string
switch req.SymbolType {
case 1:
key = fmt.Sprintf(rediskey.SpotPosition, req.ExchangeType, req.ApiId, req.Symbol, req.Side)
case 2:
key = fmt.Sprintf(rediskey.FuturePosition, req.ExchangeType, req.ApiId, req.Symbol, req.Side)
default:
return fmt.Errorf("symbol type error")
}
return helper.DefaultRedis.DeleteString(key)
}