1\交易对返回价格

This commit is contained in:
2025-02-15 18:38:58 +08:00
parent 7892c9c9dd
commit eb2455f967
10 changed files with 182 additions and 28 deletions

View File

@ -602,3 +602,29 @@ func (e LinePreOrder) QueryAiCoinPrice(c *gin.Context) {
}
e.OK(res, "操作成功")
}
// 计算回本盈利比例
func (e LinePreOrder) CalculateBreakEevenRatio(c *gin.Context) {
s := service.LinePreOrder{}
req := dto.CalculateBreakEevenRatioReq{}
err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
Errors
if err != nil {
e.Logger.Error(err)
e.Error(500, err, err.Error())
return
}
data := dto.CalculateBreakEvenRatioResp{}
err = s.CalculateBreakEvenRatio(&req, &data)
if err != nil {
e.Error(500, err, err.Error())
return
}
e.OK(data, "操作成功")
}

View File

@ -2,19 +2,22 @@ package models
import (
"go-admin/common/models"
"github.com/shopspring/decimal"
)
type LineSymbol struct {
models.Model
ExchangeType string `json:"exchangeType" gorm:"type:varchar(20);comment:交易所类型 字典 exchange_type"`
ApiId string `json:"apiId" gorm:"type:int;comment:api账户id"`
Symbol string `json:"symbol" gorm:"type:varchar(32);comment:交易对"`
BaseAsset string `json:"baseAsset" gorm:"type:varchar(255);comment:基础货币"`
QuoteAsset string `json:"quoteAsset" gorm:"type:varchar(255);comment:计价货币"`
Switch string `json:"switch" gorm:"type:enum('0','1');comment:状态"`
Type string `json:"type" gorm:"type:enum('1','2');comment:交易对类型"`
Number int `json:"number" gorm:"->"`
ExchangeType string `json:"exchangeType" gorm:"type:varchar(20);comment:交易所类型 字典 exchange_type"`
ApiId string `json:"apiId" gorm:"type:int;comment:api账户id"`
Symbol string `json:"symbol" gorm:"type:varchar(32);comment:交易对"`
BaseAsset string `json:"baseAsset" gorm:"type:varchar(255);comment:基础货币"`
QuoteAsset string `json:"quoteAsset" gorm:"type:varchar(255);comment:计价货币"`
Switch string `json:"switch" gorm:"type:enum('0','1');comment:状态"`
Type string `json:"type" gorm:"type:enum('1','2');comment:交易对类型"`
Number int `json:"number" gorm:"->"`
LastPrice decimal.Decimal `json:"lastPrice"gorm:"->"`
models.ModelTime
models.ControlBy
}

View File

@ -37,6 +37,8 @@ func registerLinePreOrderRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTM
r.GET("getOrderPage", actions.PermissionAction(), api.GetOrderPage) //订单列表
r.POST("clearUnTriggered", actions.PermissionAction(), api.ClearUnTriggered) // 清除待触发的交易对
r.POST("aiCoinPrice", actions.PermissionAction(), api.QueryAiCoinPrice) //获取aiCoin买入点
r.GET("/calculate", api.CalculateBreakEevenRatio) //计算亏损后止盈百分比
}
}

View File

