1、合约止盈止损单在减仓单成交之后再取消
This commit is contained in:
@ -1015,7 +1015,6 @@ func createPreReduceOrder(preOrder *models.LinePreOrder, ext models.LinePreOrder
|
|||||||
|
|
||||||
stopOrder.OrderType = 4
|
stopOrder.OrderType = 4
|
||||||
stopOrder.Status = 0
|
stopOrder.Status = 0
|
||||||
stopOrder.Rate = ext.PriceRatio.String()
|
|
||||||
stopOrder.Num = ext.TotalAfter.Sub(ext.TotalBefore).Abs().Truncate(int32(tradeSet.AmountDigit)).String()
|
stopOrder.Num = ext.TotalAfter.Sub(ext.TotalBefore).Abs().Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
stopOrder.BuyPrice = "0"
|
stopOrder.BuyPrice = "0"
|
||||||
stopOrder.Rate = ext.PriceRatio.String()
|
stopOrder.Rate = ext.PriceRatio.String()
|
||||||
|
|||||||
@ -95,9 +95,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//现货最后成交价 sort set {exchangeType,symbol}
|
//现货最后成交价 sort set key:={exchangeType,symbol} content:={utc:price}
|
||||||
SpotTickerLastPrice = "spot_ticker_last_price:%s:%s"
|
SpotTickerLastPrice = "spot_ticker_last_price:%s:%s"
|
||||||
//合约最后成交价 sort set {exchangeType,symbol}
|
//合约最后成交价 sort set {exchangeType,symbol} content:={utc:price}
|
||||||
FutureTickerLastPrice = "fut_ticker_last_price:%s:%s"
|
FutureTickerLastPrice = "fut_ticker_last_price:%s:%s"
|
||||||
|
|
||||||
//允许缓存交易对价格的交易对 list
|
//允许缓存交易对价格的交易对 list
|
||||||
|
|||||||
@ -28,7 +28,7 @@ func TestFutureJudge(t *testing.T) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
|
key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
|
||||||
item := `{"id":50,"apiId":49,"mainId":47,"pid":47,"symbol":"ADAUSDT","price":"0.5936","side":"SELL","num":"12","orderSn":"397913127842217984"}`
|
item := `{"id":10,"apiId":49,"mainId":7,"pid":7,"symbol":"ADAUSDT","price":"0.6244","side":"BUY","num":"12","orderSn":"398690240274890752"}`
|
||||||
reduceOrder := ReduceListItem{}
|
reduceOrder := ReduceListItem{}
|
||||||
futApi := FutRestApi{}
|
futApi := FutRestApi{}
|
||||||
setting, err := cacheservice.GetSystemSetting(db)
|
setting, err := cacheservice.GetSystemSetting(db)
|
||||||
|
|||||||
@ -555,50 +555,6 @@ func (e FutRestApi) OrderPlace(orm *gorm.DB, params FutOrderPlace) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClosePositionB 平仓B对应的交易对
|
|
||||||
// bApiUserInfo B 账户api-user信息
|
|
||||||
// symbol 需要平仓的交易对
|
|
||||||
// closeType 平仓模式 ALL = 全平 reduceOnly = 只减仓
|
|
||||||
// func (e FutRestApi) ClosePositionB(orm *gorm.DB, bApiUserInfo *DbModels.LineApiUser, symbol string, closeType string) error {
|
|
||||||
// if bApiUserInfo == nil {
|
|
||||||
// return errors.New("缺失平仓账户信息")
|
|
||||||
// }
|
|
||||||
// if symbol == "" {
|
|
||||||
// return errors.New("缺失平仓交易对信息")
|
|
||||||
// }
|
|
||||||
// risks, err := e.GetPositionV3(bApiUserInfo, symbol)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for _, risk := range risks {
|
|
||||||
// if risk.Symbol == strings.ToUpper(symbol) {
|
|
||||||
// //持仓数量
|
|
||||||
// positionAmt, _ := decimal.NewFromString(risk.PositionAmt)
|
|
||||||
// side := "BUY"
|
|
||||||
// if positionAmt.GreaterThan(decimal.Zero) {
|
|
||||||
// side = "SELL"
|
|
||||||
// }
|
|
||||||
// var closeAmt decimal.Decimal
|
|
||||||
// if strings.ToUpper(closeType) == "ALL" { //全部平仓
|
|
||||||
// closeAmt = positionAmt
|
|
||||||
// } else {
|
|
||||||
// //如果是只减仓的话 数量=仓位数量*比例
|
|
||||||
// closeAmt = positionAmt.Mul(decimal.NewFromFloat(reduceOnlyRate))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err = e.ClosePosition(symbol, closeAmt, side, *bApiUserInfo, "MARKET", "", decimal.Zero)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// orm.Model(&DbModels.LinePreOrder{}).Where("api_id = ? AND symbol = ?", bApiUserInfo.Id, symbol).Updates(map[string]interface{}{
|
|
||||||
// "status": "6",
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 获取合约 持仓价格、数量
|
// 获取合约 持仓价格、数量
|
||||||
// symbol:交易对
|
// symbol:交易对
|
||||||
// side:方向
|
// side:方向
|
||||||
|
|||||||
@ -277,9 +277,10 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes
|
|||||||
} else if ok {
|
} else if ok {
|
||||||
defer lock.Release()
|
defer lock.Release()
|
||||||
takeOrders := make([]DbModels.LinePreOrder, 0)
|
takeOrders := make([]DbModels.LinePreOrder, 0)
|
||||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type IN (1,2,4) AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
|
//只取消减仓单 止盈止损减仓成功后取消
|
||||||
|
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type IN 4 AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
|
||||||
log.Error("查询止盈单失败")
|
log.Error("查询止盈单失败")
|
||||||
return false
|
// return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasrecord bool
|
var hasrecord bool
|
||||||
|
|||||||
@ -158,6 +158,8 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//取消委托中的止盈止损
|
||||||
|
cancelTakeProfitByReduce(db, apiUserInfo, preOrder.Symbol, preOrder.MainId, preOrder.SymbolType)
|
||||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutReducecCallback, preOrder.ApiId, preOrder.Symbol), 120, 20, 100*time.Millisecond)
|
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutReducecCallback, preOrder.ApiId, preOrder.Symbol), 120, 20, 100*time.Millisecond)
|
||||||
|
|
||||||
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||||
@ -179,6 +181,36 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 减仓成功后取消止盈止损
|
||||||
|
func cancelTakeProfitByReduce(db *gorm.DB, apiUserInfo DbModels.LineApiUser, symbol string, mainId int, symbolType int) {
|
||||||
|
orders, err := GetSymbolTakeAndStop(db, mainId, symbolType)
|
||||||
|
futApi := FutRestApi{}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("mainId:%d 获取委托中的止盈止损失败:%v", mainId, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
orderSns := make([]string, 0)
|
||||||
|
|
||||||
|
for _, v := range orders {
|
||||||
|
if v.OrderType != 1 && v.OrderType != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
orderSns = append(orderSns, v.OrderSn)
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := utility.SplitSlice(orderSns, 10)
|
||||||
|
|
||||||
|
for _, v := range arr {
|
||||||
|
err := futApi.CancelBatchFutOrder(apiUserInfo, symbol, v)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("mainId:%d 取消止盈止损失败:%v", mainId, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 减仓处理止盈止损
|
// 减仓处理止盈止损
|
||||||
func FutTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder, apiUserInfo DbModels.LineApiUser, tradeSet models2.TradeSet,
|
func FutTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder, apiUserInfo DbModels.LineApiUser, tradeSet models2.TradeSet,
|
||||||
positionData positiondto.PositionDto, orderExt DbModels.LinePreOrderExt, manualTakeRatio, manualStopRatio decimal.Decimal) bool {
|
positionData positiondto.PositionDto, orderExt DbModels.LinePreOrderExt, manualTakeRatio, manualStopRatio decimal.Decimal) bool {
|
||||||
|
|||||||
@ -134,7 +134,7 @@ func GetTotalLossAmount(db *gorm.DB, mainId int) (decimal.Decimal, error) {
|
|||||||
return totalLossAmountU, nil
|
return totalLossAmountU, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取交易对的 委托中的止盈止损
|
// 获取交易对的 委托中的止盈止损、减仓单
|
||||||
// mainId 主单id
|
// mainId 主单id
|
||||||
// symbolType 交易对类型
|
// symbolType 交易对类型
|
||||||
func GetSymbolTakeAndStop(db *gorm.DB, mainId int, symbolType int) ([]models.LinePreOrder, error) {
|
func GetSymbolTakeAndStop(db *gorm.DB, mainId int, symbolType int) ([]models.LinePreOrder, error) {
|
||||||
|
|||||||
@ -12,9 +12,11 @@ import (
|
|||||||
models2 "go-admin/models"
|
models2 "go-admin/models"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
"go-admin/services/cacheservice"
|
"go-admin/services/cacheservice"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
@ -95,8 +97,16 @@ func (e *BinanceStrategyOrderService) JudgeStrategy(order dto.StrategyOrderRedis
|
|||||||
}
|
}
|
||||||
|
|
||||||
score := lastPrices[0].Score
|
score := lastPrices[0].Score
|
||||||
startPrice := utility.StrToDecimal(beforePrice)
|
var startPrice decimal.Decimal
|
||||||
lastPrice := utility.StrToDecimal(lastPrices[0].Member.(string))
|
var lastPrice decimal.Decimal
|
||||||
|
startPriceArgs := strings.Split(beforePrice, ":")
|
||||||
|
endPricecArgs := strings.Split(lastPrices[0].Member.(string), ":")
|
||||||
|
|
||||||
|
if len(startPriceArgs) == 0 || len(endPricecArgs) == 0 {
|
||||||
|
return result, errors.New("获取交易对起止价格失败")
|
||||||
|
}
|
||||||
|
startPrice = utility.StrToDecimal(startPriceArgs[len(startPriceArgs)-1])
|
||||||
|
lastPrice = utility.StrToDecimal(endPricecArgs[len(endPricecArgs)-1])
|
||||||
|
|
||||||
//时间差超过10s
|
//时间差超过10s
|
||||||
if (nowUtc-int64(score))/1000 > 10 {
|
if (nowUtc-int64(score))/1000 > 10 {
|
||||||
@ -188,33 +198,81 @@ func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet
|
|||||||
mainOrder.SignPrice = lastPrice.String()
|
mainOrder.SignPrice = lastPrice.String()
|
||||||
mainOrder.Price = newPrice.String()
|
mainOrder.Price = newPrice.String()
|
||||||
mainOrder.Num = totalNum.String()
|
mainOrder.Num = totalNum.String()
|
||||||
|
remainQuantity := totalNum
|
||||||
|
|
||||||
for index := range mainOrder.Childs {
|
for index := range mainOrder.Childs {
|
||||||
//主单止盈
|
var ext models.LinePreOrderExt
|
||||||
if mainOrder.Child[index].OrderType == 1 {
|
for _, v := range exts {
|
||||||
var ext models.LinePreOrderExt
|
if v.OrderId == mainOrder.Child[index].Id {
|
||||||
|
ext = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ext.Id <= 0 {
|
||||||
|
logger.Errorf("子订单ext不存在 id:%d", mainOrder.Child[index].Id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range exts {
|
//主单止盈、止损
|
||||||
if v.OrderId == mainOrder.Child[index].Id {
|
if mainOrder.Child[index].Pid == mainOrder.Child[index].MainId && (mainOrder.Child[index].OrderType == 1 || mainOrder.Child[index].OrderType == 2) {
|
||||||
ext = v
|
var percent decimal.Decimal
|
||||||
break
|
|
||||||
}
|
switch {
|
||||||
|
// 加价
|
||||||
|
case mainOrder.Child[index].OrderType == 1 && mainOrder.Site == "BUY", mainOrder.Child[index].OrderType == 2 && mainOrder.Site == "SELL":
|
||||||
|
percent = decimal.NewFromInt(100).Add(ext.TakeProfitRatio)
|
||||||
|
//减价
|
||||||
|
case mainOrder.Child[index].OrderType == 2 && mainOrder.Site == "BUY", mainOrder.Child[index].OrderType == 1 && mainOrder.Site == "SELL":
|
||||||
|
percent = decimal.NewFromInt(100).Sub(ext.StopLossRatio)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ext.Id > 0 {
|
childPrice := lastPrice.Mul(percent.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.PriceDigit))
|
||||||
var percent decimal.Decimal
|
mainOrder.Child[index].Price = childPrice.String()
|
||||||
//多
|
mainOrder.Child[index].Num = totalNum.String()
|
||||||
if mainOrder.Site == "BUY" {
|
|
||||||
percent = decimal.NewFromInt(100).Add(ext.TakeProfitRatio)
|
|
||||||
} else {
|
|
||||||
percent = decimal.NewFromInt(100).Sub(ext.StopLossRatio)
|
|
||||||
}
|
|
||||||
|
|
||||||
childPrice := lastPrice.Mul(percent.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.PriceDigit))
|
|
||||||
mainOrder.Child[index].Price = childPrice.String()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
//todo 重新计算
|
//todo 重新计算
|
||||||
|
lastNum := remainQuantity
|
||||||
|
|
||||||
|
//过期时间
|
||||||
|
if ext.ExpirateHour <= 0 {
|
||||||
|
mainOrder.Child[index].ExpireTime = time.Now().AddDate(10, 0, 0)
|
||||||
|
} else {
|
||||||
|
mainOrder.Child[index].ExpireTime = time.Now().Add(time.Hour * time.Duration(ext.ExpirateHour))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
//加仓单
|
||||||
|
case mainOrder.Child[index].OrderType == 1 && mainOrder.Child[index].OrderCategory == 3:
|
||||||
|
var percentage decimal.Decimal
|
||||||
|
|
||||||
|
if mainOrder.Site == "BUY" {
|
||||||
|
percentage = decimal.NewFromInt(1).Sub(ext.PriceRatio.Div(decimal.NewFromInt(100)))
|
||||||
|
} else {
|
||||||
|
percentage = decimal.NewFromInt(1).Add(ext.PriceRatio.Div(decimal.NewFromInt(100)))
|
||||||
|
}
|
||||||
|
|
||||||
|
dataPrice := utility.StrToDecimal(mainOrder.Price).Mul(percentage).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
mainOrder.Child[index].Price = dataPrice.String()
|
||||||
|
|
||||||
|
if ext.AddPositionType == 1 {
|
||||||
|
buyPrice := utility.StrToDecimal(mainOrder.BuyPrice).Mul(utility.SafeDiv(ext.AddPositionVal, decimal.NewFromInt(100))).Truncate(2)
|
||||||
|
mainOrder.Child[index].Num = utility.SafeDiv(buyPrice, dataPrice).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
mainOrder.Child[index].Num = utility.SafeDiv(ext.AddPositionVal.Truncate(2), dataPrice).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
//加库存
|
||||||
|
lastNum = lastNum.Add(utility.StrToDecimal(mainOrder.Child[index].Num))
|
||||||
|
//todo 计算子订单
|
||||||
|
//减仓单
|
||||||
|
case mainOrder.Child[index].OrderType == 4:
|
||||||
|
// todo 计算
|
||||||
|
//减库存
|
||||||
|
lastNum = lastNum.Add(utility.StrToDecimal(mainOrder.Child[index].Num))
|
||||||
|
//todo 计算子订单
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -162,14 +162,19 @@ func handleTickerAllMessage(msg []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//行情存储时间
|
val, _ := helper.DefaultRedis.GetAllList(rediskey.CacheSymbolLastPrice)
|
||||||
lastUtc := utcTime - 1000*60*60
|
|
||||||
if _, err := helper.DefaultRedis.RemoveBeforeScore(lastPriceKey, float64(lastUtc)); err != nil {
|
|
||||||
log.Errorf("移除 合约交易对:%s %d之前的最新成交价失败,err:%v", symbol, lastUtc, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := helper.DefaultRedis.AddSortSet(lastPriceKey, float64(utcTime), lastPrice.String()); err != nil {
|
if utility.ContainsStr(val, symbol) {
|
||||||
log.Errorf("添加 合约交易对:%s %d之前的最新成交价失败,err:%v", symbol, lastUtc, err)
|
//行情存储时间
|
||||||
|
lastUtc := utcTime - 1000*60*60
|
||||||
|
content := fmt.Sprintf("%d:%s", utcTime, lastPrice.String())
|
||||||
|
if _, err := helper.DefaultRedis.RemoveBeforeScore(lastPriceKey, float64(lastUtc)); err != nil {
|
||||||
|
log.Errorf("移除 合约交易对:%s %d之前的最新成交价失败,err:%v", symbol, lastUtc, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := helper.DefaultRedis.AddSortSet(lastPriceKey, float64(utcTime), content); err != nil {
|
||||||
|
log.Errorf("添加 合约交易对:%s %d之前的最新成交价失败,err:%v", symbol, lastUtc, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -250,15 +250,20 @@ func handleTickerMessage(msg []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//行情存储时间
|
val, _ := helper.DefaultRedis.GetAllList(rediskey.CacheSymbolLastPrice)
|
||||||
lastUtc := utcTime - 1000*60*60
|
|
||||||
|
|
||||||
if _, err := helper.DefaultRedis.RemoveBeforeScore(lastPriceKey, float64(lastUtc)); err != nil {
|
if utility.ContainsStr(val, symbolName) {
|
||||||
log.Errorf("移除 现货交易对:%s %d之前的最新成交价失败,err:%v", symbolName, lastUtc, err)
|
//行情存储时间
|
||||||
}
|
lastUtc := utcTime - 1000*60*60
|
||||||
|
content := fmt.Sprintf("%d:%s", utcTime, lastPrice.String())
|
||||||
|
|
||||||
if err := helper.DefaultRedis.AddSortSet(lastPriceKey, float64(utcTime), lastPrice.String()); err != nil {
|
if _, err := helper.DefaultRedis.RemoveBeforeScore(lastPriceKey, float64(lastUtc)); err != nil {
|
||||||
log.Errorf("添加 现货交易对:%s %d之前的最新成交价失败,err:%v", symbolName, lastUtc, err)
|
log.Errorf("移除 现货交易对:%s %d之前的最新成交价失败,err:%v", symbolName, lastUtc, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := helper.DefaultRedis.AddSortSet(lastPriceKey, float64(utcTime), content); err != nil {
|
||||||
|
log.Errorf("添加 现货交易对:%s %d之前的最新成交价失败,err:%v", symbolName, lastUtc, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user