1、减仓策略
2、减仓后减仓节点(60%)
This commit is contained in:
232
services/binanceservice/strategy_order_service.go
Normal file
232
services/binanceservice/strategy_order_service.go
Normal file
@ -0,0 +1,232 @@
|
||||
package binanceservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go-admin/app/admin/models"
|
||||
"go-admin/app/admin/service/dto"
|
||||
"go-admin/common/const/rediskey"
|
||||
"go-admin/common/global"
|
||||
"go-admin/common/helper"
|
||||
models2 "go-admin/models"
|
||||
"go-admin/pkg/utility"
|
||||
"go-admin/services/cacheservice"
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
type BinanceStrategyOrderService struct {
|
||||
service.Service
|
||||
}
|
||||
|
||||
// 判断是否触发波段订单
|
||||
func (e *BinanceStrategyOrderService) TriggerStrategyOrder(exchangeType string) {
|
||||
//现货
|
||||
orderStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType))
|
||||
e.DoJudge(orderStrs, 1, exchangeType)
|
||||
|
||||
//合约
|
||||
futOrdedrStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType))
|
||||
e.DoJudge(futOrdedrStrs, 2, exchangeType)
|
||||
}
|
||||
|
||||
// 处理订单
|
||||
func (e *BinanceStrategyOrderService) DoJudge(orderStrs []string, symbolType int, exchangeType string) {
|
||||
for _, orderStr := range orderStrs {
|
||||
var lockKey string
|
||||
orderItem := dto.StrategyOrderRedisList{}
|
||||
err := sonic.Unmarshal([]byte(orderStr), &orderItem)
|
||||
|
||||
if err != nil || orderItem.Symbol == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if symbolType == 1 {
|
||||
lockKey = rediskey.StrategySpotTriggerLock
|
||||
} else {
|
||||
lockKey = rediskey.StrategyFutTriggerLock
|
||||
}
|
||||
|
||||
lock := helper.NewRedisLock(fmt.Sprintf(lockKey, orderItem.ApiId, orderItem.Symbol), 200, 50, 100*time.Millisecond)
|
||||
|
||||
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||
e.Log.Debug("获取锁失败", err)
|
||||
return
|
||||
} else if ok {
|
||||
defer lock.Release()
|
||||
|
||||
//判断是否符合条件
|
||||
success, err := e.JudgeStrategy(orderItem, 1, exchangeType)
|
||||
|
||||
if err != nil {
|
||||
e.Log.Errorf("order_id:%d err:%v", orderItem.Id, err)
|
||||
}
|
||||
|
||||
if success {
|
||||
e.TriggerOrder(orderItem, symbolType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否符合触发条件
|
||||
func (e *BinanceStrategyOrderService) JudgeStrategy(order dto.StrategyOrderRedisList, symbolType int, exchangeType string) (bool, error) {
|
||||
var symbolKey string
|
||||
result := false
|
||||
nowUtc := time.Now().UnixMilli()
|
||||
|
||||
switch symbolType {
|
||||
case 1:
|
||||
symbolKey = fmt.Sprintf(rediskey.SpotTickerLastPrice, exchangeType, order.Symbol)
|
||||
case 2:
|
||||
symbolKey = fmt.Sprintf(rediskey.FutureTickerLastPrice, exchangeType, order.Symbol)
|
||||
}
|
||||
|
||||
lastUtc := nowUtc - (int64(order.TimeSlotStart) * 60 * 1000)
|
||||
beforePrice, _ := helper.DefaultRedis.GetNextAfterScore(symbolKey, float64(lastUtc))
|
||||
lastPrices, _ := helper.DefaultRedis.GetLastSortSet(symbolKey)
|
||||
|
||||
if beforePrice == "" || len(lastPrices) == 0 {
|
||||
return result, errors.New("获取交易对起止价格失败")
|
||||
}
|
||||
|
||||
score := lastPrices[0].Score
|
||||
startPrice := utility.StrToDecimal(beforePrice)
|
||||
lastPrice := utility.StrToDecimal(lastPrices[0].Member.(string))
|
||||
|
||||
//时间差超过10s
|
||||
if (nowUtc-int64(score))/1000 > 10 {
|
||||
return result, fmt.Errorf("时间差超过 %ss", "10")
|
||||
}
|
||||
|
||||
if startPrice.Cmp(decimal.Zero) == 0 || lastPrice.Cmp(decimal.Zero) == 0 {
|
||||
return result, errors.New("获取交易对起止价格有一个为0")
|
||||
}
|
||||
|
||||
percentag := lastPrice.Div(startPrice).Sub(decimal.NewFromInt(1)).Truncate(6)
|
||||
|
||||
//价格没有变动
|
||||
if percentag.Cmp(decimal.Zero) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
//满足条件
|
||||
switch order.CompareType {
|
||||
case 1:
|
||||
result = percentag.Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) > 0
|
||||
case 2:
|
||||
result = percentag.Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) >= 0
|
||||
case 5:
|
||||
result = percentag.Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) == 0
|
||||
default:
|
||||
return result, errors.New("没有对应的类型")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 触发委托单
|
||||
func (e *BinanceStrategyOrderService) TriggerOrder(order dto.StrategyOrderRedisList, symbolType int) error {
|
||||
orders := make([]models.LinePreOrder, 0)
|
||||
if err := e.Orm.Model(&models.LinePreOrder{}).Where("main_id =?", order.Id).Find(&orders).Error; err != nil {
|
||||
e.Log.Errorf("order_id:%d 获取委托单失败:%s", order.Id, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
setting, _ := cacheservice.GetSystemSetting(e.Orm)
|
||||
|
||||
if setting.Id == 0 {
|
||||
return errors.New("获取系统设置失败")
|
||||
}
|
||||
|
||||
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, symbolType)
|
||||
|
||||
if tradeSet.Coin == "" {
|
||||
return errors.New("获取交易对行情失败")
|
||||
}
|
||||
|
||||
lastPrice := utility.StrToDecimal(tradeSet.LastPrice)
|
||||
|
||||
if lastPrice.Cmp(decimal.Zero) <= 0 {
|
||||
return errors.New("最新成交价小于等于0")
|
||||
}
|
||||
|
||||
var mainOrder models.LinePreOrder
|
||||
|
||||
for _, v := range orders {
|
||||
if v.MainId == 0 {
|
||||
mainOrder = v
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
GetOrderByPid(&mainOrder, orders, mainOrder.Id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 重新计算订单单价、数量
|
||||
// tradeSet 交易对行情
|
||||
// mainOrder 主订单
|
||||
// setting 系统设置
|
||||
func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet, mainOrder *models.LinePreOrder, setting models.LineSystemSetting) error {
|
||||
exts := make([]models.LinePreOrderExt, 0)
|
||||
if err := e.Orm.Model(models.LinePreOrderExt{}).Where("main_id =?", mainOrder.Id).Find(&exts).Error; err != nil {
|
||||
return errors.New("获取拓展信息失败")
|
||||
}
|
||||
|
||||
lastPrice := utility.StrToDecimal(tradeSet.LastPrice)
|
||||
rate := utility.StrToDecimal(mainOrder.Rate)
|
||||
newPrice := lastPrice.Mul(decimal.NewFromInt(1).Add(rate.Div(decimal.NewFromInt(100)).Truncate(4))).Truncate(int32(tradeSet.PriceDigit))
|
||||
buyPrice := utility.StrToDecimal(mainOrder.BuyPrice)
|
||||
totalNum := buyPrice.Div(newPrice).Truncate(int32(tradeSet.AmountDigit))
|
||||
|
||||
mainOrder.SignPrice = lastPrice.String()
|
||||
mainOrder.Price = newPrice.String()
|
||||
mainOrder.Num = totalNum.String()
|
||||
|
||||
for index := range mainOrder.Childs {
|
||||
//主单止盈
|
||||
if mainOrder.Child[index].OrderType == 1 {
|
||||
var ext models.LinePreOrderExt
|
||||
|
||||
for _, v := range exts {
|
||||
if v.OrderId == mainOrder.Child[index].Id {
|
||||
ext = v
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ext.Id > 0 {
|
||||
var percent decimal.Decimal
|
||||
//多
|
||||
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 {
|
||||
//todo 重新计算
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 递归订单树
|
||||
func GetOrderByPid(order *models.LinePreOrder, orders []models.LinePreOrder, pid int) {
|
||||
for _, v := range orders {
|
||||
if v.Pid == pid {
|
||||
GetOrderByPid(&v, orders, v.Id)
|
||||
|
||||
order.Childs = append(order.Childs, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user