@ -446,6 +446,29 @@ type QueryAiCoinPriceReq struct {
Symbol string `json:"symbol"` //交易对
}
// 计算亏损止盈百分比
type CalculateBreakEevenRatioReq struct {
Price decimal.Decimal `form:"price"`
Symbol string `form:"symbol"` //交易对
ExchangeType string `form:"exchangeType"` //交易所类型 字典exchange_type
SymbolType int `form:"symbolType"`
BuyPrice decimal.Decimal `form:"buyPrice"` //主单购买总金额
LossBeginPercent decimal.Decimal `form:"lossBeginPercent"` //亏损开始百分比
LossEndPercent decimal.Decimal `form:"lossEndPercent"` //亏损截至百分比
AddPositionType int `form:"addPositionType"` //加仓类型 1-百分比 2-实际金额
AddPositionVal decimal.Decimal `form:"addPositionVal"` //加仓金额
ReducePercent decimal.Decimal `form:"reducePercent"` //减仓百分比
RemainingQuantity decimal.Decimal `form:"remainingQuantity"` //剩余数量
TotalLossAmountU decimal.Decimal `form:"totalLossAmountU"` //累计亏损金额
}
// 计算亏损返回值
type CalculateBreakEvenRatioResp struct {
RemainingQuantity decimal.Decimal `json:"remainingQuantity"` //剩余数量
Ratio decimal.Decimal `json:"ratio"` //亏损止盈百分比
TotalLossAmountU decimal.Decimal `json:"totalLossAmountU"` //总亏损金额
}
type SpotQueryOrderResp struct {
Symbol string `json:"symbol"`
OrderId int `json:"orderId"`

View File

@ -1316,3 +1316,65 @@ func (e *LinePreOrder) QueryAiCoinPrice(req *dto.QueryAiCoinPriceReq) (models.Li
err := e.Orm.Model(&models.LineDirection{}).Where("symbol = ?", req.Symbol).Find(&info).Error
return info, err
}
// 计算亏损百分比
func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatioReq, data *dto.CalculateBreakEvenRatioResp) error {
var tradeSet models2.TradeSet
if req.LossEndPercent.Cmp(req.LossBeginPercent) < 0 {
return errors.New("截至亏损百分比必须大于开始亏损百分比")
}
if req.SymbolType == 1 {
val, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.TICKER_SPOT, req.ExchangeType, req.Symbol))
sonic.Unmarshal([]byte(val), &tradeSet)
} else if req.SymbolType == 2 {
val, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.TICKER_FUTURES, req.ExchangeType, req.Symbol))
sonic.Unmarshal([]byte(val), &tradeSet)
} else {
return errors.New("symbolType error")
}
if tradeSet.LastPrice == "" {
return errors.New("没有找到交易对行情")
}
var addPositionBuyPrice decimal.Decimal
if req.AddPositionType == 1 {
addPositionBuyPrice = req.BuyPrice.Mul(req.AddPositionVal.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(2)
} else {
addPositionBuyPrice = req.BuyPrice.Add(req.AddPositionVal).Truncate(2)
}
var percentDiff decimal.Decimal
var reduceAmount decimal.Decimal
nowPrice := req.Price.Mul(decimal.NewFromInt(1).Sub(req.LossEndPercent.Div(decimal.NewFromInt(100).Truncate(4))))
addPositionAmount := addPositionBuyPrice.Div(nowPrice).Truncate(int32(tradeSet.AmountDigit))
//计算价格下跌价差
if req.LossEndPercent.Cmp(req.LossBeginPercent) > 0 {
percentDiff = req.LossEndPercent.Sub(req.LossBeginPercent).Abs()
}
totalAmount := req.RemainingQuantity.Add(addPositionAmount)
lossAmountU := req.Price.Mul(percentDiff.Div(decimal.NewFromInt(100)).Truncate(4)).Mul(req.RemainingQuantity).Truncate(int32(tradeSet.AmountDigit))
//计算减仓数量
if req.ReducePercent.Cmp(decimal.NewFromInt(0)) > 0 {
reduceAmount = totalAmount.Mul(req.ReducePercent.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.AmountDigit))
}
data.RemainingQuantity = totalAmount.Sub(reduceAmount)
data.TotalLossAmountU = lossAmountU.Add(req.TotalLossAmountU)
//计算百分比
if data.RemainingQuantity.Cmp(decimal.Zero) > 0 {
data.Ratio = data.TotalLossAmountU.Div(data.RemainingQuantity).Div(nowPrice).Mul(decimal.NewFromInt(100)).Truncate(2)
}
return nil
}

View File

