Files
exchange_go/app/admin/service/line_pre_order.go
2025-02-10 18:21:44 +08:00

1262 lines
45 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"errors"
"fmt"
"go-admin/common/const/rediskey"
"go-admin/common/global"
"go-admin/common/helper"
models2 "go-admin/models"
"go-admin/pkg/utility"
"go-admin/pkg/utility/snowflakehelper"
"go-admin/services/binanceservice"
"strconv"
"strings"
"time"
"github.com/bytedance/sonic"
"github.com/jinzhu/copier"
"github.com/shopspring/decimal"
"github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk/service"
"gorm.io/gorm"
"go-admin/app/admin/models"
"go-admin/app/admin/service/dto"
"go-admin/common/actions"
cDto "go-admin/common/dto"
)
type LinePreOrder struct {
service.Service
}
// GetPage 获取LinePreOrder列表
func (e *LinePreOrder) GetPage(c *dto.LinePreOrderGetPageReq, p *actions.DataPermission, list *[]models.LinePreOrder, count *int64) error {
var err error
var data models.LinePreOrder
tx := e.Orm.Model(&data).
Scopes(
cDto.MakeCondition(c.GetNeedSearch()),
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
actions.Permission(data.TableName(), p),
).Where("pid = 0").Joins("JOIN line_api_user on line_api_user.id = line_pre_order.api_id").
Joins("JOIN line_pre_order_status on line_pre_order_status.order_sn = line_pre_order.order_sn").
Select("line_pre_order.*,line_api_user.api_name,line_pre_order_status.add_position_status,line_pre_order_status.reduce_status")
if c.AddPositionStatus >= 0 {
tx.Where("line_pre_order_status.add_position_status = ?", c.AddPositionStatus)
}
if c.HedgeStatus >= 0 {
tx.Where("line_pre_order_status.reduce_status = ?", c.HedgeStatus)
}
err = tx.
Find(list).Limit(-1).Offset(-1).
Count(count).Error
if err != nil {
e.Log.Errorf("LinePreOrderService GetPage error:%s \r\n", err)
return err
}
for i, order := range *list {
var childNum int64
e.Orm.Model(&models.LinePreOrder{}).Where("pid = ?", order.Id).Count(&childNum)
(*list)[i].ChildNum = childNum
}
return nil
}
// GetOrderPage 获取LinePreOrder列表
func (e *LinePreOrder) GetOrderPage(c *dto.LinePreOrderGetPageReq, p *actions.DataPermission, list *[]models.LinePreOrder, count *int64) error {
var err error
var data models.LinePreOrder
tx := e.Orm.Model(&data).
Scopes(
cDto.MakeCondition(c.GetNeedSearch()),
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
actions.Permission(data.TableName(), p),
).Where("pid = 0 AND status != '0'").Joins("JOIN line_api_user on line_api_user.id = line_pre_order.api_id").
Joins("JOIN line_pre_order_status on line_pre_order_status.order_id = line_pre_order.id").
Select("line_pre_order.*,line_api_user.api_name,line_pre_order_status.add_position_status,line_pre_order_status.reduce_status")
if c.AddPositionStatus >= 0 {
tx.Where("line_pre_order_status.add_position_status = ?", c.AddPositionStatus)
}
if c.HedgeStatus >= 0 {
tx.Where("line_pre_order_status.reduce_status = ?", c.HedgeStatus)
}
err = tx.
Find(list).Limit(-1).Offset(-1).
Count(count).Error
//err = e.Orm.Model(&data).
// Scopes(
// cDto.MakeCondition(c.GetNeedSearch()),
// cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
// actions.Permission(data.TableName(), p),
// ).Where("pid = 0 AND status != '0'").Joins("JOIN line_api_user on line_api_user.id = line_pre_order.api_id").Select("line_pre_order.*,line_api_user.api_name").
// Find(list).Limit(-1).Offset(-1).
// Count(count).Error
if err != nil {
e.Log.Errorf("LinePreOrderService GetChildPage error:%s \r\n", err)
return err
}
for i, order := range *list {
var childNum int64
e.Orm.Model(&models.LinePreOrder{}).Where("pid = ?", order.Id).Count(&childNum)
(*list)[i].ChildNum = childNum
}
return nil
}
// GetAllPage 获取LinePreOrder列表
func (e *LinePreOrder) GetAllPage(c *dto.LinePreOrderGetPageReq, p *actions.DataPermission, list *[]models.LinePreOrder, count *int64) error {
var err error
var data models.LinePreOrder
err = e.Orm.Model(&data).
Scopes(
cDto.MakeCondition(c.GetNeedSearch()),
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
actions.Permission(data.TableName(), p),
).
Find(list).Limit(-1).Offset(-1).
Count(count).Error
if err != nil {
e.Log.Errorf("LinePreOrderService GetPage error:%s \r\n", err)
return err
}
return nil
}
// GetChildList 获取子订单列表
func (e *LinePreOrder) GetChildList(req *dto.GetChildOrderReq, p *actions.DataPermission, order *[]models.LinePreOrder) error {
err := e.Orm.Model(&models.LinePreOrder{}).Where("pid = ?", req.Id).
Order("id asc").
Joins("JOIN line_api_user on line_api_user.id = line_pre_order.api_id").Select("line_pre_order.*,line_api_user.api_name").
Find(order).Error
if err != nil {
e.Log.Errorf("LinePreOrderService GetPage error:%s \r\n", err)
return err
}
return nil
}
// Get 获取LinePreOrder对象
func (e *LinePreOrder) Get(d *dto.LinePreOrderGetReq, p *actions.DataPermission, model *models.LinePreOrder) error {
var data models.LinePreOrder
err := e.Orm.Model(&data).
Scopes(
actions.Permission(data.TableName(), p),
).
First(model, d.GetId()).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
err = errors.New("查看对象不存在或无权查看")
e.Log.Errorf("Service GetLinePreOrder error:%s \r\n", err)
return err
}
if err != nil {
e.Log.Errorf("db error:%s", err)
return err
}
return nil
}
// Insert 创建LinePreOrder对象
func (e *LinePreOrder) Insert(c *dto.LinePreOrderInsertReq) error {
var err error
var data models.LinePreOrder
c.Generate(&data)
err = e.Orm.Create(&data).Error
if err != nil {
e.Log.Errorf("LinePreOrderService Insert error:%s \r\n", err)
return err
}
return nil
}
// Update 修改LinePreOrder对象
func (e *LinePreOrder) Update(c *dto.LinePreOrderUpdateReq, p *actions.DataPermission) error {
var err error
var data = models.LinePreOrder{}
e.Orm.Scopes(
actions.Permission(data.TableName(), p),
).First(&data, c.GetId())
c.Generate(&data)
db := e.Orm.Save(&data)
if err = db.Error; err != nil {
e.Log.Errorf("LinePreOrderService Save error:%s \r\n", err)
return err
}
if db.RowsAffected == 0 {
return errors.New("无权更新该数据")
}
return nil
}
// Remove 删除LinePreOrder
func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermission) error {
var data models.LinePreOrder
var list []models.LinePreOrder
e.Orm.Model(&models.LinePreOrder{}).Where("id in ?", d.GetId()).Find(&list)
//for _, order := range list {
//if order.Status != "0" {
// return errors.New(fmt.Sprintf("订单id %d 已被触发 无法被删除", order.Id))
//}
//}
db := e.Orm.Model(&data).
Scopes(
actions.Permission(data.TableName(), p),
).Unscoped().Delete(&data, d.GetId())
if err := db.Error; err != nil {
e.Log.Errorf("Service RemoveLinePreOrder error:%s \r\n", err)
return err
}
ints := make([]int, 0)
apiIds := make([]int, 0)
if db.RowsAffected == 0 {
return errors.New("无权删除该数据")
}
//删除的缓存
for _, order := range list {
redisList := dto.PreOrderRedisList{
Id: order.Id,
Symbol: order.Symbol,
Price: order.Price,
Site: order.Site,
ApiId: order.ApiId,
OrderSn: order.OrderSn,
QuoteSymbol: order.QuoteSymbol,
}
if !utility.ContainsInt(apiIds, order.ApiId) {
apiIds = append(apiIds, order.ApiId)
}
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol))
redisList.Price = utility.StringToDecimal(redisList.Price).Truncate(int32(tradeSet.PriceDigit)).String()
marshal, _ := sonic.Marshal(redisList)
if order.SymbolType == 1 {
listKey := fmt.Sprintf(rediskey.PreSpotOrderList, order.ExchangeType)
helper.DefaultRedis.LRem(listKey, string(marshal))
} else {
listKey := fmt.Sprintf(rediskey.PreFutOrderList, order.ExchangeType)
helper.DefaultRedis.LRem(listKey, string(marshal))
}
binanceservice.MainClosePositionClearCache(order.Id, order.CoverType)
ints = append(ints, order.Id)
}
if len(ints) > 0 {
e.Orm.Model(&models.LinePreOrder{}).Where("pid >0 AND pid in ?", ints).Unscoped().Delete(&models.LinePreOrder{})
}
return nil
}
// AddPreOrder 单个添加
func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataPermission, errs *[]error, tickerSymbol string) error {
apiUserIds := strings.Split(req.ApiUserId, ",")
if req.SaveTemplate == "2" || req.SaveTemplate == "1" { //2 = 只保存模板 1= 保存模板并下单
var templateLog dto.LineAddPreOrderReq
copier.Copy(&templateLog, req)
//templateLog := *req
templateLog.SaveTemplate = "0"
templateLog.TemplateName = ""
marshal, _ := sonic.Marshal(templateLog)
saveTemplateParams := models.LineOrderTemplateLogs{
Name: req.TemplateName,
UserId: 0,
Params: string(marshal),
Type: 1,
Switch: "0",
}
e.Orm.Model(&models.LineOrderTemplateLogs{}).Create(&saveTemplateParams)
}
if req.SaveTemplate == "2" {
return nil
}
var key string
if req.SymbolType == global.SYMBOL_SPOT {
key = fmt.Sprintf(global.TICKER_SPOT, req.ExchangeType, req.Symbol)
} else {
key = fmt.Sprintf(global.TICKER_FUTURES, req.ExchangeType, req.Symbol)
}
for _, id := range apiUserIds {
if req.Site == "SELL" && req.SymbolType == global.SYMBOL_SPOT {
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 现货不支持卖出操作", id, req.Symbol))
continue
}
var AddOrder models.LinePreOrder
var profitOrder models.LinePreOrder
var stopOrder models.LinePreOrder
//获取交易对
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key)
orderCount := e.CheckRepeatOrder(req.OrderType, id, req.Site, tradeSet.Coin)
if orderCount > 0 {
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 该交易对已存在,请勿重复下单", id, req.Symbol))
continue
}
tickerPrice := utility.StrToDecimal(tradeSet.LastPrice)
if tickerPrice.Equal(decimal.Zero) { //redis 没有这个值
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 交易行情出错", id, req.Symbol))
continue
}
AddOrder.ExchangeType = req.ExchangeType
AddOrder.OrderCategory = 1
AddOrder.SignPriceType = "new"
AddOrder.BuyPrice = req.BuyPrice //购买多少U
AddOrder.SymbolType = req.SymbolType //交易对类型1= 现货 2 = 合约
AddOrder.OrderType = req.OrderType //订单类型
AddOrder.CoverType = req.CoverType //对冲类型 0=无对冲 1= 现货对合约 2=合约对合约 3 合约对现货
if req.ExpireHour == 0 { //过期时间默认为4个小时
req.ExpireHour = 4
}
AddOrder.ExpireTime = time.Now().Add(time.Duration(req.ExpireHour) * time.Hour) //过期时间
AddOrder.MainOrderType = req.MainOrderType
AddOrder.Site = req.Site
if req.PricePattern == "percentage" {
AddOrder.Rate = req.Price
orderPrice, _ := decimal.NewFromString(req.Price) //下单价百分比 10%
priceRate := orderPrice.Div(decimal.NewFromInt(100)) //下单价除100 =0.1
AddOrder.SignPrice = tickerPrice.String()
if strings.ToUpper(req.Site) == "BUY" { //购买方向
//实际下单价格
truncate := tickerPrice.Mul(decimal.NewFromInt(1).Sub(priceRate)).Truncate(int32(tradeSet.PriceDigit))
AddOrder.Price = truncate.String()
} else {
truncate := tickerPrice.Mul(decimal.NewFromInt(1).Add(priceRate)).Truncate(int32(tradeSet.PriceDigit))
AddOrder.Price = truncate.String()
}
} else { //实际价格下单
AddOrder.Price = utility.StringToDecimal(req.Price).Truncate(int32(tradeSet.PriceDigit)).String()
AddOrder.SignPrice = req.Price
AddOrder.SignPriceType = "mixture"
AddOrder.Rate = "0"
}
buyPrice, _ := decimal.NewFromString(req.BuyPrice) //购买多少U
var symbolInfo models.LineSymbol
e.Orm.Model(&models.LineSymbol{}).Where("type = ? AND symbol = ?", req.SymbolType, req.Symbol).Find(&symbolInfo)
//计算购买数量 判断是否是否是U本位
if symbolInfo.QuoteAsset != "USDT" { //不是U本位
//获取币本位兑换u的价格
ticker2 := models2.TradeSet{}
tickerVal, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.TICKER_SPOT, req.ExchangeType, strings.ToUpper(symbolInfo.QuoteAsset+"USDT")))
if tickerVal == "" {
logger.Error("查询行情失败")
continue
}
err := sonic.Unmarshal([]byte(tickerVal), &ticker2)
if ticker2.LastPrice == "" {
logger.Errorf("查询行情失败 %s err:%v", strings.ToUpper(symbolInfo.QuoteAsset+"USDT"), err)
continue
}
//LTCBTC --> LTCUSDT
uTickerPrice, _ := decimal.NewFromString(ticker2.LastPrice) //94069
//换算成U
//div := decimal.NewFromInt(1).Div(uTickerPrice) //0.0000106365
//在换算成对应交易对对应的价值
//LTCBTC --> LTCUSDT == LTCUSDT -- 100.502
div := tickerPrice.Div(decimal.NewFromInt(1).Div(uTickerPrice))
//计算下单数量
AddOrder.Num = buyPrice.Div(div).Truncate(int32(tradeSet.AmountDigit)).String()
} else {
fromString, _ := decimal.NewFromString(AddOrder.Price)
AddOrder.Num = buyPrice.Div(fromString).Truncate(int32(tradeSet.AmountDigit)).String()
}
if utility.StringToFloat64(AddOrder.Num) < tradeSet.MinQty {
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 小于最小下单数量", id, req.Symbol))
continue
}
AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
AddOrder.ApiId, _ = strconv.Atoi(id)
AddOrder.Symbol = req.Symbol
AddOrder.QuoteSymbol = symbolInfo.QuoteAsset
AddOrder.Pid = 0
AddOrder.GroupId = "0"
AddOrder.Status = 0
copier.Copy(&profitOrder, &AddOrder)
copier.Copy(&stopOrder, &AddOrder)
preOrderStatus := models.LinePreOrderStatus{}
preOrderStatus.OrderSn = AddOrder.OrderSn
//订单配置信息
preOrderExts := make([]models.LinePreOrderExt, 0)
defultExt := models.LinePreOrderExt{
TakeProfitRatio: req.TakeProfitRatio,
ReducePriceRatio: req.ReducePriceRatio,
ReduceNumRatio: req.ReduceNumRatio,
ReduceTakeProfitRatio: req.ReduceTakeProfitRatio,
ReduceStopLossRatio: req.ReduceStopLossRatio,
}
preOrderExts = append(preOrderExts, defultExt)
for _, addPosition := range req.Ext {
ext := models.LinePreOrderExt{
TakeProfitRatio: addPosition.TakeProfitRatio,
ReducePriceRatio: addPosition.ReducePriceRatio,
ReduceNumRatio: addPosition.ReduceNumRatio,
ReduceTakeProfitRatio: addPosition.ReduceTakeProfitRatio,
ReduceStopLossRatio: addPosition.ReduceStopLossRatio,
AddPositionPriceRatio: addPosition.AddPositionPriceRatio,
AddPositionType: addPosition.AddPositionType,
AddPositionVal: addPosition.AddPositionVal,
}
preOrderExts = append(preOrderExts, ext)
}
//事务添加
e.Orm.Transaction(func(tx *gorm.DB) error {
err := tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&AddOrder).Error
if err != nil {
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", id, req.Symbol))
return err
}
preOrderStatus.OrderId = AddOrder.Id
//加仓、减仓状态
tx.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus)
for index := range preOrderExts {
if index == 0 {
preOrderExts[index].OrderId = AddOrder.Id
}
preOrderExts[index].MainOrderId = AddOrder.Id
}
list := dto.PreOrderRedisList{
Id: AddOrder.Id,
Symbol: AddOrder.Symbol,
Price: AddOrder.Price,
Site: AddOrder.Site,
ApiId: AddOrder.ApiId,
OrderSn: AddOrder.OrderSn,
QuoteSymbol: AddOrder.QuoteSymbol,
}
marshal, _ := sonic.Marshal(&list)
var preKey string
if AddOrder.SymbolType == global.SYMBOL_SPOT {
preKey = fmt.Sprintf(rediskey.PreSpotOrderList, AddOrder.ExchangeType)
} else {
preKey = fmt.Sprintf(rediskey.PreFutOrderList, AddOrder.ExchangeType)
}
helper.DefaultRedis.LPushList(preKey, string(marshal))
//是否有止盈止损订单
if req.Profit != "" {
if strings.ToUpper(req.Site) == "BUY" {
profitOrder.Site = "SELL"
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
} else {
profitOrder.Site = "BUY"
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
}
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
profitOrder.Pid = AddOrder.Id
profitOrder.OrderType = 1
profitOrder.Status = 0
profitOrder.Rate = req.Profit
profitOrder.MainId = AddOrder.Id
tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&profitOrder)
}
if req.ReducePriceRatio.Cmp(decimal.Zero) > 0 {
if strings.ToUpper(req.Site) == "BUY" {
stopOrder.Site = "SELL"
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Sub(req.ReducePriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
} else {
stopOrder.Site = "BUY"
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Add(req.ReducePriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
}
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
stopOrder.Pid = AddOrder.Id
stopOrder.MainId = AddOrder.Id
stopOrder.OrderType = 4
stopOrder.Status = 0
stopOrder.Rate = req.ReducePriceRatio.String()
tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&stopOrder)
}
return nil
})
}
return nil
}
// CheckRepeatOrder 检查重复下单 检查基础货币
func (e *LinePreOrder) CheckRepeatOrder(orderType int, apiUserId, site, baseCoin string) int64 {
var count int64
e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND symbol like ? AND order_type = ? AND site = ? AND `status` IN (1,5)", apiUserId, baseCoin+"%", orderType, site).Count(&count)
return count
}
// AddBatchPreOrder 批量添加
func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p *actions.DataPermission, errs *[]error) error {
if batchReq.SaveTemplate == "2" || batchReq.SaveTemplate == "1" { //2 = 只保存模板 1= 保存模板并下单
var templateLog dto.LineBatchAddPreOrderReq
copier.Copy(&templateLog, batchReq)
//templateLog = *batchReq
templateLog.SaveTemplate = "0"
templateLog.TemplateName = ""
marshal, _ := sonic.Marshal(templateLog)
saveTemplateParams := models.LineOrderTemplateLogs{
Name: batchReq.TemplateName,
UserId: 0,
Params: string(marshal),
Type: 2,
Switch: "0",
}
e.Orm.Model(&models.LineOrderTemplateLogs{}).Create(&saveTemplateParams)
}
if batchReq.SaveTemplate == "2" {
return nil
}
if batchReq.SymbolGroupId != "" {
var symbolGroupInfo models.LineSymbolGroup
e.Orm.Model(&models.LineSymbolGroup{}).Where("id = ?", utility.StringToInt(batchReq.SymbolGroupId)).Find(&symbolGroupInfo)
if symbolGroupInfo.Id <= 0 || symbolGroupInfo.Symbol == "" {
*errs = append(*errs, errors.New(fmt.Sprintf("选择的交易对组:%s不存在或交易对组的交易对为空", batchReq.SymbolGroupId)))
return nil
}
batchReq.Symbol = symbolGroupInfo.Symbol
}
//脚本次数
if batchReq.OrderNum > 0 {
var tickerSymbol string
if batchReq.SymbolType == global.SYMBOL_SPOT {
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
} else {
tickerSymbol = helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val()
}
apiUserIds := strings.Split(batchReq.ApiUserId, ",")
if batchReq.Script == "1" {
//scriptLogs := make([]models.LinePreScript, 0)
logParams := *batchReq
for _, id := range apiUserIds {
for j := 1; j <= batchReq.OrderNum; j++ {
var log models.LinePreScript
logParams.SaveTemplate = "0"
logParams.TemplateName = ""
logParams.Script = ""
marshal, _ := sonic.Marshal(logParams)
log.ApiId = int64(utility.StringToInt(id))
log.ScriptNum = int64(j)
log.ScriptParams = string(marshal)
log.AdminId = 0
log.Status = "0"
//scriptLogs = append(scriptLogs, log)
err := e.Orm.Model(&models.LinePreScript{}).Create(&log).Error
if err != nil {
*errs = append(*errs, fmt.Errorf("记录脚本失败:%+v", err.Error()))
return nil
}
helper.DefaultRedis.RPushList(rediskey.PreOrderScriptList, utility.IntToString(log.Id))
}
}
return nil
}
for _, id := range apiUserIds {
for j := 0; j < batchReq.OrderNum; j++ {
symbols := strings.Split(batchReq.Symbol, ",")
for _, symbol := range symbols {
var req dto.LineAddPreOrderReq
req.ExchangeType = batchReq.ExchangeType
req.OrderType = batchReq.OrderType
req.Symbol = symbol
req.ApiUserId = id
req.Site = batchReq.Site
req.BuyPrice = batchReq.BuyPrice
req.PricePattern = batchReq.PricePattern
req.Price = batchReq.Price
req.Profit = batchReq.Profit
// req.StopPrice = batchReq.StopPrice
req.ReducePriceRatio = batchReq.ReducePriceRatio
req.PriceType = batchReq.PriceType
req.CoverType = batchReq.CoverType
req.ExpireHour = batchReq.ExpireHour
req.MainOrderType = batchReq.MainOrderType
req.ReduceNumRatio = batchReq.ReduceNumRatio
req.ReduceStopLossRatio = batchReq.ReduceStopLossRatio
req.ReduceTakeProfitRatio = batchReq.ReduceTakeProfitRatio
e.AddPreOrder(&req, p, errs, tickerSymbol)
}
}
}
return nil
} else {
*errs = append(*errs, errors.New("请选择运行次数"))
return nil
}
}
// QuickAddPreOrder 模板快速下单
func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *actions.DataPermission, errs *[]error) error {
templateLogs := make([]models.LineOrderTemplateLogs, 0)
e.Orm.Model(&models.LineOrderTemplateLogs{}).Where("id in ?", strings.Split(quickReq.Ids, ",")).Find(&templateLogs)
for _, log := range templateLogs {
//单独添加
if log.Type == 1 {
var addPreOrderParams dto.LineAddPreOrderReq
sonic.Unmarshal([]byte(log.Params), &addPreOrderParams)
var tickerSymbol string
if addPreOrderParams.OrderType == global.SYMBOL_SPOT {
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
} else {
tickerSymbol = helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val()
}
err := e.AddPreOrder(&addPreOrderParams, p, errs, tickerSymbol)
if err != nil {
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", addPreOrderParams.ApiUserId, addPreOrderParams.Symbol))
continue
}
}
//批量添加
if log.Type == 2 {
var batchAddPreOrder dto.LineBatchAddPreOrderReq
sonic.Unmarshal([]byte(log.Params), &batchAddPreOrder)
e.AddBatchPreOrder(&batchAddPreOrder, p, errs)
}
}
return nil
}
// Lever 设置杠杆
func (e *LinePreOrder) Lever(req *dto.LeverReq, p *actions.DataPermission, errs *[]error) {
users := make([]models.LineApiUser, 0)
err := e.Orm.Model(&models.LineApiUser{}).Where("id in ? ", strings.Split(req.ApiUserIds, ",")).Find(&users).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
*errs = append(*errs, errors.New(fmt.Sprintf("设置杠杆失败:%+v", err.Error())))
return
}
var symbols string
if req.Symbol != "" {
symbols = req.Symbol
} else {
var symbolGroupInfo models.LineSymbolGroup
e.Orm.Model(&models.LineSymbolGroup{}).Where("id = ?", req.GroupId).Find(&symbolGroupInfo)
symbols = symbolGroupInfo.Symbol
}
if req.IsAll == 1 {
lineSymbols := make([]models.LineSymbol, 0)
futSymbols := make([]string, 0)
e.Orm.Model(&models.LineSymbol{}).Where("type = '2' AND switch = '1'").Find(&lineSymbols)
for _, symbol := range lineSymbols {
futSymbols = append(futSymbols, symbol.Symbol)
}
if len(futSymbols) != 0 {
symbols = strings.Join(futSymbols, ",")
}
}
for _, user := range users {
var client *helper.BinanceClient
if user.UserPass == "" {
client, _ = helper.NewBinanceClient(user.ApiKey, user.ApiSecret, "", user.IpAddress)
} else {
client, _ = helper.NewBinanceClient(user.ApiKey, user.ApiSecret, "socks5", user.UserPass+"@"+user.IpAddress)
}
//client.SendFuturesRequestAuth("/")
symbolsSlice := strings.Split(symbols, ",")
for _, s := range symbolsSlice {
params := map[string]string{
"leverage": utility.IntToString(req.Leverage),
"symbol": s,
}
resp, _, err := client.SendFuturesRequestAuth("/fapi/v1/leverage", "POST", params)
if err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 交易对:%s 设置杠杆失败:%+v", user.Id, s, err.Error())))
continue
}
var dataMap map[string]interface{}
if err := sonic.Unmarshal(resp, &dataMap); err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 交易对:%s 设置杠杆失败:%+v", user.Id, s, err.Error())))
continue
}
if _, ok := dataMap["leverage"]; !ok {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 交易对:%s 设置杠杆失败:%+v", user.Id, s, dataMap["message"])))
continue
}
}
}
return
}
// MarginType 设置仓位模式
func (e *LinePreOrder) MarginType(req *dto.MarginTypeReq, p *actions.DataPermission, errs *[]error) {
users := make([]models.LineApiUser, 0)
err := e.Orm.Model(&models.LineApiUser{}).Where("id in ? ", strings.Split(req.ApiUserIds, ",")).Find(&users).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
*errs = append(*errs, errors.New(fmt.Sprintf("设置杠杆失败:%+v", err.Error())))
return
}
var symbols string
if req.Symbol != "" {
symbols = req.Symbol
} else {
var symbolGroupInfo models.LineSymbolGroup
e.Orm.Model(&models.LineSymbolGroup{}).Where("id = ?", req.GroupId).Find(&symbolGroupInfo)
symbols = symbolGroupInfo.Symbol
}
if req.IsAll == 1 {
lineSymbols := make([]models.LineSymbol, 0)
futSymbols := make([]string, 0)
e.Orm.Model(&models.LineSymbol{}).Where("type = '2' AND switch = '1'").Find(&lineSymbols)
for _, symbol := range lineSymbols {
futSymbols = append(futSymbols, symbol.Symbol)
}
if len(futSymbols) != 0 {
symbols = strings.Join(futSymbols, ",")
}
}
for _, user := range users {
var client *helper.BinanceClient
if user.UserPass == "" {
client, _ = helper.NewBinanceClient(user.ApiKey, user.ApiSecret, "", user.IpAddress)
} else {
client, _ = helper.NewBinanceClient(user.ApiKey, user.ApiSecret, "socks5", user.UserPass+"@"+user.IpAddress)
}
//client.SendFuturesRequestAuth("/")
symbolsSlice := strings.Split(symbols, ",")
for _, s := range symbolsSlice {
params := map[string]string{
"marginType": req.MarginType,
"symbol": s,
}
resp, _, err := client.SendFuturesRequestAuth("/fapi/v1/marginType", "POST", params)
if err != nil {
*errs = append(*errs, fmt.Errorf("api_id:%d 交易对:%s 设置仓位失败:%+v", user.Id, s, err.Error()))
continue
}
var dataMap map[string]interface{}
if err := sonic.Unmarshal(resp, &dataMap); err != nil {
*errs = append(*errs, fmt.Errorf("api_id:%d 交易对:%s 设置仓位失败:%+v", user.Id, s, err.Error()))
continue
}
code, ok := dataMap["code"]
if !ok {
*errs = append(*errs, fmt.Errorf("api_id:%d 交易对:%s 设置仓位失败:%+v", user.Id, s, dataMap["message"]))
continue
}
if code.(float64) != 200 {
*errs = append(*errs, fmt.Errorf("api_id:%d 交易对:%s 设置仓位失败:%+v", user.Id, s, dataMap["message"]))
continue
}
}
}
}
// CancelOpenOrder 取消委托
func (e *LinePreOrder) CancelOpenOrder(req *dto.CancelOpenOrderReq, errs *[]error) {
newClientOrderIdList := make([]string, 0)
var apiUserInfo models.LineApiUser
e.Orm.Model(&models.LineApiUser{}).Where("id = ?", req.ApiId).Find(&apiUserInfo)
futApi := binanceservice.FutRestApi{}
spotApi := binanceservice.SpotRestApi{}
//取消指定订单号的委托
if req.OrderSn != "" && req.Symbol != "" {
var err error
var orderInfo models.LinePreOrder
e.Orm.Model(&models.LinePreOrder{}).Where("symbol = ? AND order_sn = ? AND status = '5'", req.Symbol, req.OrderSn).Find(&orderInfo)
if orderInfo.Id <= 0 {
*errs = append(*errs, fmt.Errorf("取消委托失败:%+v", "未找到可以取消的委托"))
return
}
if req.OrderType == 1 { //现货
err = spotApi.CancelOpenOrderByOrderSn(apiUserInfo, req.Symbol, req.OrderSn)
} else {
newClientOrderIdList = append(newClientOrderIdList, req.OrderSn)
err = futApi.CancelBatchFutOrder(apiUserInfo, req.Symbol, newClientOrderIdList)
}
if err != nil {
*errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error()))
return
}
} else {
var orderList []models.LinePreOrder
e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND pid = 0 status = '5' AND order_type = ?", req.ApiId, strconv.Itoa(req.OrderType)).Find(&orderList)
if len(orderList) <= 0 {
*errs = append(*errs, fmt.Errorf("没有可撤销的委托"))
return
}
for _, order := range orderList {
if order.OrderType == global.SYMBOL_SPOT {
err := spotApi.CancelOpenOrderByOrderSn(apiUserInfo, req.Symbol, req.OrderSn)
if err != nil {
*errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error()))
continue
}
} else {
err := futApi.CancelBatchFutOrder(apiUserInfo, order.Symbol, []string{order.OrderSn})
if err != nil {
*errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error()))
continue
}
}
}
}
}
// ClearAll 一键清除数据
func (e *LinePreOrder) ClearAll() error {
_, err := helper.DefaultRedis.BatchDeleteKeys([]string{rediskey.PreSpotOrderList, rediskey.PreFutOrderList})
if err != nil {
e.Log.Errorf("Service RemoveLinePreOrder error:%s \r\n", err)
return err
}
prefixs := []string{
"spot_stoploss_list",
"futures_stoploss_list",
"spot_add_position_list",
"futures_add_position_list",
"api_user_hold",
"spot_trigger_lock",
"fut_trigger_lock",
"fut_trigger_stop_lock",
"spot_trigger_stop_lock",
"spot_addposition_trigger",
"fut_addposition_trigger",
"spot_hedge_close_position",
"futures_hedge_close_position",
"spot_callback",
"fut_callback",
"holde_a",
"holde_b",
"stop_loss_markt",
"_PreSpotOrderList_",
"_PreFutOrderList_",
}
err = helper.DefaultRedis.DeleteKeysByPrefix(prefixs...)
if err != nil {
e.Log.Errorf("Service RemoveLinePreOrder error:%s \r\n", err)
return err
}
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order") //订单表
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_status") //订单拓展状态
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_ext") //订单拓展配置
return err
}
// GetTargetSymbol 获取目标交易对信息
func (e *LinePreOrder) GetTargetSymbol(symbol string, symbolType int) (string, bool, models.LineSymbol, error) {
var targetSymbol string
var notUsdt bool
var symbolInfo models.LineSymbol
// 处理非 USDT 交易对
if !strings.HasSuffix(symbol, "USDT") {
notUsdt = true
if err := e.Orm.Model(&models.LineSymbol{}).Where("symbol = ? AND type = ?", symbol, utility.IntToString(symbolType)).Find(&symbolInfo).Error; err != nil {
return "", false, models.LineSymbol{}, err
}
if symbolInfo.Id <= 0 {
return "", false, models.LineSymbol{}, fmt.Errorf("未找到交易对信息")
}
targetSymbol = symbolInfo.BaseAsset + "USDT"
} else {
targetSymbol = symbol
}
return targetSymbol, notUsdt, symbolInfo, nil
}
func (e *LinePreOrder) GetOrderInfo(req dto.ManuallyCover, symbol, orderType, site, status string) (models.LinePreOrder, error) {
var orderInfo models.LinePreOrder
if err := e.Orm.Model(models.LinePreOrder{}).Where("api_id = ? AND symbol = ? AND order_type = ? AND site = ? AND status = ?", req.ApiId, symbol, orderType, site, status).Find(&orderInfo).Error; err != nil {
return models.LinePreOrder{}, err
}
if orderInfo.Id <= 0 {
return models.LinePreOrder{}, fmt.Errorf("未找到主仓信息")
}
return orderInfo, nil
}
func (e *LinePreOrder) GetFutOrderInfo(req dto.ManuallyCover, symbol, orderType, status string) (models.LinePreOrder, error) {
var orderInfo models.LinePreOrder
if err := e.Orm.Model(models.LinePreOrder{}).Where("api_id = ? AND symbol = ? AND order_type = ? AND status = ? AND cover_type = 2", req.ApiId, symbol, orderType, status).Find(&orderInfo).Error; err != nil {
return models.LinePreOrder{}, err
}
if orderInfo.Id <= 0 {
return models.LinePreOrder{}, fmt.Errorf("未找到主仓信息")
}
return orderInfo, nil
}
// GetFutSpotOrderInfo 获取合约对现货的订单信息
func (e *LinePreOrder) GetFutSpotOrderInfo(req dto.ManuallyCover, symbol, orderType, status string) (models.LinePreOrder, error) {
var orderInfo models.LinePreOrder
if err := e.Orm.Model(models.LinePreOrder{}).Where("api_id = ? AND symbol = ? AND order_type = ? AND status = ? AND cover_type = 3", req.ApiId, symbol, orderType, status).Find(&orderInfo).Error; err != nil {
return models.LinePreOrder{}, err
}
if orderInfo.Id <= 0 {
return models.LinePreOrder{}, fmt.Errorf("未找到主仓信息")
}
return orderInfo, nil
}
// CalculateAmount 计算加仓数量
func (e *LinePreOrder) CalculateAmount(req dto.ManuallyCover, totalNum, lastPrice decimal.Decimal, amountDigit int, notUsdt bool, symbolInfo models.LineSymbol) (decimal.Decimal, error) {
var amt decimal.Decimal
if req.CoverType == 1 {
decimalValue := utility.StringToDecimal(req.Value).Div(decimal.NewFromInt(100))
amt = totalNum.Mul(decimalValue)
} else {
decimalValue := utility.StringToDecimal(req.Value)
if notUsdt {
tickerSymbolMaps := make([]dto.Ticker, 0)
tickerSymbol := helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
if err := sonic.Unmarshal([]byte(tickerSymbol), &tickerSymbolMaps); err != nil {
return decimal.Zero, err
}
var tickerPrice decimal.Decimal
for _, symbolMap := range tickerSymbolMaps {
if symbolMap.Symbol == strings.ToUpper(symbolInfo.BaseAsset+"USDT") {
tickerPrice, _ = decimal.NewFromString(symbolMap.Price)
break
}
}
for _, symbolMap := range tickerSymbolMaps {
if symbolMap.Symbol == strings.ToUpper(symbolInfo.QuoteAsset+"USDT") {
uTickerPrice, _ := decimal.NewFromString(symbolMap.Price)
div := tickerPrice.Div(decimal.NewFromInt(1).Div(uTickerPrice))
amt = decimalValue.Div(div)
break
}
}
} else {
amt = decimalValue.Div(lastPrice)
}
}
return amt.Truncate(int32(amountDigit)), nil
}
// SpotClosePosition 现货单个交易对平仓
func (e *LinePreOrder) SpotClosePosition(position *dto.ClosePosition, errs *[]error) {
var apiUserInfo models.LineApiUser
e.Orm.Model(&models.LineApiUser{}).Where("id = ?", position.ApiId).Find(&apiUserInfo)
client := binanceservice.GetClient(&apiUserInfo)
resp, _, err := client.SendSpotAuth("/api/v3/account", "GET", map[string]interface{}{
"omitZeroBalances": true,
})
if err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 获取账户信息失败", position.ApiId)))
return
}
var balanceInfo binanceservice.SpotAccountInfo
sonic.Unmarshal(resp, &balanceInfo)
if len(balanceInfo.Balances) == 0 {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 没有可平仓的交易对", position.ApiId)))
}
//查询已经开仓的现货交易对
var spotList []models.LinePreOrder
if position.Symbol == "" { //全平
e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND status = 6 AND pid = 0 AND order_type = 0", position.ApiId).Find(&spotList)
} else {
e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND symbol = ? AND status = 6 AND pid = 0 AND order_type = 0", position.ApiId, position.Symbol).Find(&spotList)
}
if len(spotList) <= 0 {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 没有可平仓的交易对", position.ApiId)))
}
api := binanceservice.SpotRestApi{}
for _, list := range spotList {
for _, balance := range balanceInfo.Balances {
suffix := utility.ReplaceSuffix(list.Symbol, list.QuoteSymbol, "")
if utility.StringToDecimal(balance.Free).GreaterThan(decimal.Zero) && balance.Asset == suffix {
//锁仓数量大于0
if utility.StringToDecimal(balance.Locked).GreaterThan(decimal.Zero) {
//撤销之前的委托
client.SendSpotAuth("/api/v3/openOrders", "DELETE", map[string]string{
"symbol": list.Symbol,
})
}
key := fmt.Sprintf(global.TICKER_SPOT, list.ExchangeType, list.Symbol)
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key)
total := utility.StringToDecimal(balance.Free).Add(utility.StringToDecimal(balance.Locked)).Truncate(int32(tradeSet.AmountDigit))
lastPrice := api.GetSpotSymbolLastPrice(list.Symbol)
var price decimal.Decimal
paramsMaps := make(map[string]string)
if total.GreaterThan(decimal.NewFromFloat(tradeSet.MinQty)) {
paramsMaps = map[string]string{
"symbol": list.Symbol,
"side": "SELL",
"quantity": total.String(),
"type": "LIMIT",
"newClientOrderId": utility.Int64ToString(snowflakehelper.GetOrderId()),
"timeInForce": "GTC",
}
price = lastPrice.Mul(decimal.NewFromInt(1).Sub(utility.StringToDecimal(position.Rate).Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
paramsMaps["price"] = price.String()
} else {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 下单数量小于最小下单数量", position.ApiId)))
continue
}
order := models.LinePreOrder{
ExchangeType: global.EXCHANGE_BINANCE,
Pid: list.Id,
ApiId: list.ApiId,
GroupId: "0",
Symbol: list.Symbol,
QuoteSymbol: list.QuoteSymbol,
SignPrice: lastPrice.String(),
SignPriceType: "new",
Rate: position.Rate,
Price: price.String(),
Num: total.String(),
BuyPrice: "0",
Site: "SELL",
OrderSn: paramsMaps["newClientOrderId"],
OrderType: 3,
Desc: "",
Status: 0,
CoverType: list.CoverType,
ExpireTime: time.Now().Add(time.Hour * 24 * 30),
MainOrderType: list.MainOrderType,
Child: nil,
}
err := e.Orm.Model(&models.LinePreOrder{}).Create(&order).Error
if err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 生成订单失败:%s", position.ApiId, err.Error())))
continue
}
//下订单
_, _, err = client.SendSpotAuth("/api/v3/order", "POST", paramsMaps)
if err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("api_id:%d 币安下订单失败:%s", position.ApiId, err.Error())))
continue
}
binanceservice.MainClosePositionClearCache(list.Id, list.CoverType)
}
}
}
}
// FutClosePosition 合约平仓
func (e *LinePreOrder) FutClosePosition(position *dto.ClosePosition, errs *[]error) {
var apiUserInfo models.LineApiUser
e.Orm.Model(&models.LineApiUser{}).Where("id = ?", position.ApiId).Find(&apiUserInfo)
//client := binanceservice.GetClient(&apiUserInfo)
//查询已经开仓的合约交易对
var futList []models.LinePreOrder
if position.Symbol == "" {
e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND status = 6 AND order_category=2 AND order_type =0", position.ApiId).Find(&futList)
} else {
e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND symbol = ? AND status = 6 AND order_category=2 AND order_type = 0", position.ApiId, position.Symbol).Find(&futList)
}
if len(futList) <= 0 {
*errs = append(*errs, fmt.Errorf("api_id:%d 没有可平仓的交易对", position.ApiId))
return
}
api := binanceservice.FutRestApi{}
for _, list := range futList {
risks, err := api.GetPositionV3(&apiUserInfo, list.Symbol)
if err != nil {
*errs = append(*errs, fmt.Errorf("api_id:%d 获取仓位信息时 没有可平仓的交易对 err: %s", position.ApiId, err))
continue
}
key := fmt.Sprintf(global.TICKER_FUTURES, list.ExchangeType, list.Symbol)
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key)
lastPrice := api.GetFutSymbolLastPrice(list.Symbol)
parentId := list.Id
if list.Pid > 0 {
parentId = list.Pid
}
for _, risk := range risks {
positionAmt := utility.StringToDecimal(risk.PositionAmt)
var riskSide string
var orderSide string
if positionAmt.GreaterThan(decimal.Zero) {
riskSide = "BUY"
} else {
riskSide = "SELL"
}
if riskSide == list.Site {
var price decimal.Decimal
if list.Site == "BUY" && risk.PositionSide == "LONG" { //做多
//根据仓位数量去平多
orderSide = "SELL"
price = lastPrice.Mul(decimal.NewFromInt(1).Add(utility.StringToDecimal(position.Rate).Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
} else if list.Site == "SELL" && risk.PositionSide == "SHORT" {
orderSide = "BUY"
price = lastPrice.Mul(decimal.NewFromInt(1).Sub(utility.StringToDecimal(position.Rate).Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
}
if price.LessThanOrEqual(decimal.Zero) {
continue
}
if positionAmt.Abs().LessThanOrEqual(decimal.NewFromFloat(tradeSet.MinQty)) {
*errs = append(*errs, fmt.Errorf("api_id:%d 下单数量小于最小下单数量", position.ApiId))
continue
}
order := models.LinePreOrder{
Pid: parentId,
ApiId: list.ApiId,
GroupId: "0",
Symbol: list.Symbol,
QuoteSymbol: list.QuoteSymbol,
SignPrice: lastPrice.String(),
SignPriceType: "new",
Rate: position.Rate,
Price: price.String(),
Num: positionAmt.Abs().String(),
BuyPrice: "0",
Site: orderSide,
OrderSn: utility.Int64ToString(snowflakehelper.GetOrderId()),
OrderType: 3,
Desc: "",
Status: 0,
CoverType: list.CoverType,
ExpireTime: time.Now().Add(24 * 30 * time.Hour),
MainOrderType: list.MainOrderType,
Child: nil,
}
err = e.Orm.Model(&models.LinePreOrder{}).Create(&order).Error
if err != nil {
*errs = append(*errs, fmt.Errorf("api_id:%d 生成平仓单错误:%s", position.ApiId, err))
continue
}
//撤销合约的委托
api.CancelAllFutOrder(apiUserInfo, list.Symbol)
//side=BUY&positionSide=LONG是开多
//side=SELL&positionSide=LONG是平多
//side=SELL&positionSide=SHORT是开空
//side=BUY&positionSide=SHORT是平空。
if orderSide != "" {
if orderSide == "BUY" { //平空
err = api.ClosePosition(list.Symbol, order.OrderSn, utility.StringToDecimal(order.Num), "BUY", "SHORT", apiUserInfo, "LIMIT", "0", price)
} else { // 平多
err = api.ClosePosition(list.Symbol, order.OrderSn, utility.StringToDecimal(order.Num), "SELL", "LONG", apiUserInfo, "LIMIT", "0", price)
}
if err != nil {
*errs = append(*errs, fmt.Errorf("api_id:%d 币安平仓单错误:%s", position.ApiId, err))
continue
}
// 主单平仓删除缓存
binanceservice.MainClosePositionClearCache(list.Id, list.CoverType)
}
}
}
}
}
// ClearUnTriggered 清除待触发的交易对
func (e *LinePreOrder) ClearUnTriggered() error {
var orderLists []models.LinePreOrder
e.Orm.Model(&models.LinePreOrder{}).Where("pid = 0 AND status = '0'").Find(&orderLists).Unscoped().Delete(&models.LinePreOrder{})
for _, order := range orderLists {
redisList := dto.PreOrderRedisList{
Id: order.Id,
Symbol: order.Symbol,
Price: order.Price,
Site: order.Site,
ApiId: order.ApiId,
OrderSn: order.OrderSn,
QuoteSymbol: order.QuoteSymbol,
}
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol))
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))
}
e.Orm.Model(&models.LinePreOrder{}).Where("pid = ?", order.Id).Unscoped().Delete(&models.LinePreOrder{})
}
return nil
}
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)
var client *helper.BinanceClient
if apiUserInfo.UserPass == "" {
client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress)
} else {
client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress)
}
params := map[string]string{"symbol": req.Symbol, "origClientOrderId": req.OrderSn}
if req.OrderType == 1 { //现货
var resp dto.QuickAddPreOrderReq
auth, code, err := client.SendSpotAuth("/api/v3/order", "GET", params)
if code != 200 {
return nil, err
}
if err != nil {
return nil, err
}
sonic.Unmarshal(auth, &resp)
return resp, nil
}
if req.OrderType == 2 {
var resp dto.FutQueryOrderResp
auth, code, err := client.SendFuturesRequestAuth("/fapi/v1/order", "GET", params)
if code != 200 {
return nil, err
}
if err != nil {
return nil, err
}
sonic.Unmarshal(auth, &resp)
return resp, nil
}
return nil, err
}