1、波段触发修改
This commit is contained in:
		| @ -14,7 +14,7 @@ type LineStrategyTemplate struct { | ||||
| 	Percentag     decimal.Decimal `json:"percentag" gorm:"type:decimal(10,2);comment:涨跌点数"` | ||||
| 	CompareType   int             `json:"compareType" gorm:"type:tinyint;comment:比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "` | ||||
| 	TimeSlotStart int             `json:"timeSlotStart" gorm:"type:int;comment:时间段开始(分)"` | ||||
| 	TimeSlotEnd   int             `json:"timeSlotEnd" gorm:"type:int;comment:时间断截至(分)"` | ||||
| 	// TimeSlotEnd   int             `json:"timeSlotEnd" gorm:"type:int;comment:时间断截至(分)"` | ||||
| 	models.ModelTime | ||||
| 	models.ControlBy | ||||
| } | ||||
|  | ||||
| @ -197,7 +197,7 @@ type LineAddPreOrderReq struct { | ||||
| 	Site                    string          `json:"site" `                       //购买方向 | ||||
| 	BuyPrice                string          `json:"buy_price" vd:"$>0"`          //购买金额 U | ||||
| 	PricePattern            string          `json:"price_pattern"`               //价格模式 | ||||
| 	Price                   string          `json:"price" vd:"$>0"`              //下单价百分比 | ||||
| 	Price                   string          `json:"price"`                       //下单价百分比 | ||||
| 	Profit                  string          `json:"profit" vd:"$>0"`             //止盈价 | ||||
| 	ProfitNumRatio          decimal.Decimal `json:"profit_num_ratio"`            //止盈数量百分比 | ||||
| 	ProfitTpTpPriceRatio    decimal.Decimal `json:"profit_tp_tp_price_ratio"`    //止盈后止盈价百分比 | ||||
|  | ||||
| @ -41,8 +41,8 @@ type LineStrategyTemplateInsertReq struct { | ||||
| 	Direction     int             `json:"direction" comment:"涨跌方向 1-涨 2-跌"` | ||||
| 	Percentag     decimal.Decimal `json:"percentag" comment:"涨跌点数"` | ||||
| 	CompareType   int             `json:"compareType" comment:"比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "` | ||||
| 	TimeSlotStart int             `json:"timeSlotStart" comment:"时间段开始(分)"` | ||||
| 	TimeSlotEnd   int             `json:"timeSlotEnd" comment:"时间断截至(分)"` | ||||
| 	TimeSlotStart int             `json:"timeSlotStart" comment:"时间段(分)"` | ||||
| 	// TimeSlotEnd   int             `json:"timeSlotEnd" comment:"时间断截至(分)"` | ||||
| 	common.ControlBy | ||||
| } | ||||
|  | ||||
| @ -63,13 +63,13 @@ func (s *LineStrategyTemplateInsertReq) Valid() error { | ||||
| 		return errors.New("比较类型不合法") | ||||
| 	} | ||||
|  | ||||
| 	if s.TimeSlotStart < 0 || s.TimeSlotEnd > 59 { | ||||
| 	if s.TimeSlotStart < 0 { | ||||
| 		return errors.New("时间段不合法") | ||||
| 	} | ||||
|  | ||||
| 	if s.TimeSlotEnd < s.TimeSlotStart { | ||||
| 		return errors.New("时间段不合法") | ||||
| 	} | ||||
| 	// if s.TimeSlotEnd < s.TimeSlotStart { | ||||
| 	// 	return errors.New("时间段不合法") | ||||
| 	// } | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
| @ -83,7 +83,7 @@ func (s *LineStrategyTemplateInsertReq) Generate(model *models.LineStrategyTempl | ||||
| 	model.Percentag = s.Percentag | ||||
| 	model.CompareType = s.CompareType | ||||
| 	model.TimeSlotStart = s.TimeSlotStart | ||||
| 	model.TimeSlotEnd = s.TimeSlotEnd | ||||
| 	// model.TimeSlotEnd = s.TimeSlotEnd | ||||
| 	model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 | ||||
| } | ||||
|  | ||||
| @ -97,8 +97,8 @@ type LineStrategyTemplateUpdateReq struct { | ||||
| 	Direction     int             `json:"direction" comment:"涨跌方向 1-涨 2-跌"` | ||||
| 	Percentag     decimal.Decimal `json:"percentag" comment:"涨跌点数"` | ||||
| 	CompareType   int             `json:"compareType" comment:"比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "` | ||||
| 	TimeSlotStart int             `json:"timeSlotStart" comment:"时间段开始(分)"` | ||||
| 	TimeSlotEnd   int             `json:"timeSlotEnd" comment:"时间断截至(分)"` | ||||
| 	TimeSlotStart int             `json:"timeSlotStart" comment:"时间段(分)"` | ||||
| 	// TimeSlotEnd   int             `json:"timeSlotEnd" comment:"时间断截至(分)"` | ||||
| 	common.ControlBy | ||||
| } | ||||
|  | ||||
| @ -120,13 +120,13 @@ func (s *LineStrategyTemplateUpdateReq) Valid() error { | ||||
| 		return errors.New("比较类型不合法") | ||||
| 	} | ||||
|  | ||||
| 	if s.TimeSlotStart < 0 || s.TimeSlotEnd > 59 { | ||||
| 	if s.TimeSlotStart < 0 { | ||||
| 		return errors.New("时间段不合法") | ||||
| 	} | ||||
|  | ||||
| 	if s.TimeSlotEnd < s.TimeSlotStart { | ||||
| 		return errors.New("时间段不合法") | ||||
| 	} | ||||
| 	// if s.TimeSlotEnd < s.TimeSlotStart { | ||||
| 	// 	return errors.New("时间段不合法") | ||||
| 	// } | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
| @ -139,7 +139,7 @@ func (s *LineStrategyTemplateUpdateReq) Generate(model *models.LineStrategyTempl | ||||
| 	model.Percentag = s.Percentag | ||||
| 	model.CompareType = s.CompareType | ||||
| 	model.TimeSlotStart = s.TimeSlotStart | ||||
| 	model.TimeSlotEnd = s.TimeSlotEnd | ||||
| 	// model.TimeSlotEnd = s.TimeSlotEnd | ||||
| 	model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -279,6 +279,8 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi | ||||
| 	futReduceVal, _ := helper.DefaultRedis.GetAllList(spotAddPositionKey) | ||||
| 	spotAddPositionVal, _ := helper.DefaultRedis.GetAllList(futReduceKey) | ||||
| 	spotReduceVal, _ := helper.DefaultRedis.GetAllList(spotReduceKey) | ||||
| 	spotStrategyMap := e.GetStrategyOrderListMap(1) | ||||
| 	futStrategyMap := e.GetStrategyOrderListMap(2) | ||||
|  | ||||
| 	for _, v := range futAddPositionVal { | ||||
| 		sonic.Unmarshal([]byte(v), &addPosition) | ||||
| @ -337,8 +339,14 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi | ||||
| 		if val, ok := spotRedces[order.Id]; ok { | ||||
| 			helper.DefaultRedis.LRem(spotReduceKey, val) | ||||
| 		} | ||||
| 		var tradedSetKey string | ||||
| 		if order.SymbolType == 1 { | ||||
| 			tradedSetKey = fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol) | ||||
| 		} else { | ||||
| 			tradedSetKey = fmt.Sprintf(global.TICKER_FUTURES, order.ExchangeType, order.Symbol) | ||||
| 		} | ||||
|  | ||||
| 		tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol)) | ||||
| 		tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, tradedSetKey) | ||||
| 		redisList.Price = utility.StringToDecimal(redisList.Price).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 		marshal, _ := sonic.Marshal(redisList) | ||||
| 		if order.SymbolType == 1 { | ||||
| @ -349,6 +357,13 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi | ||||
| 			helper.DefaultRedis.LRem(listKey, string(marshal)) | ||||
| 		} | ||||
|  | ||||
| 		switch { | ||||
| 		case order.StrategyTemplateType == 1 && order.SymbolType == 1: | ||||
| 			e.RemoveStrategyOrderCache(order.Id, order.SymbolType, order.ExchangeType, &spotStrategyMap) | ||||
| 		case order.StrategyTemplateType == 1 && order.SymbolType == 2: | ||||
| 			e.RemoveStrategyOrderCache(order.Id, order.SymbolType, order.ExchangeType, &futStrategyMap) | ||||
| 		} | ||||
|  | ||||
| 		//会影响持仓的 | ||||
| 		removeSymbolKey := fmt.Sprintf("%v_%s_%s_%s_%v", order.ApiId, order.ExchangeType, order.Symbol, order.Site, order.SymbolType) | ||||
|  | ||||
| @ -908,7 +923,6 @@ func saveOrderCache(req *dto.LineAddPreOrderReq, AddOrder models.LinePreOrder, l | ||||
| 		list.Percentag = linestrategyTemplate.Percentag | ||||
| 		list.CompareType = linestrategyTemplate.CompareType | ||||
| 		list.TimeSlotStart = linestrategyTemplate.TimeSlotStart | ||||
| 		list.TimeSlotEnd = linestrategyTemplate.TimeSlotEnd | ||||
|  | ||||
| 		marshal, _ = sonic.Marshal(&list) | ||||
| 		if AddOrder.SymbolType == global.SYMBOL_SPOT { | ||||
| @ -1995,6 +2009,8 @@ func (e *LinePreOrder) ClearUnTriggered() error { | ||||
| 	var orderLists []models.LinePreOrder | ||||
| 	positions := map[string]positiondto.LinePreOrderPositioinDelReq{} | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Where("main_id = 0 AND pid = 0 AND status = '0'").Find(&orderLists).Unscoped().Delete(&models.LinePreOrder{}) | ||||
| 	spotStrategyMap := e.GetStrategyOrderListMap(1) | ||||
| 	futStrategyMap := e.GetStrategyOrderListMap(2) | ||||
|  | ||||
| 	for _, order := range orderLists { | ||||
| 		redisList := dto.PreOrderRedisList{ | ||||
| @ -2006,17 +2022,35 @@ func (e *LinePreOrder) ClearUnTriggered() error { | ||||
| 			OrderSn:     order.OrderSn, | ||||
| 			QuoteSymbol: order.QuoteSymbol, | ||||
| 		} | ||||
| 		tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol)) | ||||
|  | ||||
| 		var tradedSetKey string | ||||
| 		if order.SymbolType == 1 { | ||||
| 			tradedSetKey = fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol) | ||||
| 		} else { | ||||
| 			tradedSetKey = fmt.Sprintf(global.TICKER_FUTURES, order.ExchangeType, order.Symbol) | ||||
| 		} | ||||
|  | ||||
| 		tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, tradedSetKey) | ||||
| 		redisList.Price = utility.StringToDecimal(redisList.Price).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 		marshal, _ := sonic.Marshal(redisList) | ||||
|  | ||||
| 		if order.SymbolType == 1 { | ||||
| 			key := fmt.Sprintf(rediskey.PreFutOrderList, order.ExchangeType) | ||||
|  | ||||
| 			helper.DefaultRedis.LRem(key, string(marshal)) | ||||
| 		} else { | ||||
| 			key := fmt.Sprintf(rediskey.PreSpotOrderList, order.ExchangeType) | ||||
|  | ||||
| 			helper.DefaultRedis.LRem(key, string(marshal)) | ||||
| 		} | ||||
|  | ||||
| 		switch { | ||||
| 		case order.StrategyTemplateType == 1 && order.SymbolType == 1: | ||||
| 			e.RemoveStrategyOrderCache(order.Id, order.SymbolType, order.ExchangeType, &spotStrategyMap) | ||||
| 		case order.StrategyTemplateType == 1 && order.SymbolType == 2: | ||||
| 			e.RemoveStrategyOrderCache(order.Id, order.SymbolType, order.ExchangeType, &futStrategyMap) | ||||
| 		} | ||||
|  | ||||
| 		//会影响持仓的 | ||||
| 		removeSymbolKey := fmt.Sprintf("%v_%s_%s_%s_%v", order.ApiId, order.ExchangeType, order.Symbol, order.Site, order.SymbolType) | ||||
|  | ||||
| @ -2056,6 +2090,60 @@ func (e *LinePreOrder) ClearUnTriggered() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // 移除待策略待触发单 | ||||
| func (e *LinePreOrder) RemoveStrategyOrderCache(orderId int, symbolType int, exchangeType string, caches *map[string][]dto.StrategyOrderRedisList) { | ||||
| 	strategys, _ := (*caches)[exchangeType] | ||||
| 	var strategyListKey string | ||||
|  | ||||
| 	if symbolType == 1 { | ||||
| 		strategyListKey = fmt.Sprintf(rediskey.StrategySpotOrderList, exchangeType) | ||||
| 	} else { | ||||
| 		strategyListKey = fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType) | ||||
| 	} | ||||
|  | ||||
| 	for _, strategy := range strategys { | ||||
| 		if strategy.Id == orderId { | ||||
| 			strategyVal, _ := sonic.MarshalString(strategy) | ||||
| 			helper.DefaultRedis.LRem(strategyListKey, strategyVal) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 获取策略订单缓存列表 | ||||
| // symbolType 1现货 2合约 | ||||
| func (e *LinePreOrder) GetStrategyOrderListMap(symbolType int) map[string][]dto.StrategyOrderRedisList { | ||||
| 	result := make(map[string][]dto.StrategyOrderRedisList) | ||||
| 	var key string | ||||
| 	exchanges := []string{global.EXCHANGE_BINANCE} | ||||
|  | ||||
| 	if symbolType == 1 { | ||||
| 		key = rediskey.StrategySpotOrderList | ||||
| 	} else { | ||||
| 		key = rediskey.StrategyFutOrderList | ||||
| 	} | ||||
|  | ||||
| 	for _, exchange := range exchanges { | ||||
| 		newKey := fmt.Sprintf(key, exchange) | ||||
| 		vals, _ := helper.DefaultRedis.GetAllList(newKey) | ||||
| 		itemData := make([]dto.StrategyOrderRedisList, 0) | ||||
| 		item := dto.StrategyOrderRedisList{} | ||||
|  | ||||
| 		for _, v := range vals { | ||||
| 			sonic.Unmarshal([]byte(v), &item) | ||||
|  | ||||
| 			if item.Id > 0 { | ||||
| 				itemData = append(itemData, item) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if len(itemData) > 0 { | ||||
| 			result[exchange] = itemData | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| func (e *LinePreOrder) QueryOrder(req *dto.QueryOrderReq) (res interface{}, err error) { | ||||
| 	var apiUserInfo models.LineApiUser | ||||
| 	e.Orm.Model(&models.LineApiUser{}).Where("id = ?", req.ApiId).Find(&apiUserInfo) | ||||
|  | ||||
| @ -3,6 +3,7 @@ package jobs | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	models2 "go-admin/app/jobs/models" | ||||
| 	"runtime" | ||||
| 	"time" | ||||
|  | ||||
| 	log "github.com/go-admin-team/go-admin-core/logger" | ||||
| @ -43,7 +44,10 @@ type ExecJob struct { | ||||
| func (e *ExecJob) Run() { | ||||
| 	defer func() { | ||||
| 		if err := recover(); err != nil { | ||||
| 			log.Errorf("脚本任务失败:%v", err) | ||||
| 			// 获取调用栈信息 | ||||
| 			buf := make([]byte, 1<<16) // 64KB 缓冲区 | ||||
| 			n := runtime.Stack(buf, false) | ||||
| 			log.Errorf("脚本任务失败: %v\n%s", err, buf[:n]) | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
|  | ||||
							
								
								
									
										22
									
								
								app/jobs/strategy_job_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/jobs/strategy_job_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| 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 TestStrategyJob(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") | ||||
|  | ||||
| 	job := StrategyJob{} | ||||
|  | ||||
| 	job.Exec([]string{}) | ||||
| } | ||||
| @ -46,9 +46,9 @@ const ( | ||||
| 	SpotTrigger            = "spot_trigger_lock:%v_%s"        //现货触发 {apiuserid|symbol} | ||||
| 	FutTrigger             = "fut_trigger_lock:%v_%s"         //合约触发 {apiuserid|symbol} | ||||
|  | ||||
| 	//波段现货触发{apiuserid|symbol} | ||||
| 	//波段现货触发{apiuserid|ordersn} | ||||
| 	StrategySpotTriggerLock = "strategy_spot_trigger_l:%v_%s" | ||||
| 	//波段合约触发{apiuserid|symbol} | ||||
| 	//波段合约触发{apiuserid|ordersn} | ||||
| 	StrategyFutTriggerLock = "strategy_fut_trigger_l:%v_%s" | ||||
|  | ||||
| 	//减仓波段合约触发 {apiuserid|symbol} | ||||
|  | ||||
| @ -106,6 +106,9 @@ func (rl *RedisLock) AcquireWait(ctx context.Context) (bool, error) { | ||||
| 				baseInterval = time.Second | ||||
| 			} | ||||
|  | ||||
| 			if baseInterval <= 0 { | ||||
| 				baseInterval = time.Millisecond * 100 // 至少 100ms | ||||
| 			} | ||||
| 			// 随机退避 | ||||
| 			retryInterval := time.Duration(rand.Int63n(int64(baseInterval))) // 随机退避 | ||||
| 			if retryInterval < time.Millisecond*100 { | ||||
| @ -129,6 +132,13 @@ func (rl *RedisLock) AcquireWait(ctx context.Context) (bool, error) { | ||||
| 	return false, ErrFailed | ||||
| } | ||||
|  | ||||
| func safeRandomDuration(max time.Duration) time.Duration { | ||||
| 	if max <= 0 { | ||||
| 		return 100 * time.Millisecond // fallback default | ||||
| 	} | ||||
| 	return time.Duration(rand.Int63n(int64(max))) | ||||
| } | ||||
|  | ||||
| // Release 释放锁 | ||||
| func (rl *RedisLock) Release() (bool, error) { | ||||
| 	return rl.releaseCtx(context.Background()) | ||||
|  | ||||
| @ -24,22 +24,29 @@ import ( | ||||
|  | ||||
| type BinanceStrategyOrderService struct { | ||||
| 	service.Service | ||||
| 	Debug bool | ||||
| } | ||||
|  | ||||
| // 判断是否触发波段订单 | ||||
| func (e *BinanceStrategyOrderService) TriggerStrategyOrder(exchangeType string) { | ||||
| 	//现货 | ||||
| 	orderStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType)) | ||||
| 	e.DoJudge(orderStrs, 1, exchangeType) | ||||
| 	orderStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategySpotOrderList, exchangeType)) | ||||
| 	if len(orderStrs) > 0 { | ||||
| 		e.DoJudge(orderStrs, 1, exchangeType) | ||||
| 	} | ||||
|  | ||||
| 	//合约 | ||||
| 	futOrdedrStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType)) | ||||
| 	e.DoJudge(futOrdedrStrs, 2, exchangeType) | ||||
|  | ||||
| 	if len(futOrdedrStrs) > 0 { | ||||
| 		e.DoJudge(futOrdedrStrs, 2, exchangeType) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 判断是否符合条件 | ||||
| func (e *BinanceStrategyOrderService) DoJudge(orderStrs []string, symbolType int, exchangeType string) { | ||||
| 	db := GetDBConnection() | ||||
| 	// setting, _ := cacheservice.GetSystemSetting(db) | ||||
|  | ||||
| 	for _, orderStr := range orderStrs { | ||||
| 		var lockKey string | ||||
| @ -56,7 +63,7 @@ func (e *BinanceStrategyOrderService) DoJudge(orderStrs []string, symbolType int | ||||
| 			lockKey = rediskey.StrategyFutTriggerLock | ||||
| 		} | ||||
|  | ||||
| 		lock := helper.NewRedisLock(fmt.Sprintf(lockKey, orderItem.ApiId, orderItem.Symbol), 200, 50, 100*time.Millisecond) | ||||
| 		lock := helper.NewRedisLock(fmt.Sprintf(lockKey, orderItem.ApiId, orderItem.OrderSn), 60, 20, 300*time.Millisecond) | ||||
|  | ||||
| 		if ok, err := lock.AcquireWait(context.Background()); err != nil { | ||||
| 			e.Log.Debug("获取锁失败", err) | ||||
| @ -65,13 +72,13 @@ func (e *BinanceStrategyOrderService) DoJudge(orderStrs []string, symbolType int | ||||
| 			defer lock.Release() | ||||
|  | ||||
| 			//判断是否符合条件 | ||||
| 			success, err := e.JudgeStrategy(orderItem, 1, exchangeType) | ||||
| 			success, err := e.JudgeStrategy(orderItem, symbolType, exchangeType) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				e.Log.Errorf("order_id:%d err:%v", orderItem.Id, err) | ||||
| 			} | ||||
|  | ||||
| 			if success { | ||||
| 			if e.Debug || success { | ||||
| 				e.TriggerOrder(db, orderStr, orderItem, symbolType) | ||||
| 			} | ||||
| 		} | ||||
| @ -121,22 +128,26 @@ func (e *BinanceStrategyOrderService) JudgeStrategy(order dto.StrategyOrderRedis | ||||
| 	} | ||||
|  | ||||
| 	percentag := lastPrice.Div(startPrice).Sub(decimal.NewFromInt(1)).Truncate(6) | ||||
| 	fmt.Printf("百分比:%s", percentag.Mul(decimal.NewFromInt(100)).String()) | ||||
| 	logger.Infof("百分比:%s", percentag.Mul(decimal.NewFromInt(100)).String()) | ||||
| 	//价格没有变动 | ||||
| 	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("没有对应的类型") | ||||
| 	switch { | ||||
| 	//涨价格大于0.5% 跌价格小于-0.5% | ||||
| 	case order.CompareType == 1 && order.Direction == 1 && percentag.Cmp(decimal.Zero) > 0, | ||||
| 		order.CompareType == 1 && order.Direction == 2 && percentag.Cmp(decimal.Zero) < 0: | ||||
| 		result = percentag.Abs().Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) > 0 | ||||
|  | ||||
| 	case order.CompareType == 2 && order.Direction == 1 && percentag.Cmp(decimal.Zero) > 0, | ||||
| 		order.CompareType == 2 && order.Direction == 2 && percentag.Cmp(decimal.Zero) < 0: | ||||
| 		result = percentag.Abs().Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) >= 0 | ||||
|  | ||||
| 	case order.CompareType == 5 && order.Direction == 1 && percentag.Cmp(decimal.Zero) > 0, | ||||
| 		order.CompareType == 5 && order.Direction == 2 && percentag.Cmp(decimal.Zero) < 0: | ||||
| 		result = percentag.Abs().Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) == 0 | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| @ -145,7 +156,7 @@ func (e *BinanceStrategyOrderService) JudgeStrategy(order dto.StrategyOrderRedis | ||||
| // 触发委托单 | ||||
| func (e *BinanceStrategyOrderService) TriggerOrder(db *gorm.DB, cacheVal string, 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 { | ||||
| 	if err := e.Orm.Model(&models.LinePreOrder{}).Where("main_id =? or id =?", order.Id, order.Id).Find(&orders).Error; err != nil { | ||||
| 		e.Log.Errorf("order_id:%d 获取委托单失败:%s", order.Id, err.Error()) | ||||
| 		return err | ||||
| 	} | ||||
| @ -156,7 +167,16 @@ func (e *BinanceStrategyOrderService) TriggerOrder(db *gorm.DB, cacheVal string, | ||||
| 		return errors.New("获取系统设置失败") | ||||
| 	} | ||||
|  | ||||
| 	tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, symbolType) | ||||
| 	var tradeSet models2.TradeSet | ||||
|  | ||||
| 	switch symbolType { | ||||
| 	case 1: | ||||
| 		tradeSet, _ = cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 0) | ||||
| 	case 2: | ||||
| 		tradeSet, _ = cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1) | ||||
| 	default: | ||||
| 		return errors.New("获取交易对行情失败,交易对类型错误") | ||||
| 	} | ||||
|  | ||||
| 	if tradeSet.Coin == "" { | ||||
| 		return errors.New("获取交易对行情失败") | ||||
| @ -177,11 +197,36 @@ func (e *BinanceStrategyOrderService) TriggerOrder(db *gorm.DB, cacheVal string, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if mainOrder.Id == 0 { | ||||
| 		return errors.New("获取主单失败") | ||||
| 	} | ||||
|  | ||||
| 	GetOrderByPid(&mainOrder, orders, mainOrder.Id) | ||||
|  | ||||
| 	e.RecalculateOrder(tradeSet, &mainOrder, setting) | ||||
|  | ||||
| 	if err := e.Orm.Save(&mainOrder).Error; err != nil { | ||||
| 	//事务保存 | ||||
| 	err := e.Orm.Transaction(func(tx *gorm.DB) error { | ||||
| 		if err1 := tx.Save(&mainOrder).Error; err1 != nil { | ||||
| 			return err1 | ||||
| 		} | ||||
|  | ||||
| 		for _, v := range mainOrder.Childs { | ||||
| 			if err1 := tx.Save(&v).Error; err1 != nil { | ||||
| 				return err1 | ||||
| 			} | ||||
|  | ||||
| 			for _, v2 := range v.Childs { | ||||
| 				if err1 := tx.Save(&v2).Error; err1 != nil { | ||||
| 					return err1 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return nil | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("order_id:%d 波段触发保存委托单失败:%s", mainOrder.Id, err.Error()) | ||||
| 		return err | ||||
| 	} | ||||
| @ -224,16 +269,29 @@ func (e *BinanceStrategyOrderService) StrategyOrderPlace(db *gorm.DB, cacheVal s | ||||
|  | ||||
| 	if err := futApi.OrderPlaceLoop(db, params, 3); err != nil { | ||||
| 		logger.Error("下单失败", mainOrder.Symbol, " err:", err) | ||||
| 		if _, err := helper.DefaultRedis.LRem(key, cacheVal); err != nil { | ||||
| 			logger.Error("删除redis 预下单失败:", err) | ||||
| 		} | ||||
|  | ||||
| 		err := db.Model(&models.LinePreOrder{}).Where("id =? and status='0'", mainOrder.Id).Updates(map[string]interface{}{"status": "2", "desc": err.Error()}).Error | ||||
|  | ||||
| 		if err != nil { | ||||
| 			logger.Error("更新预下单状态失败") | ||||
| 		} | ||||
|  | ||||
| 		return | ||||
| 	} else { | ||||
| 		if _, err := helper.DefaultRedis.LRem(key, cacheVal); err != nil { | ||||
| 			logger.Error("删除redis 预下单失败:", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if err := db.Model(&models.LinePreOrder{}).Where("id =? ", mainOrder.Id).Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil { | ||||
| 		logger.Error("更新预下单状态失败 ordersn:", mainOrder.OrderSn, " status:1") | ||||
| 	} | ||||
|  | ||||
| 	if err := db.Model(&models.LinePreOrder{}).Where("id =? AND status ='0'", mainOrder.Id).Updates(map[string]interface{}{"status": "1"}).Error; err != nil { | ||||
| 		logger.Error("更新预下单状态失败 ordersn:", mainOrder.OrderSn, " status:1") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -247,9 +305,10 @@ func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet | ||||
| 		return errors.New("获取拓展信息失败") | ||||
| 	} | ||||
|  | ||||
| 	var newPrice decimal.Decimal | ||||
| 	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)) | ||||
| 	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)) | ||||
|  | ||||
| @ -257,51 +316,60 @@ func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet | ||||
| 	mainOrder.Price = newPrice.String() | ||||
| 	mainOrder.Num = totalNum.String() | ||||
| 	remainQuantity := totalNum | ||||
| 	var totalLossAmount decimal.Decimal | ||||
| 	prePrice := lastPrice | ||||
|  | ||||
| 	for index := range mainOrder.Childs { | ||||
| 		var ext models.LinePreOrderExt | ||||
| 		extOrderId := mainOrder.Childs[index].Id | ||||
| 		takeStopArray := []int{1, 2} | ||||
|  | ||||
| 		//止盈止损 ext拓展id为 pid | ||||
| 		if utility.ContainsInt(takeStopArray, mainOrder.Childs[index].OrderType) { | ||||
| 			extOrderId = mainOrder.Childs[index].Pid | ||||
| 		} | ||||
|  | ||||
| 		for _, v := range exts { | ||||
| 			if v.OrderId == mainOrder.Child[index].Id { | ||||
| 			if v.OrderId == extOrderId { | ||||
| 				ext = v | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if ext.Id <= 0 { | ||||
| 			logger.Errorf("子订单ext不存在 id:%d", mainOrder.Child[index].Id) | ||||
| 			logger.Errorf("子订单ext不存在 id:%d", mainOrder.Childs[index].Id) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		//主单止盈、止损 | ||||
| 		if mainOrder.Child[index].Pid == mainOrder.Child[index].MainId && (mainOrder.Child[index].OrderType == 1 || mainOrder.Child[index].OrderType == 2) { | ||||
| 		if mainOrder.Childs[index].Pid == mainOrder.Childs[index].MainId && (mainOrder.Childs[index].OrderType == 1 || mainOrder.Childs[index].OrderType == 2) { | ||||
| 			var percent decimal.Decimal | ||||
|  | ||||
| 			switch { | ||||
| 			// 加价 | ||||
| 			case mainOrder.Child[index].OrderType == 1 && mainOrder.Site == "BUY", mainOrder.Child[index].OrderType == 2 && mainOrder.Site == "SELL": | ||||
| 			case mainOrder.Childs[index].OrderType == 1 && mainOrder.Site == "BUY", mainOrder.Childs[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": | ||||
| 			case mainOrder.Childs[index].OrderType == 2 && mainOrder.Site == "BUY", mainOrder.Childs[index].OrderType == 1 && mainOrder.Site == "SELL": | ||||
| 				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() | ||||
| 			mainOrder.Child[index].Num = totalNum.String() | ||||
| 			mainOrder.Childs[index].Price = childPrice.String() | ||||
| 			mainOrder.Childs[index].Num = totalNum.String() | ||||
|  | ||||
| 		} else { | ||||
| 			//todo 重新计算 | ||||
| 			lastNum := remainQuantity | ||||
|  | ||||
| 			//过期时间 | ||||
| 			if ext.ExpirateHour <= 0 { | ||||
| 				mainOrder.Child[index].ExpireTime = time.Now().AddDate(10, 0, 0) | ||||
| 				mainOrder.Childs[index].ExpireTime = time.Now().AddDate(10, 0, 0) | ||||
| 			} else { | ||||
| 				mainOrder.Child[index].ExpireTime = time.Now().Add(time.Hour * time.Duration(ext.ExpirateHour)) | ||||
| 				mainOrder.Childs[index].ExpireTime = time.Now().Add(time.Hour * time.Duration(ext.ExpirateHour)) | ||||
| 			} | ||||
|  | ||||
| 			switch { | ||||
| 			//加仓单 | ||||
| 			case mainOrder.Child[index].OrderType == 1 && mainOrder.Child[index].OrderCategory == 3: | ||||
| 			case mainOrder.Childs[index].OrderType == 1 && mainOrder.Childs[index].OrderCategory == 3: | ||||
| 				var percentage decimal.Decimal | ||||
|  | ||||
| 				if mainOrder.Site == "BUY" { | ||||
| @ -311,24 +379,29 @@ func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet | ||||
| 				} | ||||
|  | ||||
| 				dataPrice := utility.StrToDecimal(mainOrder.Price).Mul(percentage).Truncate(int32(tradeSet.PriceDigit)) | ||||
| 				mainOrder.Child[index].Price = dataPrice.String() | ||||
| 				mainOrder.Childs[index].Price = dataPrice.String() | ||||
|  | ||||
| 				priceDiff := dataPrice.Sub(prePrice).Abs() | ||||
| 				totalLossAmount = totalLossAmount.Add(lastNum.Mul(priceDiff)) | ||||
|  | ||||
| 				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() | ||||
| 					mainOrder.Childs[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() | ||||
| 					mainOrder.Childs[index].Num = utility.SafeDiv(ext.AddPositionVal.Truncate(2), dataPrice).Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 				} | ||||
|  | ||||
| 				//加库存 | ||||
| 				lastNum = lastNum.Add(utility.StrToDecimal(mainOrder.Child[index].Num)) | ||||
| 				lastNum = lastNum.Add(utility.StrToDecimal(mainOrder.Childs[index].Num)) | ||||
| 				// 计算子订单 | ||||
| 				if len(mainOrder.Child[index].Child) > 0 { | ||||
| 					calculateChildOrder(&mainOrder.Child, &tradeSet, ext, lastNum, dataPrice, false) | ||||
| 				if len(mainOrder.Childs[index].Childs) > 0 { | ||||
| 					calculateChildOrder(&mainOrder.Childs[index].Childs, &tradeSet, ext, lastNum, dataPrice, totalLossAmount, false) | ||||
| 				} | ||||
| 				//覆盖最近的订单价 | ||||
| 				prePrice = dataPrice | ||||
| 				//减仓单 | ||||
| 			case mainOrder.Child[index].OrderType == 4: | ||||
| 			case mainOrder.Childs[index].OrderType == 4: | ||||
| 				percentage := decimal.NewFromInt(1) | ||||
|  | ||||
| 				if mainOrder.Site == "BUY" && ext.PriceRatio.Cmp(decimal.Zero) > 0 { | ||||
| @ -338,22 +411,26 @@ func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet | ||||
| 				} | ||||
|  | ||||
| 				dataPrice := utility.StrToDecimal(mainOrder.Price).Mul(percentage).Truncate(int32(tradeSet.PriceDigit)) | ||||
| 				mainOrder.Child[index].Price = dataPrice.String() | ||||
| 				mainOrder.Childs[index].Price = dataPrice.String() | ||||
| 				priceDiff := dataPrice.Sub(prePrice).Abs() | ||||
| 				totalLossAmount = totalLossAmount.Add(lastNum.Mul(priceDiff)) | ||||
|  | ||||
| 				//百分比减仓 | ||||
| 				if ext.AddPositionType == 1 { | ||||
| 					mainOrder.Child[index].Num = lastNum.Mul(ext.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 					mainOrder.Childs[index].Num = lastNum.Mul(ext.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String() | ||||
|  | ||||
| 				} else { | ||||
| 					logger.Error("减仓不能是固定数值") | ||||
| 				} | ||||
|  | ||||
| 				//减库存 | ||||
| 				lastNum = lastNum.Sub(utility.StrToDecimal(mainOrder.Child[index].Num)) | ||||
| 				lastNum = lastNum.Sub(utility.StrToDecimal(mainOrder.Childs[index].Num)) | ||||
| 				// 计算子订单 | ||||
| 				if len(mainOrder.Child[index].Child) > 0 { | ||||
| 					calculateChildOrder(&mainOrder.Child, &tradeSet, ext, lastNum, dataPrice, false) | ||||
| 				if len(mainOrder.Childs[index].Childs) > 0 { | ||||
| 					calculateChildOrder(&mainOrder.Childs[index].Childs, &tradeSet, ext, lastNum, dataPrice, totalLossAmount, false) | ||||
| 				} | ||||
| 				//覆盖最近的订单价 | ||||
| 				prePrice = dataPrice | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -362,7 +439,8 @@ func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet | ||||
|  | ||||
| // 计算子订单信息 | ||||
| // isTpTp 是否是止盈后止损止盈 | ||||
| func calculateChildOrder(orders *[]models.LinePreOrder, tradeSet *models2.TradeSet, ext models.LinePreOrderExt, lastNum decimal.Decimal, price decimal.Decimal, isTpTp bool) error { | ||||
| // totalLossAmount 累计亏损金额 | ||||
| func calculateChildOrder(orders *[]models.LinePreOrder, tradeSet *models2.TradeSet, ext models.LinePreOrderExt, lastNum decimal.Decimal, price decimal.Decimal, totalLossAmount decimal.Decimal, isTpTp bool) error { | ||||
| 	for index := range *orders { | ||||
| 		orderQuantity := lastNum.Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		percentage := decimal.NewFromInt(1) | ||||
| @ -389,11 +467,21 @@ func calculateChildOrder(orders *[]models.LinePreOrder, tradeSet *models2.TradeS | ||||
| 		switch { | ||||
| 		//做多止盈、做空止损 | ||||
| 		case (*orders)[index].OrderType == 1 && (*orders)[index].Site == "SELL", (*orders)[index].OrderType == 2 && (*orders)[index].Site == "BUY": | ||||
| 			percentage = decimal.NewFromInt(100).Add(addPercentage).Div(decimal.NewFromInt(100)) | ||||
| 			percentage = decimal.NewFromInt(100).Add(addPercentage) | ||||
|  | ||||
| 			//做多止损、做空止盈 | ||||
| 		case (*orders)[index].OrderType == 2 && (*orders)[index].Site == "SELL", (*orders)[index].OrderType == 1 && (*orders)[index].Site == "BUY": | ||||
| 			percentage = decimal.NewFromInt(100).Sub(addPercentage).Div(decimal.NewFromInt(100)) | ||||
| 			percentage = decimal.NewFromInt(100).Sub(addPercentage) | ||||
| 		} | ||||
|  | ||||
| 		//止盈亏损回本百分比 | ||||
| 		if (*orders)[index].OrderType == 1 && totalLossAmount.Cmp(decimal.Zero) > 0 { | ||||
| 			lossPercent := totalLossAmount.Div(lastNum).Mul(decimal.NewFromInt(100)).Truncate(2) | ||||
| 			percentage = percentage.Add(lossPercent) | ||||
| 		} | ||||
|  | ||||
| 		if percentage.Cmp(decimal.Zero) > 0 { | ||||
| 			percentage = percentage.Div(decimal.NewFromInt(100)) | ||||
| 		} | ||||
|  | ||||
| 		orderPrice := price.Mul(percentage).Truncate(int32(tradeSet.PriceDigit)) | ||||
| @ -402,8 +490,8 @@ func calculateChildOrder(orders *[]models.LinePreOrder, tradeSet *models2.TradeS | ||||
| 		lastOrderQuantity := lastNum.Sub(orderQuantity).Truncate(int32(tradeSet.AmountDigit)) | ||||
|  | ||||
| 		//止盈后止盈、止盈后止损 | ||||
| 		if len((*orders)[index].Child) > 0 && lastOrderQuantity.Cmp(decimal.Zero) > 0 { | ||||
| 			calculateChildOrder(&(*orders)[index].Child, tradeSet, ext, lastOrderQuantity, orderPrice, true) | ||||
| 		if len((*orders)[index].Childs) > 0 && lastOrderQuantity.Cmp(decimal.Zero) > 0 { | ||||
| 			calculateChildOrder(&(*orders)[index].Childs, tradeSet, ext, lastOrderQuantity, orderPrice, decimal.Zero, true) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | ||||
							
								
								
									
										26
									
								
								services/binanceservice/strategy_order_service_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								services/binanceservice/strategy_order_service_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| package binanceservice | ||||
|  | ||||
| import ( | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/go-admin-team/go-admin-core/sdk" | ||||
| 	"gorm.io/driver/mysql" | ||||
| 	"gorm.io/gorm" | ||||
| ) | ||||
|  | ||||
| // 测试策略 触发单 | ||||
| func TestTriggerOrder(t *testing.T) { | ||||
| 	service := BinanceStrategyOrderService{} | ||||
| 	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") | ||||
| 	sdk.Runtime.SetDb("default", db) | ||||
|  | ||||
| 	service.Orm = db | ||||
| 	service.Debug = true | ||||
|  | ||||
| 	service.TriggerStrategyOrder(global.EXCHANGE_BINANCE) | ||||
| } | ||||
| @ -66,9 +66,11 @@ func GetConfigCacheByKey(db *gorm.DB, key string) models.SysConfig { | ||||
| // 获取缓存交易对 | ||||
| // symbolType 0-现货 1-合约 | ||||
| func GetTradeSet(exchangeType string, symbol string, symbolType int) (models2.TradeSet, error) { | ||||
| 	// 定义返回结果和val变量 | ||||
| 	result := models2.TradeSet{} | ||||
| 	val := "" | ||||
|  | ||||
| 	// 根据交易对类型选择不同的key | ||||
| 	switch symbolType { | ||||
| 	case 0: | ||||
| 		key := fmt.Sprintf(global.TICKER_SPOT, exchangeType, symbol) | ||||
| @ -78,14 +80,17 @@ func GetTradeSet(exchangeType string, symbol string, symbolType int) (models2.Tr | ||||
| 		val, _ = helper.DefaultRedis.GetString(key) | ||||
| 	} | ||||
|  | ||||
| 	// 如果val不为空,则解析val为TradeSet结构体 | ||||
| 	if val != "" { | ||||
| 		if err := sonic.Unmarshal([]byte(val), &result); err != nil { | ||||
| 			return result, err | ||||
| 		} | ||||
| 	} else { | ||||
| 		// 如果val为空,则返回错误信息 | ||||
| 		return result, errors.New("未找到交易对信息") | ||||
| 	} | ||||
|  | ||||
| 	// 返回结果 | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user