@ -44,6 +44,35 @@ func (e *LineSymbol) GetPage(c *dto.LineSymbolGetPageReq, p *actions.DataPermiss
e.Log.Errorf("LineSymbolService GetPage error:%s \r\n", err)
return err
}
var key string
if c.Type == "1" {
key = fmt.Sprintf(global.TICKER_SPOT, c.ExchangeType, "*")
} else {
key = fmt.Sprintf(global.TICKER_FUTURES, c.ExchangeType, "*")
}
tickers, _ := helper.DefaultRedis.GetAllKeysAndValues(key)
allTicker := make(map[string]commonModels.TradeSet)
tradeSet := commonModels.TradeSet{}
for _, v := range tickers {
sonic.Unmarshal([]byte(v), &tradeSet)
if tradeSet.Coin != "" && tradeSet.Currency != "" {
allTicker[tradeSet.Coin+tradeSet.Currency] = tradeSet
}
}
for index := range *list {
symbol := (*list)[index].Symbol
if v, ok := allTicker[symbol]; ok {
(*list)[index].LastPrice = utility.StrToDecimal(v.LastPrice)
}
}
return nil
}

View File

@ -10,7 +10,6 @@ import (
"go-admin/common/global"
"go-admin/common/helper"
"go-admin/models"
"go-admin/pkg/utility"
"strings"
"time"
@ -233,7 +232,7 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes
}
price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
num := utility.StrToDecimal(takeOrder.Num).Truncate(int32(tradeSet.AmountDigit))
num := reduceOrder.Num.Truncate(int32(tradeSet.AmountDigit))
var positionSide string
if reduceOrder.Side == "BUY" {
@ -338,7 +337,7 @@ func FutAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, futApi
return
}
price := v.Price
price := v.Price.Truncate(int32(tradeSet.PriceDigit))
num, _ := decimal.NewFromString(preOrder.Num)
if setting.AddPositionPremium.Cmp(decimal.Zero) > 0 {
@ -351,7 +350,7 @@ func FutAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, futApi
Side: v.Side,
OrderType: "LIMIT",
Price: price,
Quantity: num,
Quantity: num.Truncate(int32(tradeSet.AmountDigit)),
NewClientOrderId: v.OrderSn,
}
preOrderVal, _ := sonic.MarshalString(&v)

View File

