1、减仓后减仓
This commit is contained in:
@ -65,6 +65,7 @@ type LineSystemSettingUpdateReq struct {
|
||||
StopLossPremium decimal.Decimal `json:"stopLossPremium" comment:"限价止损溢价"`
|
||||
AddPositionPremium decimal.Decimal `json:"addPositionPremium" comment:"限价加仓溢价"`
|
||||
ReducePremium decimal.Decimal `json:"reducePremium" comment:"限价减仓溢价"`
|
||||
ReduceEarlyTriggerPercent decimal.Decimal `json:"reduceEarlyTriggerPercent" comment:"减仓提前触发百分比"`
|
||||
common.ControlBy
|
||||
}
|
||||
|
||||
@ -79,6 +80,7 @@ func (s *LineSystemSettingUpdateReq) Generate(model *models.LineSystemSetting) {
|
||||
model.StopLossPremium = s.StopLossPremium
|
||||
model.AddPositionPremium = s.AddPositionPremium
|
||||
model.ReducePremium = s.ReducePremium
|
||||
model.ReduceEarlyTriggerPercent = s.ReduceEarlyTriggerPercent
|
||||
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||
}
|
||||
|
||||
|
||||
@ -573,6 +573,33 @@ func (r *RedisHelper) HKeys(key string) ([]string, error) {
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func (r *RedisHelper) HExists(key, field, value string) (bool, error) {
|
||||
exists, err := r.client.HExists(r.ctx, key, field).Result()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("check existence failed: %v", err)
|
||||
}
|
||||
if !exists {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
storedValue, err := r.client.HGet(r.ctx, key, field).Result()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("get value failed: %v", err)
|
||||
}
|
||||
|
||||
// 如果值是 JSON,比较前反序列化
|
||||
var storedObj, inputObj interface{}
|
||||
if err := sonic.UnmarshalString(storedValue, &storedObj); err != nil {
|
||||
return false, fmt.Errorf("unmarshal stored value failed: %v", err)
|
||||
}
|
||||
if err := sonic.UnmarshalString(value, &inputObj); err != nil {
|
||||
return false, fmt.Errorf("unmarshal input value failed: %v", err)
|
||||
}
|
||||
|
||||
// 比较两个对象(需要根据实际类型调整)
|
||||
return fmt.Sprintf("%v", storedObj) == fmt.Sprintf("%v", inputObj), nil
|
||||
}
|
||||
|
||||
// DelSet 从集合中删除元素
|
||||
func (r *RedisHelper) DelSet(key string, value string) error {
|
||||
_, err := r.client.SRem(r.ctx, key, value).Result()
|
||||
|
||||
@ -28,7 +28,7 @@ func TestFutureJudge(t *testing.T) {
|
||||
// }
|
||||
|
||||
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"}`
|
||||
item := `{"id":50,"apiId":49,"mainId":47,"pid":47,"symbol":"ADAUSDT","price":"0.5936","side":"SELL","num":"12","orderSn":"397913127842217984"}`
|
||||
reduceOrder := ReduceListItem{}
|
||||
futApi := FutRestApi{}
|
||||
setting, err := cacheservice.GetSystemSetting(db)
|
||||
@ -42,7 +42,7 @@ func TestFutureJudge(t *testing.T) {
|
||||
return
|
||||
}
|
||||
// JudgeFuturesReduce(tradeSet)
|
||||
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false)
|
||||
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false, 0)
|
||||
}
|
||||
|
||||
// 测试减仓后减仓触发
|
||||
@ -55,7 +55,8 @@ func TestFutureReduceReduce(t *testing.T) {
|
||||
tradeSet := models.TradeSet{
|
||||
Coin: "ADA",
|
||||
Currency: "USDT",
|
||||
LastPrice: "0.5307",
|
||||
LastPrice: "0.5817",
|
||||
PriceDigit: 4,
|
||||
}
|
||||
|
||||
// JudgeFuturesReduce(tradeSet)
|
||||
|
||||
@ -186,14 +186,14 @@ func JudgeFuturesReduce(trade models.TradeSet) {
|
||||
return
|
||||
} else if ok {
|
||||
defer lock.Release()
|
||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(reduceReduceListKey, item)
|
||||
hasrecord, _ := helper.DefaultRedis.HExists(reduceReduceListKey, utility.IntToString(reduceOrderStrategy.OrderId), item)
|
||||
|
||||
if !hasrecord {
|
||||
log.Debug("减仓缓存中不存在", item)
|
||||
return
|
||||
}
|
||||
|
||||
order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.AmountDigit)
|
||||
order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.PriceDigit)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("%d 生成订单失败", reduceOrderStrategy.OrderId)
|
||||
@ -209,7 +209,7 @@ func JudgeFuturesReduce(trade models.TradeSet) {
|
||||
reduceOrder.Price = item2.Price
|
||||
reduceOrder.Num = item2.Num
|
||||
//下单成功修改策略节点状态
|
||||
if FuturesReduceTrigger(db, reduceOrder, futApi, setting, reduceReduceListKey, item, true) {
|
||||
if FuturesReduceTrigger(db, reduceOrder, futApi, setting, reduceReduceListKey, item, true, reduceOrderStrategy.OrderId) {
|
||||
reduceOrderStrategy.Items[index].Actived = true
|
||||
allActive := true
|
||||
orderId := utility.IntToString(reduceOrderStrategy.OrderId)
|
||||
@ -252,7 +252,7 @@ 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, false)
|
||||
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,7 +260,8 @@ func JudgeFuturesReduce(trade models.TradeSet) {
|
||||
|
||||
// 触发合约减仓
|
||||
// isStrategy 是否是策略减仓
|
||||
func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool) bool {
|
||||
// reduceId 父减仓单id
|
||||
func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool, reduceId int) bool {
|
||||
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 1)
|
||||
result := true
|
||||
|
||||
@ -281,7 +282,13 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes
|
||||
return false
|
||||
}
|
||||
|
||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)
|
||||
var hasrecord bool
|
||||
|
||||
if isStrategy {
|
||||
hasrecord, _ = helper.DefaultRedis.HExists(key, utility.IntToString(reduceId), item)
|
||||
} else {
|
||||
hasrecord, _ = helper.DefaultRedis.IsElementInList(key, item)
|
||||
}
|
||||
|
||||
if !hasrecord {
|
||||
log.Debug("减仓缓存中不存在", item)
|
||||
|
||||
@ -137,7 +137,12 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
//修改减仓单减仓策略状态
|
||||
ReduceCallBack(db, preOrder)
|
||||
orderExt := models.LinePreOrderExt{}
|
||||
//减仓策略单获取主减仓单的拓展信息
|
||||
if preOrder.ReduceOrderId > 0 {
|
||||
db.Model(&orderExt).Where("order_id =?", preOrder.ReduceOrderId).First(&orderExt)
|
||||
} else {
|
||||
db.Model(&orderExt).Where("order_id =?", preOrder.Id).First(&orderExt)
|
||||
}
|
||||
// rate := utility.StringAsFloat(orderExt.AddPositionVal)
|
||||
|
||||
// 100%减仓 终止流程
|
||||
@ -248,7 +253,7 @@ func nextFuturesReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal,
|
||||
nextOrder := DbModels.LinePreOrder{}
|
||||
nextExt := DbModels.LinePreOrderExt{}
|
||||
|
||||
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
||||
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0 AND reduce_order_id=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
||||
logger.Errorf("获取下一个单失败 err:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ func GetChildTpOrder(db *gorm.DB, pid int) (int, error) {
|
||||
}
|
||||
|
||||
// 创建减仓后减仓单
|
||||
func CreateReduceReduceOrder(db *gorm.DB, pid int, price, num decimal.Decimal, amountDigit int) (models.LinePreOrder, error) {
|
||||
func CreateReduceReduceOrder(db *gorm.DB, pid int, price, num decimal.Decimal, priceDigit int) (models.LinePreOrder, error) {
|
||||
var preOrder models.LinePreOrder
|
||||
var result models.LinePreOrder
|
||||
var ext models.LinePreOrderExt
|
||||
@ -201,6 +201,7 @@ func CreateReduceReduceOrder(db *gorm.DB, pid int, price, num decimal.Decimal, a
|
||||
result.BuyPrice = decimal.Zero.String()
|
||||
result.Price = price.String()
|
||||
result.Num = num.String()
|
||||
result.ReduceOrderId = preOrder.Id
|
||||
|
||||
for index := range result.Childs {
|
||||
result.Childs[index].Id = 0
|
||||
@ -230,7 +231,7 @@ func CreateReduceReduceOrder(db *gorm.DB, pid int, price, num decimal.Decimal, a
|
||||
|
||||
//重新计算止盈止损价
|
||||
if pricePercent.Cmp(decimal.Zero) > 0 {
|
||||
result.Childs[index].Price = price.Mul(pricePercent).Truncate(int32(amountDigit)).String()
|
||||
result.Childs[index].Price = price.Mul(pricePercent).Truncate(int32(priceDigit)).String()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -124,14 +124,14 @@ func ReduceCallBack(db *gorm.DB, preOrder *models.LinePreOrder) error {
|
||||
return fmt.Errorf("交易对类型错误")
|
||||
}
|
||||
|
||||
arrays, _ := helper.DefaultRedis.GetAllList(key)
|
||||
arrays, _ := helper.DefaultRedis.HGetAllFields(key)
|
||||
cache := dto.LineOrderReduceStrategyResp{}
|
||||
|
||||
for _, v := range arrays {
|
||||
sonic.Unmarshal([]byte(v), &cache)
|
||||
|
||||
if cache.OrderId == reduceOrderId {
|
||||
if _, err := helper.DefaultRedis.LRem(key, v); err != nil {
|
||||
if err := helper.DefaultRedis.HDelField(key, utility.IntToString(cache.OrderId)); err != nil {
|
||||
logger.Errorf("移除减仓单减仓策略失败redis err:%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
64
services/binanceservice/spot_judge_service_test.go
Normal file
64
services/binanceservice/spot_judge_service_test.go
Normal file
@ -0,0 +1,64 @@
|
||||
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 TestSpotJudge(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.SpotReduceList, global.EXCHANGE_BINANCE)
|
||||
item := `{"id":66,"apiId":49,"mainId":63,"pid":63,"symbol":"ADAUSDT","price":"0.5912","side":"SELL","num":"12.6","orderSn":"397919643961917440"}`
|
||||
reduceOrder := ReduceListItem{}
|
||||
spotApi := SpotRestApi{}
|
||||
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)
|
||||
SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, false, 0)
|
||||
}
|
||||
|
||||
// 测试减仓后减仓触发
|
||||
func TestSpotReduceReduce(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.5793",
|
||||
PriceDigit: 4,
|
||||
}
|
||||
|
||||
// JudgeFuturesReduce(tradeSet)
|
||||
JudgeSpotReduce(tradeSet)
|
||||
}
|
||||
@ -270,7 +270,7 @@ func JudgeSpotReduce(trade models.TradeSet) {
|
||||
tradePrice, _ := decimal.NewFromString(trade.LastPrice)
|
||||
//减仓单减仓策略
|
||||
reduceReduceListKey := fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||
orderReduceVal, _ := helper.DefaultRedis.GetAllList(reduceReduceListKey)
|
||||
orderReduceVal, _ := helper.DefaultRedis.HGetAllFields(reduceReduceListKey)
|
||||
reduceOrderStrategy := dto.LineOrderReduceStrategyResp{}
|
||||
|
||||
for _, item := range orderReduceVal {
|
||||
@ -290,14 +290,14 @@ func JudgeSpotReduce(trade models.TradeSet) {
|
||||
return
|
||||
} else if ok {
|
||||
defer lock.Release()
|
||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(reduceReduceListKey, item)
|
||||
hasrecord, _ := helper.DefaultRedis.HExists(reduceReduceListKey, utility.IntTostring(reduceOrderStrategy.OrderId), item)
|
||||
|
||||
if !hasrecord {
|
||||
log.Debug("减仓缓存中不存在", item)
|
||||
return
|
||||
}
|
||||
|
||||
order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.AmountDigit)
|
||||
order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.PriceDigit)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("%d 生成订单失败", reduceOrderStrategy.OrderId)
|
||||
@ -312,7 +312,7 @@ func JudgeSpotReduce(trade models.TradeSet) {
|
||||
reduceOrder.OrderSn = order.OrderSn
|
||||
reduceOrder.Price = item2.Price
|
||||
reduceOrder.Num = item2.Num
|
||||
if SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, true) {
|
||||
if SpotReduceTrigger(db, reduceOrder, spotApi, setting, reduceReduceListKey, item, true, reduceOrderStrategy.OrderId) {
|
||||
reduceOrderStrategy.Items[index].Actived = true
|
||||
allActive := true
|
||||
orderId := utility.IntToString(reduceOrderStrategy.OrderId)
|
||||
@ -358,14 +358,16 @@ func JudgeSpotReduce(trade models.TradeSet) {
|
||||
orderPrice.Cmp(decimal.Zero) > 0 &&
|
||||
tradePrice.Cmp(decimal.Zero) > 0 {
|
||||
|
||||
SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, false)
|
||||
SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, false, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 触发现货减仓
|
||||
func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool) bool {
|
||||
// isStrategy 是否是策略减仓单
|
||||
// reduceId 策略主减仓单id
|
||||
func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool, reduceId int) bool {
|
||||
tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 0)
|
||||
result := true
|
||||
|
||||
@ -385,7 +387,13 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest
|
||||
log.Error("查询止盈单失败")
|
||||
return false
|
||||
}
|
||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)
|
||||
var hasrecord bool
|
||||
|
||||
if isStrategy {
|
||||
hasrecord, _ = helper.DefaultRedis.HExists(key, utility.IntToString(reduceId), item)
|
||||
} else {
|
||||
hasrecord, _ = helper.DefaultRedis.IsElementInList(key, item)
|
||||
}
|
||||
|
||||
if !hasrecord {
|
||||
log.Debug("减仓缓存中不存在", item)
|
||||
|
||||
@ -182,7 +182,13 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id =? ", preOrder.MainId).Update("reduce_status", 1).Error; err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 更新主单减仓状态失败,订单号:%s", preOrder.OrderSn)
|
||||
}
|
||||
|
||||
//策略减仓单 获取主减仓单拓展信息
|
||||
if preOrder.ReduceOrderId > 0 {
|
||||
db.Model(&orderExt).Where("order_id =?", preOrder.ReduceOrderId).Find(&orderExt)
|
||||
} else {
|
||||
db.Model(&orderExt).Where("order_id =?", preOrder.Id).Find(&orderExt)
|
||||
}
|
||||
|
||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotReduceCallback, preOrder.ApiId, preOrder.Symbol), 120, 20, 100*time.Millisecond)
|
||||
|
||||
@ -282,7 +288,7 @@ func nextSpotReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tr
|
||||
nextExt := DbModels.LinePreOrderExt{}
|
||||
// var percentag decimal.Decimal
|
||||
|
||||
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
||||
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0 AND reduce_order_id =0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
||||
logger.Errorf("获取下一个单失败 err:%v", err)
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user