135 lines
3.7 KiB
Go
135 lines
3.7 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
|
|
}
|
|
|
|
//总亏损大于0
|
|
if totalLoss.Add(result.TotalLoss).Cmp(decimal.Zero) > 0 {
|
|
result.TotalLoss = result.TotalLoss.Add(totalLoss)
|
|
} else {
|
|
result.TotalLoss = decimal.Zero
|
|
}
|
|
|
|
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)
|
|
}
|