@ -196,7 +196,7 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
takeProfitOrder.Rate = ext.ReduceTakeProfitRatio.String()
//止盈需要累加之前的亏损
if totalLossAmountU.Cmp(decimal.Zero) > 0 {
percent := totalLossAmountU.Div(totalNum).Div(price).Sub(decimal.NewFromInt(1)).Abs()
percent := totalLossAmountU.Div(totalNum).Div(price).Abs()
takeProfitOrder.Rate = percent.Mul(decimal.NewFromInt(100)).Add(ext.ReduceTakeProfitRatio).Truncate(2).String()
}
@ -241,7 +241,7 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
//加仓待触发
addPositionOrder := DbModels.LinePreOrder{}
if err := db.Model(&addPositionOrder).Where("main_id =? AND order_category=3 AND status=0", preOrder.MainId).First(addPositionOrder).Error; err != nil {
if err := db.Model(&addPositionOrder).Where("main_id =? AND order_category=3 AND status=0", preOrder.MainId).First(&addPositionOrder).Error; err != nil {
logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
return
}
@ -301,7 +301,8 @@ func getFuturesPositionAvailableQuantity(db *gorm.DB, apiUserInfo DbModels.LineA
if totalNum.Cmp(decimal.Zero) <= 0 {
totalNum = utility.StrToDecimal(preOrder.Num)
}
return totalNum
return totalNum.Truncate(int32(tradeSet.AmountDigit))
}
// 获取币安合约持仓
@ -524,16 +525,16 @@ func createFutPreAddPosition(preOrder *DbModels.LinePreOrder, db *gorm.DB, trade
var percentage decimal.Decimal
if data.Site == "BUY" {
percentage = decimal.NewFromInt(1).Add(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
} else {
percentage = decimal.NewFromInt(1).Sub(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
} else {
percentage = decimal.NewFromInt(1).Add(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
}
dataPrice := price.Mul(percentage).Truncate(int32(tradeSet.PriceDigit))
data.Price = dataPrice.String()
if v.AddPositionType == 1 {
data.Num = preOrder.Num
data.Num = utility.StrToDecimal(preOrder.Num).Truncate(int32(tradeSet.AmountDigit)).String()
data.BuyPrice = "0"
} else {
data.BuyPrice = v.AddPositionVal.String()
@ -588,6 +589,7 @@ func makeFuturesTakeAndReduce(preOrder *DbModels.LinePreOrder, db *gorm.DB, trad
profitOrder := models.LinePreOrder{}
copier.Copy(&profitOrder, preOrder)
profitOrder.Id = 0
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
profitOrder.Pid = preOrder.Id
profitOrder.OrderType = 1
@ -598,7 +600,7 @@ func makeFuturesTakeAndReduce(preOrder *DbModels.LinePreOrder, db *gorm.DB, trad
//止盈需要累加之前的亏损
if totalLossAmountU.Cmp(decimal.Zero) > 0 {
percent := totalLossAmountU.Div(num).Div(price).Sub(decimal.NewFromInt(1)).Abs()
percent := totalLossAmountU.Div(num).Div(price).Abs()
profitOrder.Rate = percent.Mul(decimal.NewFromInt(100)).Add(ext.TakeProfitRatio).Truncate(2).String()
}
@ -617,6 +619,7 @@ func makeFuturesTakeAndReduce(preOrder *DbModels.LinePreOrder, db *gorm.DB, trad
stopOrder := models.LinePreOrder{}
copier.Copy(&stopOrder, preOrder)
stopOrder.Id = 0
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
stopOrder.Pid = preOrder.Id
stopOrder.MainId = ext.MainOrderId

View File

@ -83,6 +83,13 @@ func SpotOrderLock(db *gorm.DB, v *dto.PreOrderRedisList, item string, spotApi S
return
}
//判断是否有已触发交易对
count, _ := GetSymbolTriggerCount(db, v.Symbol, 2)
if count > 0 {
return
}
price, _ := decimal.NewFromString(v.Price)
num, _ := decimal.NewFromString(preOrder.Num)
params := OrderPlacementService{
@ -419,13 +426,6 @@ func SpotAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, spotAp
return
}
//判断是否有已触发交易对
count, _ := GetSymbolTriggerCount(db, v.Symbol, 2)
if count > 0 {
return
}
price := v.Price
num, _ := decimal.NewFromString(preOrder.Num)

View File

@ -199,7 +199,7 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
takeProfitOrder.Rate = ext.ReduceTakeProfitRatio.String()
//止盈需要累加之前的亏损
if totalLossAmountU.Cmp(decimal.Zero) > 0 {
percent := totalLossAmountU.Div(totalNum).Div(price).Sub(decimal.NewFromInt(1)).Abs()
percent := totalLossAmountU.Div(totalNum).Div(price).Abs()
takeProfitOrder.Rate = percent.Mul(decimal.NewFromInt(100)).Add(ext.ReduceTakeProfitRatio).Truncate(2).String()
}
@ -252,6 +252,12 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
}
}
for _, item := range orders {
if item.OrderType == 2 {
processStopLossOrder(item)
}
}
//计算实际亏损
if parentOrder.Price != "" {
parentPrice := utility.StrToDecimal(parentOrder.Price)
@ -734,7 +740,7 @@ func makeSpotTakeAndReduce(preOrder *DbModels.LinePreOrder, db *gorm.DB, tradeSe
//止盈需要累加之前的亏损
if totalLossAmountU.Cmp(decimal.Zero) > 0 {
percent := totalLossAmountU.Div(num).Div(price).Sub(decimal.NewFromInt(1)).Abs()
percent := totalLossAmountU.Div(num).Div(price).Abs()
profitOrder.Rate = percent.Mul(decimal.NewFromInt(100)).Add(ext.TakeProfitRatio).Truncate(2).String()
}
@ -874,6 +880,7 @@ func processStopLossOrder(order models.LinePreOrder) error {
price := utility.StrToDecimal(order.Price)
stopLoss := dto.StopLossRedisList{
Id: order.Id,
MainId: order.MainId,
PId: order.Pid,
ApiId: order.ApiId,
OrderTye: order.OrderType,