diff --git a/app/admin/service/dto/line_pre_order.go b/app/admin/service/dto/line_pre_order.go index 5952222..b1317e2 100644 --- a/app/admin/service/dto/line_pre_order.go +++ b/app/admin/service/dto/line_pre_order.go @@ -295,7 +295,7 @@ func (req LineAddPreOrderReq) Valid() error { return errors.New("主单减仓数量百分比不能为空") } - if req.ReducePriceRatio.IsZero() || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0 { + if req.PricePattern != "mixture" && (req.ReducePriceRatio.IsZero() || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0) { return errors.New("主单减仓价格百分比错误") } @@ -447,7 +447,7 @@ func (req LineBatchAddPreOrderReq) CheckParams() error { return errors.New("主单减仓数量百分比不能为空") } - if req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0 { + if req.PricePattern != "mixture" && (req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0) { return errors.New("主单减仓价格百分比错误") } diff --git a/app/admin/service/line_pre_order.go b/app/admin/service/line_pre_order.go index 8b49be6..2d2d859 100644 --- a/app/admin/service/line_pre_order.go +++ b/app/admin/service/line_pre_order.go @@ -592,6 +592,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int preOrderStatus := models.LinePreOrderStatus{} preOrderStatus.OrderSn = AddOrder.OrderSn + mainPrice := utility.StringToDecimal(AddOrder.Price) //订单配置信息 preOrderExts := make([]models.LinePreOrderExt, 0) @@ -606,6 +607,12 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int TpTpPriceRatio: req.ProfitTpTpPriceRatio, TpSlPriceRatio: req.ProfitTpSlPriceRatio, } + + if req.PricePattern == "mixture" { + defultExt.TakeProfitRatio = mainPrice.Div(utility.StrToDecimal(req.Profit)).Sub(decimal.NewFromInt(1)).Abs().Mul(decimal.NewFromInt(100)).Truncate(2) + defultExt.StopLossRatio = mainPrice.Div(req.StopLoss).Sub(decimal.NewFromInt(1)).Abs().Mul(decimal.NewFromInt(100)).Truncate(2) + } + //减仓单 defultExt2 := models.LinePreOrderExt{ AddType: 2, @@ -617,17 +624,12 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int TakeProfitNumRatio: decimal.NewFromInt(100), //减仓止盈默认100% StopLossRatio: req.ReduceStopLossRatio, } - mainPrice := utility.StringToDecimal(AddOrder.Price) mainAmount := utility.SafeDiv(buyPrice, mainPrice) defultExt.TotalAfter = utility.StrToDecimal(AddOrder.Num).Truncate(int32(tradeSet.AmountDigit)) defultExt2.TotalBefore = defultExt.TotalAfter default2NumPercent := utility.SafeDiv(decimal.NewFromInt(100).Sub(req.ReduceNumRatio), decimal.NewFromInt(100)) defultExt2.TotalAfter = mainAmount.Mul(default2NumPercent).Truncate(int32(tradeSet.AmountDigit)) - defultExt2.ReTakeRatio = utility.SafeDiv(req.ReducePriceRatio, default2NumPercent).Truncate(2) - - preOrderExts = append(preOrderExts, defultExt) - preOrderExts = append(preOrderExts, defultExt2) calculateResp := dto.CalculateBreakEvenRatioResp{} mainParam := dto.CalculateBreakEevenRatioReq{ @@ -643,15 +645,22 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int AddPositionVal: req.ReduceNumRatio, } + if req.PricePattern == "mixture" { + mainParam.LossEndPercent = mainPrice.Div(req.ReducePriceRatio).Sub(decimal.NewFromInt(1)).Abs().Mul(decimal.NewFromInt(100)).Truncate(2) + defultExt2.PriceRatio = mainParam.LossEndPercent + } + //计算减仓后 - mainParam.LossEndPercent = req.ReducePriceRatio + defultExt2.ReTakeRatio = utility.SafeDiv(mainParam.LossEndPercent, default2NumPercent).Truncate(2) mainParam.RemainingQuantity = mainAmount e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet) mainParam.RemainingQuantity = calculateResp.RemainingQuantity //mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU //buyPrice.Mul(req.ReducePriceRatio.Div(decimal.NewFromInt(100)).Truncate(4)).Truncate(int32(tradeSet.PriceDigit)) req.ReduceReTakeProfitRatio = calculateResp.Ratio - mainParam.LossBeginPercent = req.ReducePriceRatio + mainParam.LossBeginPercent = mainParam.LossEndPercent // defultExt.ReTakeRatio = calculateResp.Ratio + preOrderExts = append(preOrderExts, defultExt) + preOrderExts = append(preOrderExts, defultExt2) for index, addPosition := range req.Ext { ext := models.LinePreOrderExt{ @@ -1069,6 +1078,8 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO mainId = preOrder.MainId } + fmt.Println("take", ext.TakeProfitRatio.String()) + fmt.Println("boo", ext.TakeProfitRatio.Cmp(decimal.Zero)) if ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 { // 止盈单 profitOrder := models.LinePreOrder{} @@ -2237,15 +2248,18 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error { AddPositionVal: req.ReduceNumRatio, } + if req.PricePattern == "mixture" { + mainParam.LossEndPercent = price.Div(req.ReducePriceRatio).Sub(decimal.NewFromInt(1)).Abs().Mul(decimal.NewFromInt(100)).Truncate(2) + } + //计算减仓后 - mainParam.LossEndPercent = req.ReducePriceRatio mainParam.RemainingQuantity = mainAmount mainParam.AddType = 2 e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet) mainParam.RemainingQuantity = calculateResp.RemainingQuantity mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU req.ReduceReTakeProfitRatio = calculateResp.Ratio - lossBeginPercent = req.ReducePriceRatio + lossBeginPercent = mainParam.LossEndPercent //顺序排序 sort.Slice(req.Ext, func(i, j int) bool { diff --git a/app/jobs/account_job.go b/app/jobs/account_job.go new file mode 100644 index 0000000..36deba4 --- /dev/null +++ b/app/jobs/account_job.go @@ -0,0 +1,67 @@ +package jobs + +import ( + binancedto "go-admin/models/binancedto" + "go-admin/services/binanceservice" + + DbModels "go-admin/app/admin/models" + + "github.com/go-admin-team/go-admin-core/logger" + "github.com/shopspring/decimal" +) + +type BinanceSpotAccountJob struct{} + +type BinanceFuturesAccountJob struct{} + +// 币安账户划转 +func (t BinanceSpotAccountJob) Exec(arg interface{}) error { + db := getDefaultDb() + req := binancedto.BinanceTransfer{ + Type: "MAIN_UMFUTURE", + Asset: "USDT", + Amount: decimal.NewFromFloat(0.1), + FromSymbol: "USDT", + ToSymbol: "USDT", + } + var apis []DbModels.LineApiUser + + if err := db.Model(&DbModels.LineApiUser{}).Where("open_status = 1").Find(&apis).Error; err != nil { + return err + } + + for _, apiUserInfo := range apis { + err := binanceservice.TradeAmount(db, &req, apiUserInfo) + + if err != nil { + logger.Errorf("现货划转合约失败, err: %s", err) + } + } + return nil +} + +// 币安账户划转 +func (t BinanceFuturesAccountJob) Exec(arg interface{}) error { + db := getDefaultDb() + req := binancedto.BinanceTransfer{ + Type: "UMFUTURE_MAIN", + Asset: "USDT", + Amount: decimal.NewFromFloat(0.1), + FromSymbol: "USDT", + ToSymbol: "USDT", + } + var apis []DbModels.LineApiUser + if err := db.Model(&DbModels.LineApiUser{}).Where("open_status = 1").Find(&apis).Error; err != nil { + return err + } + + for _, apiUserInfo := range apis { + err := binanceservice.TradeAmount(db, &req, apiUserInfo) + + if err != nil { + logger.Errorf("合约划转现货失败, err: %s", err) + } + } + + return nil +} diff --git a/app/jobs/account_job_test.go b/app/jobs/account_job_test.go new file mode 100644 index 0000000..4e894a3 --- /dev/null +++ b/app/jobs/account_job_test.go @@ -0,0 +1,34 @@ +package jobs + +import ( + "go-admin/common/helper" + "testing" + + "github.com/go-admin-team/go-admin-core/sdk" + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +func TestAccountJob(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") + + accountJob := BinanceSpotAccountJob{} + accountJob.Exec(nil) +} + +func TestFutureAccountJob(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") + + accountJob := BinanceFuturesAccountJob{} + accountJob.Exec(nil) +} diff --git a/app/jobs/examples.go b/app/jobs/examples.go index a2a78b3..2aa5a5d 100644 --- a/app/jobs/examples.go +++ b/app/jobs/examples.go @@ -39,6 +39,8 @@ func InitJob() { "MemberRenwalOrderExpirationJob": MemberRenwalOrderExpirationJob{}, //会员续费订单过期处理 "TrxQueryJobs": TrxQueryJobs{}, //订单支付监听 "StrategyJob": StrategyJob{}, //下单策略触发 + "BinanceSpotAccountJob": BinanceSpotAccountJob{}, //币安现货划转 + "BinanceFuturesAccountJob": BinanceFuturesAccountJob{}, //币安合约划转 } } diff --git a/models/binancedto/account.go b/models/binancedto/account.go new file mode 100644 index 0000000..58648fb --- /dev/null +++ b/models/binancedto/account.go @@ -0,0 +1,11 @@ +package binancedto + +import "github.com/shopspring/decimal" + +type BinanceTransfer struct { + Type string `json:"type" content:"枚举 MAIN_UMFUTURE-现货到u合约"` + Asset string `json:"asset" content:"币种"` + Amount decimal.Decimal `json:"amount" content:"数量"` + FromSymbol string `json:"fromSymbol" content:"转出币种"` + ToSymbol string `json:"toSymbol" content:"转入币种"` +} diff --git a/services/binanceservice/binancerest.go b/services/binanceservice/binancerest.go index d833ae9..e267568 100644 --- a/services/binanceservice/binancerest.go +++ b/services/binanceservice/binancerest.go @@ -640,3 +640,43 @@ func GetSpotUProperty(apiUserInfo DbModels.LineApiUser, data *dto.LineUserProper return nil } + +// 万象划转 +func TradeAmount(db *gorm.DB, req *binancedto.BinanceTransfer, apiUserInfo DbModels.LineApiUser) error { + url := "/sapi/v1/asset/transfer" + + client := GetClient(&apiUserInfo) + + params := map[string]string{ + "type": req.Type, + "asset": req.Asset, + "amount": req.Amount.String(), + "fromSymbol": req.FromSymbol, + "toSymbol": req.ToSymbol, + "recvWindow": "10000", + } + + _, code, err := client.SendSpotAuth(url, "POST", params) + if err != nil || code != 200 { + log.Error("万向划转失败 参数:", params) + log.Error("万向划转失败 code:", code) + log.Error("万向划转失败 err:", err) + dataMap := make(map[string]interface{}) + if err.Error() != "" { + if err := sonic.Unmarshal([]byte(err.Error()), &dataMap); err != nil { + return fmt.Errorf("api_id:%d 万向划转失败:%+v", apiUserInfo.Id, err.Error()) + } + } + + code, ok := dataMap["code"] + if ok { + return fmt.Errorf("api_id:%d 万向划转失败:%s", apiUserInfo.Id, ErrorMaps[code.(float64)]) + } + if strings.Contains(err.Error(), "Unknown order sent.") { + return fmt.Errorf("api_id:%d 万向划转失败:%+v", apiUserInfo.Id, ErrorMaps[-2011]) + } + return fmt.Errorf("api_id:%d 万向划转失败:%+v", apiUserInfo.Id, err.Error()) + } + + return nil +}