1、阶段减仓
This commit is contained in:
63
services/binanceservice/futures_judge_service_test.go
Normal file
63
services/binanceservice/futures_judge_service_test.go
Normal file
@ -0,0 +1,63 @@
|
||||
package binanceservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go-admin/common/const/rediskey"
|
||||
"go-admin/common/global"
|
||||
"go-admin/common/helper"
|
||||
"go-admin/models"
|
||||
"go-admin/services/cacheservice"
|
||||
"testing"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/go-admin-team/go-admin-core/logger"
|
||||
"github.com/go-admin-team/go-admin-core/sdk"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestFutureJudge(t *testing.T) {
|
||||
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||
helper.InitLockRedisConn("127.0.0.1:6379", "", "2")
|
||||
// tradeSet := models.TradeSet{
|
||||
// Coin: "ADA",
|
||||
// Currency: "USDT",
|
||||
// LastPrice: "0.516",
|
||||
// }
|
||||
|
||||
key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
|
||||
item := `{"id":4,"apiId":49,"mainId":1,"pid":1,"symbol":"ADAUSDT","price":"0.5417","side":"SELL","num":"13","orderSn":"397659701065547776"}`
|
||||
reduceOrder := ReduceListItem{}
|
||||
futApi := FutRestApi{}
|
||||
setting, err := cacheservice.GetSystemSetting(db)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("获取系统设置失败")
|
||||
return
|
||||
}
|
||||
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
||||
logger.Error("反序列化失败")
|
||||
return
|
||||
}
|
||||
// JudgeFuturesReduce(tradeSet)
|
||||
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false)
|
||||
}
|
||||
|
||||
// 测试减仓后减仓触发
|
||||
func TestFutureReduceReduce(t *testing.T) {
|
||||
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
sdk.Runtime.SetDb("default", db)
|
||||
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||
helper.InitLockRedisConn("127.0.0.1:6379", "", "2")
|
||||
tradeSet := models.TradeSet{
|
||||
Coin: "ADA",
|
||||
Currency: "USDT",
|
||||
LastPrice: "0.5307",
|
||||
}
|
||||
|
||||
// JudgeFuturesReduce(tradeSet)
|
||||
JudgeFuturesReduce(tradeSet)
|
||||
}
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"go-admin/common/global"
|
||||
"go-admin/common/helper"
|
||||
"go-admin/models"
|
||||
"go-admin/pkg/utility"
|
||||
"go-admin/services/cacheservice"
|
||||
"strings"
|
||||
"time"
|
||||
@ -161,30 +162,83 @@ func JudgeFuturesReduce(trade models.TradeSet) {
|
||||
return
|
||||
}
|
||||
|
||||
reduceOrder := ReduceListItem{}
|
||||
tradePrice, _ := decimal.NewFromString(trade.LastPrice)
|
||||
//减仓单减仓策略
|
||||
orderReduceVal, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE))
|
||||
reduceReduceListKey := fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||
orderReduceVal, _ := helper.DefaultRedis.HGetAllFields(reduceReduceListKey)
|
||||
reduceOrderStrategy := dto.LineOrderReduceStrategyResp{}
|
||||
|
||||
for _, item := range orderReduceVal {
|
||||
sonic.Unmarshal([]byte(item), &reduceOrderStrategy)
|
||||
|
||||
for _, item2 := range reduceOrderStrategy.Items {
|
||||
if reduceOrderStrategy.Symbol == trade.Coin+trade.Currency {
|
||||
for index, item2 := range reduceOrderStrategy.Items {
|
||||
if reduceOrderStrategy.Symbol == trade.Coin+trade.Currency && !item2.Actived {
|
||||
//买入
|
||||
if item2.TriggerPrice.Cmp(decimal.Zero) > 0 &&
|
||||
tradePrice.Cmp(decimal.Zero) > 0 &&
|
||||
((strings.ToUpper(reduceOrderStrategy.Side) == "SELL" && item2.TriggerPrice.Cmp(tradePrice) >= 0) ||
|
||||
(strings.ToUpper(reduceOrderStrategy.Side) == "BUY" && item2.TriggerPrice.Cmp(tradePrice) <= 0)) {
|
||||
//todo 生成订单并触发
|
||||
// SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item)
|
||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.ReduceStrategyFutTriggerLock, reduceOrder.ApiId, reduceOrder.Symbol), 50, 15, 100*time.Millisecond)
|
||||
|
||||
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||
log.Error("获取锁失败", err)
|
||||
return
|
||||
} else if ok {
|
||||
defer lock.Release()
|
||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(reduceReduceListKey, item)
|
||||
|
||||
if !hasrecord {
|
||||
log.Debug("减仓缓存中不存在", item)
|
||||
return
|
||||
}
|
||||
|
||||
order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.AmountDigit)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("%d 生成订单失败", reduceOrderStrategy.OrderId)
|
||||
}
|
||||
|
||||
reduceOrder.ApiId = order.ApiId
|
||||
reduceOrder.Id = order.Id
|
||||
reduceOrder.Pid = order.Pid
|
||||
reduceOrder.MainId = order.MainId
|
||||
reduceOrder.Symbol = order.Symbol
|
||||
reduceOrder.Side = reduceOrderStrategy.Side
|
||||
reduceOrder.OrderSn = order.OrderSn
|
||||
reduceOrder.Price = item2.Price
|
||||
reduceOrder.Num = item2.Num
|
||||
//下单成功修改策略节点状态
|
||||
if FuturesReduceTrigger(db, reduceOrder, futApi, setting, reduceReduceListKey, item, true) {
|
||||
reduceOrderStrategy.Items[index].Actived = true
|
||||
allActive := true
|
||||
orderId := utility.IntToString(reduceOrderStrategy.OrderId)
|
||||
|
||||
for _, item3 := range reduceOrderStrategy.Items {
|
||||
if !item3.Actived {
|
||||
allActive = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if allActive {
|
||||
if err := helper.DefaultRedis.HDelField(reduceReduceListKey, orderId); err != nil {
|
||||
log.Errorf("删除redis reduceReduceListKey失败 %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
str, _ := sonic.MarshalString(reduceOrderStrategy)
|
||||
if err := helper.DefaultRedis.HSetField(reduceReduceListKey, orderId, str); err != nil {
|
||||
log.Errorf("更新redis reduceReduceListKey失败 %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, item := range reduceVal {
|
||||
reduceOrder := ReduceListItem{}
|
||||
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
||||
log.Error("反序列化失败")
|
||||
continue
|
||||
@ -198,52 +252,54 @@ func JudgeFuturesReduce(trade models.TradeSet) {
|
||||
((strings.ToUpper(reduceOrder.Side) == "SELL" && orderPrice.Cmp(tradePrice) >= 0) ||
|
||||
(strings.ToUpper(reduceOrder.Side) == "BUY" && orderPrice.Cmp(tradePrice) <= 0)) {
|
||||
|
||||
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item)
|
||||
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 触发合约减仓
|
||||
func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string) {
|
||||
// isStrategy 是否是策略减仓
|
||||
func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool) bool {
|
||||
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 1)
|
||||
result := true
|
||||
|
||||
if tradeSet.LastPrice == "" {
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutTrigger, reduceOrder.ApiId, reduceOrder.Symbol), 20, 5, 100*time.Millisecond)
|
||||
|
||||
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||
log.Error("获取锁失败", err)
|
||||
return
|
||||
return false
|
||||
} else if ok {
|
||||
defer lock.Release()
|
||||
takeOrders := make([]DbModels.LinePreOrder, 0)
|
||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type =1 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 (1,2,4) AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
|
||||
log.Error("查询止盈单失败")
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)
|
||||
|
||||
if !hasrecord {
|
||||
log.Debug("减仓缓存中不存在", item)
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
apiInfo, _ := GetApiInfo(reduceOrder.ApiId)
|
||||
|
||||
if apiInfo.Id == 0 {
|
||||
log.Error("现货减仓 查询api用户不存在")
|
||||
return
|
||||
return false
|
||||
}
|
||||
for _, takeOrder := range takeOrders {
|
||||
err := CancelFutOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn)
|
||||
|
||||
if err != nil {
|
||||
log.Error("合约止盈撤单失败", err)
|
||||
return
|
||||
log.Error("撤单失败", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,6 +314,7 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes
|
||||
}
|
||||
|
||||
if err := futApi.ClosePositionLoop(reduceOrder.Symbol, reduceOrder.OrderSn, num, reduceOrder.Side, positionSide, apiInfo, "LIMIT", "0", price, 3); err != nil {
|
||||
result = false
|
||||
log.Errorf("合约减仓挂单失败 id:%s err:%v", reduceOrder.Id, err)
|
||||
|
||||
if err2 := db.Model(&DbModels.LinePreOrder{}).
|
||||
@ -276,15 +333,22 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes
|
||||
}
|
||||
|
||||
//处理减仓单减仓策略
|
||||
CacheOrderStrategyAndReCreate(db, reduceOrder, 2, tradeSet, setting)
|
||||
if err := CacheOrderStrategyAndReCreate(db, reduceOrder, 2, tradeSet, setting); err != nil {
|
||||
log.Errorf("合约减仓策略处理失败 id:%s err:%v", reduceOrder.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
|
||||
log.Errorf("合约减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
|
||||
if !isStrategy {
|
||||
if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
|
||||
log.Errorf("合约减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Error("获取锁失败")
|
||||
result = false
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 判断合约加仓
|
||||
|
||||
@ -163,9 +163,9 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
positionData := savePosition(db, preOrder)
|
||||
|
||||
//市价单就跳出 市价减仓不设止盈止损
|
||||
if preOrder.MainOrderType == "MARKET" {
|
||||
return
|
||||
}
|
||||
// if preOrder.MainOrderType == "MARKET" {
|
||||
// return
|
||||
// }
|
||||
|
||||
//亏损大于0 重新计算比例
|
||||
FutTakeProfit(db, preOrder, apiUserInfo, tradeSet, positionData, orderExt, decimal.Zero, decimal.Zero)
|
||||
@ -435,6 +435,8 @@ func removeFutLossAndAddPosition(mainId int, orderSn string) {
|
||||
stoploss := dto.StopLossRedisList{}
|
||||
addPosition := AddPositionList{}
|
||||
reduce := ReduceListItem{}
|
||||
//移除减仓后减仓策略
|
||||
RemoveReduceReduceCacheByMainId(mainId, 2)
|
||||
|
||||
//止损缓存
|
||||
for _, v := range stoplossVal {
|
||||
@ -598,7 +600,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd
|
||||
}
|
||||
}
|
||||
|
||||
processFutStopLossOrder(db, order, price, num)
|
||||
processFutStopLossOrder(db, order, utility.StrToDecimal(order.Price), num)
|
||||
// case 4: // 减仓
|
||||
// processFutReduceOrder(order, price, num)
|
||||
}
|
||||
@ -700,9 +702,13 @@ func updateOrderQuantity(db *gorm.DB, order models.LinePreOrder, preOrder *model
|
||||
// order.Num = num.String()
|
||||
// } else
|
||||
|
||||
if first && (order.OrderCategory == 1 || order.OrderCategory == 3) && order.OrderType == 1 && ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 {
|
||||
//止盈止损重算数量
|
||||
if first && (order.OrderCategory == 1 || order.OrderCategory == 3) && ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 {
|
||||
// 计算止盈数量
|
||||
num = num.Mul(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||
if order.OrderType == 1 {
|
||||
num = num.Mul(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||
}
|
||||
|
||||
order.Num = num.String()
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
package binanceservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go-admin/app/admin/models"
|
||||
DbModels "go-admin/app/admin/models"
|
||||
"go-admin/pkg/utility"
|
||||
"go-admin/pkg/utility/snowflakehelper"
|
||||
"time"
|
||||
|
||||
"github.com/go-admin-team/go-admin-core/logger"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@ -170,3 +175,68 @@ func GetChildTpOrder(db *gorm.DB, pid int) (int, error) {
|
||||
|
||||
return int(count), nil
|
||||
}
|
||||
|
||||
// 创建减仓后减仓单
|
||||
func CreateReduceReduceOrder(db *gorm.DB, pid int, price, num decimal.Decimal, amountDigit int) (models.LinePreOrder, error) {
|
||||
var preOrder models.LinePreOrder
|
||||
var result models.LinePreOrder
|
||||
var ext models.LinePreOrderExt
|
||||
|
||||
if err := db.Model(&models.LinePreOrder{}).Preload("Childs").Where("id =? ", pid).First(&preOrder).Error; err != nil {
|
||||
return preOrder, err
|
||||
}
|
||||
|
||||
if err := db.Model(&models.LinePreOrderExt{}).Where("order_id =? ", pid).Find(&ext).Error; err != nil {
|
||||
return preOrder, err
|
||||
}
|
||||
|
||||
copier.Copy(&result, &preOrder)
|
||||
|
||||
result.Id = 0
|
||||
result.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
result.Status = 0
|
||||
result.CreatedAt = time.Now()
|
||||
result.TriggerTime = nil
|
||||
result.UpdatedAt = time.Now()
|
||||
result.BuyPrice = decimal.Zero.String()
|
||||
result.Price = price.String()
|
||||
result.Num = num.String()
|
||||
|
||||
for index := range result.Childs {
|
||||
result.Childs[index].Id = 0
|
||||
result.Childs[index].OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
result.Childs[index].Status = 0
|
||||
result.Childs[index].CreatedAt = time.Now()
|
||||
result.Childs[index].TriggerTime = nil
|
||||
result.Childs[index].UpdatedAt = time.Now()
|
||||
result.Childs[index].BuyPrice = decimal.Zero.String()
|
||||
var pricePercent decimal.Decimal
|
||||
|
||||
if result.Childs[index].OrderType == 1 && ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 {
|
||||
// 减仓单卖出
|
||||
if preOrder.Site == "SELL" {
|
||||
pricePercent = decimal.NewFromInt(100).Add(ext.TakeProfitRatio).Div(decimal.NewFromInt(100))
|
||||
} else {
|
||||
pricePercent = decimal.NewFromInt(100).Sub(ext.TakeProfitRatio).Div(decimal.NewFromInt(100))
|
||||
}
|
||||
|
||||
} else if result.Childs[index].OrderType == 2 && ext.StopLossRatio.Cmp(decimal.Zero) > 0 {
|
||||
if preOrder.Site == "SELL" {
|
||||
pricePercent = decimal.NewFromInt(100).Sub(ext.StopLossRatio).Div(decimal.NewFromInt(100))
|
||||
} else {
|
||||
pricePercent = decimal.NewFromInt(100).Add(ext.StopLossRatio).Div(decimal.NewFromInt(100))
|
||||
}
|
||||
}
|
||||
|
||||
//重新计算止盈止损价
|
||||
if pricePercent.Cmp(decimal.Zero) > 0 {
|
||||
result.Childs[index].Price = price.Mul(pricePercent).Truncate(int32(amountDigit)).String()
|
||||
}
|
||||
}
|
||||
|
||||
if err := db.Create(&result).Error; err != nil {
|
||||
return result, fmt.Errorf("复制减仓单失败:pid:%d err:%v", pid, err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"go-admin/common/global"
|
||||
"go-admin/common/helper"
|
||||
models2 "go-admin/models"
|
||||
"go-admin/pkg/utility"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/go-admin-team/go-admin-core/logger"
|
||||
@ -19,7 +20,7 @@ import (
|
||||
// reduceOrder:原始减仓单
|
||||
// reduceOrderStrategy:减仓策略
|
||||
func CacheOrderStrategyAndReCreate(db *gorm.DB, reduceOrder ReduceListItem, symbolType int, tradeSet models2.TradeSet, setting models.LineSystemSetting) error {
|
||||
reduceOrderStrategy := models.LineReduceStrategy{}
|
||||
reduceOrderStrategy := models.LineOrderReduceStrategy{}
|
||||
var key string
|
||||
|
||||
if symbolType == 1 {
|
||||
@ -28,21 +29,27 @@ func CacheOrderStrategyAndReCreate(db *gorm.DB, reduceOrder ReduceListItem, symb
|
||||
key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||
}
|
||||
|
||||
if err := db.Model(&reduceOrderStrategy).Where("order_id =?", reduceOrder.Id).Find(reduceOrderStrategy).Error; err != nil {
|
||||
if err := db.Model(&reduceOrderStrategy).Where("order_id =?", reduceOrder.Id).Find(&reduceOrderStrategy).Error; err != nil {
|
||||
logger.Errorf("获取减仓策略失败,err:%v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if reduceOrderStrategy.Id > 0 {
|
||||
items := make([]models.LineReduceStrategyItem, 0)
|
||||
strategyCache := dto.LineOrderReduceStrategyResp{
|
||||
OrderId: reduceOrder.Id,
|
||||
Symbol: reduceOrder.Symbol,
|
||||
MainId: reduceOrder.MainId,
|
||||
Side: reduceOrder.Side,
|
||||
}
|
||||
|
||||
for _, item := range reduceOrderStrategy.Items {
|
||||
sonic.Unmarshal([]byte(reduceOrderStrategy.ItemContent), &items)
|
||||
|
||||
for _, item := range items {
|
||||
var rate decimal.Decimal
|
||||
var triggerRate decimal.Decimal
|
||||
|
||||
if reduceOrder.Side == "BUY" {
|
||||
if reduceOrder.Side == "SELL" {
|
||||
rate = (decimal.NewFromInt(100).Sub(item.LossPercent)).Div(decimal.NewFromInt(100))
|
||||
|
||||
if setting.ReduceEarlyTriggerPercent.Cmp(decimal.Zero) > 0 {
|
||||
@ -61,19 +68,26 @@ func CacheOrderStrategyAndReCreate(db *gorm.DB, reduceOrder ReduceListItem, symb
|
||||
}
|
||||
price := reduceOrder.Price.Mul(rate).Truncate(int32(tradeSet.PriceDigit))
|
||||
triggerPrice := reduceOrder.Price.Mul(triggerRate).Truncate(int32(tradeSet.PriceDigit))
|
||||
num := reduceOrder.Num
|
||||
|
||||
//百分比大于0就重新计算 否则就是主减仓单数量
|
||||
if item.QuantityPercent.Cmp(decimal.Zero) > 0 {
|
||||
num = reduceOrder.Num.Mul(item.QuantityPercent.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||
}
|
||||
|
||||
strategyCache.Items = append(strategyCache.Items, dto.LineOrderReduceStrategyRespItem{
|
||||
LossPercent: item.LossPercent,
|
||||
OrderType: item.OrderType,
|
||||
Price: price,
|
||||
TriggerPrice: triggerPrice,
|
||||
Num: num,
|
||||
})
|
||||
}
|
||||
|
||||
str, _ := sonic.MarshalString(reduceOrderStrategy)
|
||||
str, _ := sonic.MarshalString(strategyCache)
|
||||
|
||||
if str != "" {
|
||||
if err := helper.DefaultRedis.SetString(key, str); err != nil {
|
||||
if err := helper.DefaultRedis.HSetField(key, utility.IntToString(reduceOrder.Id), str); err != nil {
|
||||
logger.Errorf("减仓单缓存减仓策略,err:%v", err)
|
||||
}
|
||||
}
|
||||
@ -132,3 +146,33 @@ func ReduceCallBack(db *gorm.DB, preOrder *models.LinePreOrder) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 移除减仓后减仓策略
|
||||
// mainId 主单id
|
||||
// symbolType 交易对类型
|
||||
func RemoveReduceReduceCacheByMainId(mainId int, symbolType int) error {
|
||||
var key string
|
||||
switch symbolType {
|
||||
case 1:
|
||||
key = fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||
case 2:
|
||||
key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||
default:
|
||||
return fmt.Errorf("交易对类型错误")
|
||||
}
|
||||
|
||||
arrays, _ := helper.DefaultRedis.HGetAllFields(key)
|
||||
cache := dto.LineOrderReduceStrategyResp{}
|
||||
|
||||
for _, v := range arrays {
|
||||
sonic.Unmarshal([]byte(v), &cache)
|
||||
|
||||
if cache.MainId == mainId {
|
||||
if err := helper.DefaultRedis.HDelField(key, utility.IntToString(cache.OrderId)); err != nil {
|
||||
logger.Errorf("移除减仓单减仓策略失败redis err:%v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -266,23 +266,76 @@ func JudgeSpotReduce(trade models.TradeSet) {
|
||||
return
|
||||
}
|
||||
|
||||
reduceOrder := ReduceListItem{}
|
||||
tradePrice, _ := decimal.NewFromString(trade.LastPrice)
|
||||
//减仓单减仓策略
|
||||
orderReduceVal, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE))
|
||||
reduceReduceListKey := fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||
orderReduceVal, _ := helper.DefaultRedis.GetAllList(reduceReduceListKey)
|
||||
reduceOrderStrategy := dto.LineOrderReduceStrategyResp{}
|
||||
|
||||
for _, item := range orderReduceVal {
|
||||
sonic.Unmarshal([]byte(item), &reduceOrderStrategy)
|
||||
|
||||
for _, item2 := range reduceOrderStrategy.Items {
|
||||
for index, item2 := range reduceOrderStrategy.Items {
|
||||
if reduceOrderStrategy.Symbol == trade.Coin+trade.Currency {
|
||||
//买入
|
||||
if strings.ToUpper(reduceOrderStrategy.Side) == "SELL" &&
|
||||
item2.TriggerPrice.Cmp(tradePrice) >= 0 &&
|
||||
item2.TriggerPrice.Cmp(decimal.Zero) > 0 &&
|
||||
tradePrice.Cmp(decimal.Zero) > 0 {
|
||||
//todo 生成订单并触发
|
||||
// SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item)
|
||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.ReduceStrategySpotTriggerLock, reduceOrder.ApiId, reduceOrder.Symbol), 50, 15, 100*time.Millisecond)
|
||||
|
||||
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||
log.Error("获取锁失败", err)
|
||||
return
|
||||
} else if ok {
|
||||
defer lock.Release()
|
||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(reduceReduceListKey, item)
|
||||
|
||||
if !hasrecord {
|
||||
log.Debug("减仓缓存中不存在", item)
|
||||
return
|
||||
}
|
||||
|
||||
order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.AmountDigit)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("%d 生成订单失败", reduceOrderStrategy.OrderId)
|
||||
}
|
||||
|
||||
reduceOrder.ApiId = order.ApiId
|
||||
reduceOrder.Id = order.Id
|
||||
reduceOrder.Pid = order.Pid
|
||||
reduceOrder.MainId = order.MainId
|
||||
reduceOrder.Symbol = order.Symbol
|
||||
reduceOrder.Side = reduceOrderStrategy.Side
|
||||
reduceOrder.OrderSn = order.OrderSn
|
||||
reduceOrder.Price = item2.Price
|
||||
reduceOrder.Num = item2.Num
|
||||
if SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, true) {
|
||||
reduceOrderStrategy.Items[index].Actived = true
|
||||
allActive := true
|
||||
orderId := utility.IntToString(reduceOrderStrategy.OrderId)
|
||||
|
||||
for _, item3 := range reduceOrderStrategy.Items {
|
||||
if !item3.Actived {
|
||||
allActive = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if allActive {
|
||||
if err := helper.DefaultRedis.HDelField(reduceReduceListKey, orderId); err != nil {
|
||||
log.Errorf("删除redis reduceReduceListKey失败 %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
str, _ := sonic.MarshalString(reduceOrderStrategy)
|
||||
if err := helper.DefaultRedis.HSetField(reduceReduceListKey, orderId, str); err != nil {
|
||||
log.Errorf("更新redis reduceReduceListKey失败 %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -292,7 +345,6 @@ func JudgeSpotReduce(trade models.TradeSet) {
|
||||
reduceVal, _ := helper.DefaultRedis.GetAllList(key)
|
||||
|
||||
for _, item := range reduceVal {
|
||||
reduceOrder := ReduceListItem{}
|
||||
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
||||
log.Error("反序列化失败")
|
||||
continue
|
||||
@ -306,52 +358,53 @@ func JudgeSpotReduce(trade models.TradeSet) {
|
||||
orderPrice.Cmp(decimal.Zero) > 0 &&
|
||||
tradePrice.Cmp(decimal.Zero) > 0 {
|
||||
|
||||
SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item)
|
||||
SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 触发现货减仓
|
||||
func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string) {
|
||||
func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool) bool {
|
||||
tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 0)
|
||||
result := true
|
||||
|
||||
if err != nil {
|
||||
log.Error("获取交易设置失败")
|
||||
return
|
||||
return false
|
||||
}
|
||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, reduceOrder.ApiId, reduceOrder.Symbol), 20, 5, 100*time.Millisecond)
|
||||
|
||||
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||
log.Error("获取锁失败", err)
|
||||
return
|
||||
return false
|
||||
} else if ok {
|
||||
defer lock.Release()
|
||||
takeOrders := make([]DbModels.LinePreOrder, 0)
|
||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type =1 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 (1,2,4) AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
|
||||
log.Error("查询止盈单失败")
|
||||
return
|
||||
return false
|
||||
}
|
||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)
|
||||
|
||||
if !hasrecord {
|
||||
log.Debug("减仓缓存中不存在", item)
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
apiInfo, _ := GetApiInfo(reduceOrder.ApiId)
|
||||
|
||||
if apiInfo.Id == 0 {
|
||||
log.Error("现货减仓 查询api用户不存在")
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
for _, takeOrder := range takeOrders {
|
||||
err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn)
|
||||
|
||||
if err != nil {
|
||||
log.Error("现货止盈撤单失败", err)
|
||||
return
|
||||
log.Error("现货撤单失败", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
|
||||
@ -368,6 +421,7 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest
|
||||
}
|
||||
|
||||
if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
|
||||
result = false
|
||||
log.Errorf("现货减仓挂单失败 id:%s err:%v", reduceOrder.Id, err)
|
||||
|
||||
if err2 := db.Model(&DbModels.LinePreOrder{}).
|
||||
@ -387,15 +441,21 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest
|
||||
}
|
||||
|
||||
//处理减仓单减仓策略
|
||||
CacheOrderStrategyAndReCreate(db, reduceOrder, 1, tradeSet, setting)
|
||||
if err := CacheOrderStrategyAndReCreate(db, reduceOrder, 1, tradeSet, setting); err != nil {
|
||||
log.Errorf("现货减仓 处理减仓策略失败 id:%v err:%v", reduceOrder.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
|
||||
result = false
|
||||
log.Errorf("现货减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
|
||||
}
|
||||
} else {
|
||||
log.Error("获取锁失败")
|
||||
result = false
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 判断现货加仓
|
||||
|
||||
@ -550,6 +550,9 @@ func removeSpotLossAndAddPosition(mainId int, orderSn string) {
|
||||
addPosition := AddPositionList{}
|
||||
reduce := ReduceListItem{}
|
||||
|
||||
//移除减仓后减仓策略
|
||||
RemoveReduceReduceCacheByMainId(mainId, 1)
|
||||
|
||||
//止损缓存
|
||||
for _, v := range stoplossVal {
|
||||
sonic.Unmarshal([]byte(v), &stoploss)
|
||||
|
||||
Reference in New Issue
Block a user