1撤销限价后 市价分单
This commit is contained in:
@ -52,11 +52,11 @@ func (e LineApiUser) GetPage(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, apiUser := range list {
|
// for i, apiUser := range list {
|
||||||
if apiUser.UserId <= 0 {
|
// if apiUser.UserId <= 0 {
|
||||||
list[i].OpenStatus = 1
|
// list[i].OpenStatus = 1
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
||||||
}
|
}
|
||||||
|
|||||||
225
app/admin/apis/line_api_user_group.go
Normal file
225
app/admin/apis/line_api_user_group.go
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
package apis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/api"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
|
||||||
|
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
|
||||||
|
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineApiUserGroup struct {
|
||||||
|
api.Api
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取api用户分组列表
|
||||||
|
// @Summary 获取api用户分组列表
|
||||||
|
// @Description 获取api用户分组列表
|
||||||
|
// @Tags api用户分组
|
||||||
|
// @Param groupName query string false "分组名称"
|
||||||
|
// @Param pageSize query int false "页条数"
|
||||||
|
// @Param pageIndex query int false "页码"
|
||||||
|
// @Success 200 {object} response.Response{data=response.Page{list=[]models.LineApiUserGroup}} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-api-user-group [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineApiUserGroup) GetPage(c *gin.Context) {
|
||||||
|
req := dto.LineApiUserGroupGetPageReq{}
|
||||||
|
s := service.LineApiUserGroup{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
list := make([]models.LineApiUserGroup, 0)
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
err = s.GetPage(&req, p, &list, &count)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取api用户分组失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取api用户分组
|
||||||
|
// @Summary 获取api用户分组
|
||||||
|
// @Description 获取api用户分组
|
||||||
|
// @Tags api用户分组
|
||||||
|
// @Param id path int false "id"
|
||||||
|
// @Success 200 {object} response.Response{data=models.LineApiUserGroup} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-api-user-group/{id} [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineApiUserGroup) Get(c *gin.Context) {
|
||||||
|
req := dto.LineApiUserGroupGetReq{}
|
||||||
|
s := service.LineApiUserGroup{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var object models.LineApiUserGroup
|
||||||
|
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
err = s.Get(&req, p, &object)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取api用户分组失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(object, "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建api用户分组
|
||||||
|
// @Summary 创建api用户分组
|
||||||
|
// @Description 创建api用户分组
|
||||||
|
// @Tags api用户分组
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.LineApiUserGroupInsertReq true "data"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
|
||||||
|
// @Router /api/v1/line-api-user-group [post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineApiUserGroup) Insert(c *gin.Context) {
|
||||||
|
req := dto.LineApiUserGroupInsertReq{}
|
||||||
|
s := service.LineApiUserGroup{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 设置创建人
|
||||||
|
req.SetCreateBy(user.GetUserId(c))
|
||||||
|
|
||||||
|
if err := req.Valid(); err != nil {
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.Insert(&req)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("创建api用户分组失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(req.GetId(), "创建成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改api用户分组
|
||||||
|
// @Summary 修改api用户分组
|
||||||
|
// @Description 修改api用户分组
|
||||||
|
// @Tags api用户分组
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param id path int true "id"
|
||||||
|
// @Param data body dto.LineApiUserGroupUpdateReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
|
||||||
|
// @Router /api/v1/line-api-user-group/{id} [put]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineApiUserGroup) Update(c *gin.Context) {
|
||||||
|
req := dto.LineApiUserGroupUpdateReq{}
|
||||||
|
s := service.LineApiUserGroup{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.SetUpdateBy(user.GetUserId(c))
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
|
||||||
|
if err := req.Valid(); err != nil {
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.Update(&req, p)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("修改api用户分组失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(req.GetId(), "修改成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除api用户分组
|
||||||
|
// @Summary 删除api用户分组
|
||||||
|
// @Description 删除api用户分组
|
||||||
|
// @Tags api用户分组
|
||||||
|
// @Param data body dto.LineApiUserGroupDeleteReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
|
||||||
|
// @Router /api/v1/line-api-user-group [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineApiUserGroup) Delete(c *gin.Context) {
|
||||||
|
s := service.LineApiUserGroup{}
|
||||||
|
req := dto.LineApiUserGroupDeleteReq{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// req.SetUpdateBy(user.GetUserId(c))
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
|
||||||
|
err = s.Remove(&req, p)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("删除api用户分组失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(req.GetId(), "删除成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e LineApiUserGroup) GetOptions(c *gin.Context) {
|
||||||
|
s := service.LineApiUserGroup{}
|
||||||
|
req := dto.LineApiUserGroupGetOptionsReq{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
var datas []dto.LineApiUserGroupOptions
|
||||||
|
if err = s.GetOptions(&req, &datas, p); err != nil {
|
||||||
|
e.Error(500, err, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(datas, "查询成功")
|
||||||
|
}
|
||||||
@ -296,23 +296,27 @@ func (e LinePreOrder) AddPreOrder(c *gin.Context) {
|
|||||||
req.SetCreateBy(userId)
|
req.SetCreateBy(userId)
|
||||||
errs := make([]error, 0)
|
errs := make([]error, 0)
|
||||||
errStr := make([]string, 0)
|
errStr := make([]string, 0)
|
||||||
|
var msg string
|
||||||
var tickerSymbol string
|
var tickerSymbol string
|
||||||
if req.SymbolType == global.SYMBOL_SPOT {
|
if req.SymbolType == global.SYMBOL_SPOT {
|
||||||
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
|
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
|
||||||
} else {
|
} else {
|
||||||
tickerSymbol = helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val()
|
tickerSymbol = helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val()
|
||||||
}
|
}
|
||||||
s.AddPreOrder(&req, p, &errs, tickerSymbol)
|
if err := s.AddPreOrderCheck(&req, p, &errs, tickerSymbol); err != nil {
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
//e.Logger.Error(err)
|
|
||||||
for _, err2 := range errs {
|
for _, err2 := range errs {
|
||||||
errStr = append(errStr, err2.Error())
|
errStr = append(errStr, err2.Error())
|
||||||
}
|
}
|
||||||
e.Error(500, nil, strings.Join(errStr, ","))
|
|
||||||
return
|
msg = strings.Join(errStr, ",")
|
||||||
}
|
}
|
||||||
e.OK(nil, "操作成功")
|
|
||||||
|
e.OK(msg, "操作成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 手动加仓
|
// // 手动加仓
|
||||||
@ -368,22 +372,26 @@ func (e LinePreOrder) BatchAddOrder(c *gin.Context) {
|
|||||||
errs := make([]error, 0)
|
errs := make([]error, 0)
|
||||||
errStr := make([]string, 0)
|
errStr := make([]string, 0)
|
||||||
userId := user.GetUserId(c)
|
userId := user.GetUserId(c)
|
||||||
|
var msg string
|
||||||
if userId <= 0 {
|
if userId <= 0 {
|
||||||
e.Error(500, nil, "用户不存在")
|
e.Error(500, nil, "用户不存在")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.SetCreateBy(userId)
|
req.SetCreateBy(userId)
|
||||||
s.AddBatchPreOrder(&req, p, &errs)
|
if err := s.AddBatchPreOrder(&req, p, &errs); err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
//e.Logger.Error(err)
|
//e.Logger.Error(err)
|
||||||
for _, err2 := range errs {
|
for _, err2 := range errs {
|
||||||
errStr = append(errStr, err2.Error())
|
errStr = append(errStr, err2.Error())
|
||||||
}
|
}
|
||||||
e.Error(500, nil, strings.Join(errStr, ","))
|
msg = strings.Join(errStr, ",")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
e.OK(nil, "操作成功")
|
e.OK(msg, "操作成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuickAddPreOrder 模板快速下单
|
// QuickAddPreOrder 模板快速下单
|
||||||
@ -409,22 +417,27 @@ func (e LinePreOrder) QuickAddPreOrder(c *gin.Context) {
|
|||||||
errs := make([]error, 0)
|
errs := make([]error, 0)
|
||||||
errStr := make([]string, 0)
|
errStr := make([]string, 0)
|
||||||
userId := user.GetUserId(c)
|
userId := user.GetUserId(c)
|
||||||
|
var msg string
|
||||||
|
|
||||||
if userId <= 0 {
|
if userId <= 0 {
|
||||||
e.Error(500, nil, "用户不存在")
|
e.Error(500, nil, "用户不存在")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.QuickAddPreOrder(&req, p, userId, &errs)
|
if err := s.QuickAddPreOrder(&req, p, userId, &errs); err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
//e.Logger.Error(err)
|
//e.Logger.Error(err)
|
||||||
for _, err2 := range errs {
|
for _, err2 := range errs {
|
||||||
errStr = append(errStr, err2.Error())
|
errStr = append(errStr, err2.Error())
|
||||||
}
|
}
|
||||||
e.Error(500, nil, strings.Join(errStr, ","))
|
|
||||||
return
|
msg = strings.Join(errStr, ",")
|
||||||
}
|
}
|
||||||
e.OK(nil, "操作成功")
|
e.OK(msg, "操作成功")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -113,6 +113,7 @@ func (e SysConfig) Insert(c *gin.Context) {
|
|||||||
e.Error(500, err, "创建失败")
|
e.Error(500, err, "创建失败")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
e.OK(req.GetId(), "创建成功")
|
e.OK(req.GetId(), "创建成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
31
app/admin/models/line_api_user_group.go
Normal file
31
app/admin/models/line_api_user_group.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineApiUserGroup struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
ExchangeType string `json:"exchangeType" gorm:"type:varchar(30);comment:交易所"`
|
||||||
|
GroupName string `json:"groupName" gorm:"type:varchar(30);comment:分组名称"`
|
||||||
|
UserId string `json:"userId" gorm:"type:text;comment:用户ids 逗号分割"`
|
||||||
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"`
|
||||||
|
UserIds []int `json:"userIds" gorm:"-"`
|
||||||
|
Count int `json:"count" gorm:"-"`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (LineApiUserGroup) TableName() string {
|
||||||
|
return "line_api_user_group"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineApiUserGroup) Generate() models.ActiveRecord {
|
||||||
|
o := *e
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineApiUserGroup) GetId() interface{} {
|
||||||
|
return e.Id
|
||||||
|
}
|
||||||
@ -40,6 +40,7 @@ type LinePreOrder struct {
|
|||||||
ChildNum int64 `json:"child_num" gorm:"->"`
|
ChildNum int64 `json:"child_num" gorm:"->"`
|
||||||
AddPositionStatus int `json:"add_position_status" gorm:"->"`
|
AddPositionStatus int `json:"add_position_status" gorm:"->"`
|
||||||
ReduceStatus int `json:"reduce_status" gorm:"->"`
|
ReduceStatus int `json:"reduce_status" gorm:"->"`
|
||||||
|
Childs []LinePreOrder `json:"childs" gorm:"foreignKey:pid;references:id"`
|
||||||
// LinePreOrder 线上预埋单\
|
// LinePreOrder 线上预埋单\
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
|
|||||||
29
app/admin/router/line_api_user_group.go
Normal file
29
app/admin/router/line_api_user_group.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
||||||
|
|
||||||
|
"go-admin/app/admin/apis"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
"go-admin/common/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
routerCheckRole = append(routerCheckRole, registerLineApiUserGroupRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerLineApiUserGroupRouter
|
||||||
|
func registerLineApiUserGroupRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||||
|
api := apis.LineApiUserGroup{}
|
||||||
|
r := v1.Group("/line-api-user-group").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
|
||||||
|
{
|
||||||
|
r.GET("", actions.PermissionAction(), api.GetPage)
|
||||||
|
r.GET("/:id", actions.PermissionAction(), api.Get)
|
||||||
|
r.POST("", api.Insert)
|
||||||
|
r.PUT("/:id", actions.PermissionAction(), api.Update)
|
||||||
|
r.DELETE("", api.Delete)
|
||||||
|
|
||||||
|
r.GET("/options", actions.PermissionAction(), api.GetOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@ import (
|
|||||||
type LineApiUserGetPageReq struct {
|
type LineApiUserGetPageReq struct {
|
||||||
dto.Pagination `search:"-"`
|
dto.Pagination `search:"-"`
|
||||||
ExchangeType string `form:"exchangeType" search:"-"`
|
ExchangeType string `form:"exchangeType" search:"-"`
|
||||||
|
OpenStatus *int `form:"openStatus" search:"-" comment:"开启状态 0-关闭 1-开启"`
|
||||||
LineApiUserOrder
|
LineApiUserOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
151
app/admin/service/dto/line_api_user_group.go
Normal file
151
app/admin/service/dto/line_api_user_group.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/dto"
|
||||||
|
common "go-admin/common/models"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineApiUserGroupGetPageReq struct {
|
||||||
|
dto.Pagination `search:"-"`
|
||||||
|
GroupName string `form:"groupName" search:"type:contains;column:group_name;table:line_api_user_group" comment:"分组名称"`
|
||||||
|
LineApiUserGroupOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineApiUserGroupOrder struct {
|
||||||
|
Id string `form:"idOrder" search:"type:order;column:id;table:line_api_user_group"`
|
||||||
|
GroupName string `form:"groupNameOrder" search:"type:order;column:group_name;table:line_api_user_group"`
|
||||||
|
UserId string `form:"userIdOrder" search:"type:order;column:user_id;table:line_api_user_group"`
|
||||||
|
Status string `form:"statusOrder" search:"type:order;column:status;table:line_api_user_group"`
|
||||||
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:line_api_user_group"`
|
||||||
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:line_api_user_group"`
|
||||||
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:line_api_user_group"`
|
||||||
|
CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:line_api_user_group"`
|
||||||
|
UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:line_api_user_group"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LineApiUserGroupGetPageReq) GetNeedSearch() interface{} {
|
||||||
|
return *m
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineApiUserGroupInsertReq struct {
|
||||||
|
Id int `json:"-" comment:"组件"` // 组件
|
||||||
|
ExchangeType string `json:"exchangeType" comment:"交易类型"`
|
||||||
|
|
||||||
|
GroupName string `json:"groupName" comment:"分组名称"`
|
||||||
|
UserId string `json:"userId" comment:"用户ids 逗号分割"`
|
||||||
|
UserIds []int `json:"userIds" comment:"用户ids"`
|
||||||
|
Status int `json:"status" comment:"状态 1-启用 2-禁用"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineApiUserGroupInsertReq) Valid() error {
|
||||||
|
if s.ExchangeType == "" {
|
||||||
|
return errors.New("交易类型不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.GroupName == "" {
|
||||||
|
return errors.New("分组名称不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.UserIds) == 0 {
|
||||||
|
return errors.New("用户不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineApiUserGroupInsertReq) Generate(model *models.LineApiUserGroup) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
strIds := make([]string, len(s.UserIds))
|
||||||
|
for i, id := range s.UserIds {
|
||||||
|
strIds[i] = strconv.Itoa(id)
|
||||||
|
}
|
||||||
|
model.GroupName = s.GroupName
|
||||||
|
model.ExchangeType = s.ExchangeType
|
||||||
|
model.UserId = strings.Join(strIds, ",")
|
||||||
|
model.Status = s.Status
|
||||||
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineApiUserGroupInsertReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineApiUserGroupUpdateReq struct {
|
||||||
|
Id int `uri:"id" comment:"组件"` // 组件
|
||||||
|
ExchangeType string `json:"exchangeType" comment:"交易类型"`
|
||||||
|
GroupName string `json:"groupName" comment:"分组名称"`
|
||||||
|
UserId string `json:"userId" comment:"用户ids 逗号分割"`
|
||||||
|
UserIds []int `json:"userIds" comment:"用户ids"`
|
||||||
|
Status int `json:"status" comment:"状态 1-启用 2-禁用"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineApiUserGroupUpdateReq) Valid() error {
|
||||||
|
if s.ExchangeType == "" {
|
||||||
|
return errors.New("交易类型不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.GroupName == "" {
|
||||||
|
return errors.New("分组名称不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.UserIds) == 0 {
|
||||||
|
return errors.New("用户不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (s *LineApiUserGroupUpdateReq) Generate(model *models.LineApiUserGroup) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
strIds := make([]string, len(s.UserIds))
|
||||||
|
for i, id := range s.UserIds {
|
||||||
|
strIds[i] = strconv.Itoa(id)
|
||||||
|
}
|
||||||
|
model.GroupName = s.GroupName
|
||||||
|
model.ExchangeType = s.ExchangeType
|
||||||
|
model.UserId = strings.Join(strIds, ",")
|
||||||
|
model.Status = s.Status
|
||||||
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineApiUserGroupUpdateReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineApiUserGroupGetReq 功能获取请求参数
|
||||||
|
type LineApiUserGroupGetReq struct {
|
||||||
|
Id int `uri:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineApiUserGroupGetReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineApiUserGroupDeleteReq 功能删除请求参数
|
||||||
|
type LineApiUserGroupDeleteReq struct {
|
||||||
|
Ids []int `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineApiUserGroupDeleteReq) GetId() interface{} {
|
||||||
|
return s.Ids
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineApiUserGroupGetOptionsReq struct {
|
||||||
|
ExchangeType string `form:"exchangeType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineApiUserGroupOptions struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Value []int `json:"value"`
|
||||||
|
Disabled bool `json:"disabled"`
|
||||||
|
}
|
||||||
@ -187,6 +187,8 @@ type LineAddPreOrderReq struct {
|
|||||||
OrderType int `json:"order_type"` //订单类型
|
OrderType int `json:"order_type"` //订单类型
|
||||||
Symbol string `json:"symbol"` //交易对
|
Symbol string `json:"symbol"` //交易对
|
||||||
ApiUserId string `json:"api_id" ` //下单用户
|
ApiUserId string `json:"api_id" ` //下单用户
|
||||||
|
ApiIdType int `json:"api_id_type"` //下单用户类型
|
||||||
|
ApiUserGroupId int `json:"api_user_group_id"` //下单用户组
|
||||||
Site string `json:"site" ` //购买方向
|
Site string `json:"site" ` //购买方向
|
||||||
BuyPrice string `json:"buy_price" vd:"$>0"` //购买金额 U
|
BuyPrice string `json:"buy_price" vd:"$>0"` //购买金额 U
|
||||||
PricePattern string `json:"price_pattern"` //价格模式
|
PricePattern string `json:"price_pattern"` //价格模式
|
||||||
@ -368,6 +370,8 @@ type LineBatchAddPreOrderReq struct {
|
|||||||
SymbolGroupId string `json:"symbol_group_id"` //交易对组id
|
SymbolGroupId string `json:"symbol_group_id"` //交易对组id
|
||||||
Symbol string `json:"symbol"` //交易对
|
Symbol string `json:"symbol"` //交易对
|
||||||
ApiUserId string `json:"api_id"` //下单用户
|
ApiUserId string `json:"api_id"` //下单用户
|
||||||
|
ApiIdType int `json:"api_id_type"` //下单用户类型
|
||||||
|
ApiUserGroupId int `json:"api_user_group_id"` //下单用户组
|
||||||
Site string `json:"site"` //购买方向
|
Site string `json:"site"` //购买方向
|
||||||
BuyPrice string `json:"buy_price"` //购买金额 U
|
BuyPrice string `json:"buy_price"` //购买金额 U
|
||||||
PricePattern string `json:"price_pattern"` //价格模式
|
PricePattern string `json:"price_pattern"` //价格模式
|
||||||
|
|||||||
@ -40,6 +40,10 @@ func (e *LineApiUser) GetPage(c *dto.LineApiUserGetPageReq, p *actions.DataPermi
|
|||||||
query.Where("exchange_type = ?", c.ExchangeType)
|
query.Where("exchange_type = ?", c.ExchangeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.OpenStatus != nil {
|
||||||
|
query.Where("open_status = ?", c.OpenStatus)
|
||||||
|
}
|
||||||
|
|
||||||
err = query.
|
err = query.
|
||||||
Find(list).Limit(-1).Offset(-1).
|
Find(list).Limit(-1).Offset(-1).
|
||||||
Count(count).Error
|
Count(count).Error
|
||||||
@ -188,6 +192,7 @@ func OpenUserBinanceWebsocket(item models.LineApiUser) {
|
|||||||
func (e *LineApiUser) Update(c *dto.LineApiUserUpdateReq, p *actions.DataPermission) error {
|
func (e *LineApiUser) Update(c *dto.LineApiUserUpdateReq, p *actions.DataPermission) error {
|
||||||
var err error
|
var err error
|
||||||
var data = models.LineApiUser{}
|
var data = models.LineApiUser{}
|
||||||
|
|
||||||
e.Orm.Scopes(
|
e.Orm.Scopes(
|
||||||
actions.Permission(data.TableName(), p),
|
actions.Permission(data.TableName(), p),
|
||||||
).First(&data, c.GetId())
|
).First(&data, c.GetId())
|
||||||
@ -195,14 +200,31 @@ func (e *LineApiUser) Update(c *dto.LineApiUserUpdateReq, p *actions.DataPermiss
|
|||||||
|
|
||||||
c.Generate(&data)
|
c.Generate(&data)
|
||||||
|
|
||||||
db := e.Orm.Save(&data)
|
updateGroups, err := e.GetUpdateGroups(c.Id)
|
||||||
if err = db.Error; err != nil {
|
|
||||||
e.Log.Errorf("LineApiUserService Save error:%s \r\n", err)
|
//事务
|
||||||
|
err = e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
db := tx.Save(&data)
|
||||||
|
if err = db.Error; err != nil {
|
||||||
|
e.Log.Errorf("LineApiUserService Save error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(updateGroups) > 0 {
|
||||||
|
if err := tx.Save(&updateGroups).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if db.RowsAffected == 0 {
|
|
||||||
return errors.New("无权更新该数据")
|
|
||||||
}
|
|
||||||
|
|
||||||
e.saveCache(data)
|
e.saveCache(data)
|
||||||
|
|
||||||
@ -224,6 +246,24 @@ func (e *LineApiUser) Update(c *dto.LineApiUserUpdateReq, p *actions.DataPermiss
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *LineApiUser) GetUpdateGroups(apiUserId int) ([]models.LineApiUserGroup, error) {
|
||||||
|
updateGroups := make([]models.LineApiUserGroup, 0)
|
||||||
|
var groups []models.LineApiUserGroup
|
||||||
|
if err := e.Orm.Model(models.LineApiUserGroup{}).Where(" concat(',',user_id,',') like ? ", fmt.Sprintf("%%,%v,%%", apiUserId)).Find(&groups).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
delId := fmt.Sprintf(",%v,", apiUserId)
|
||||||
|
for _, group := range groups {
|
||||||
|
|
||||||
|
userId := strings.ReplaceAll(("," + group.UserId + ","), delId, "")
|
||||||
|
group.UserId = strings.Trim(userId, ",")
|
||||||
|
|
||||||
|
updateGroups = append(updateGroups, group)
|
||||||
|
}
|
||||||
|
return updateGroups, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Remove 删除LineApiUser
|
// Remove 删除LineApiUser
|
||||||
func (e *LineApiUser) Remove(d *dto.LineApiUserDeleteReq, p *actions.DataPermission) error {
|
func (e *LineApiUser) Remove(d *dto.LineApiUserDeleteReq, p *actions.DataPermission) error {
|
||||||
var data models.LineApiUser
|
var data models.LineApiUser
|
||||||
@ -347,3 +387,30 @@ func (e *LineApiUser) GetMainUser(req *dto.GetMainUserReq, list *[]models.LineAp
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitCache 初始化缓存
|
||||||
|
func (e *LineApiUser) InitCache() error {
|
||||||
|
var items []models.LineApiUser
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.LineApiUser{}).Find(&items).Error; err != nil {
|
||||||
|
e.Log.Errorf("LineApiUserService error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
e.saveCache(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetActiveApis 获取激活的api
|
||||||
|
func (e *LineApiUser) GetActiveApis(apiIds []int) ([]int, error) {
|
||||||
|
result := make([]int, 0)
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.LineApiUser{}).Where("open_status = 1 and id IN ?", apiIds).Pluck("id", &result).Error; err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|||||||
165
app/admin/service/line_api_user_group.go
Normal file
165
app/admin/service/line_api_user_group.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
"go-admin/pkg/utility"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineApiUserGroup struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取LineApiUserGroup列表
|
||||||
|
func (e *LineApiUserGroup) GetPage(c *dto.LineApiUserGroupGetPageReq, p *actions.DataPermission, list *[]models.LineApiUserGroup, count *int64) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineApiUserGroup
|
||||||
|
|
||||||
|
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("LineApiUserGroupService GetPage error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for index := range *list {
|
||||||
|
userIds := strings.Split((*list)[index].UserId, ",")
|
||||||
|
var filteredUserIds []string
|
||||||
|
for _, id := range userIds {
|
||||||
|
if id != "" {
|
||||||
|
filteredUserIds = append(filteredUserIds, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*list)[index].Count = len(filteredUserIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取LineApiUserGroup对象
|
||||||
|
func (e *LineApiUserGroup) Get(d *dto.LineApiUserGroupGetReq, p *actions.DataPermission, model *models.LineApiUserGroup) error {
|
||||||
|
var data models.LineApiUserGroup
|
||||||
|
|
||||||
|
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 GetLineApiUserGroup error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userIds := []int{}
|
||||||
|
|
||||||
|
for _, userId := range strings.Split(model.UserId, ",") {
|
||||||
|
if userId == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
userIds = append(userIds, utility.ToInt(userId))
|
||||||
|
}
|
||||||
|
model.UserIds = userIds
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建LineApiUserGroup对象
|
||||||
|
func (e *LineApiUserGroup) Insert(c *dto.LineApiUserGroupInsertReq) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineApiUserGroup
|
||||||
|
c.Generate(&data)
|
||||||
|
err = e.Orm.Create(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("LineApiUserGroupService Insert error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改LineApiUserGroup对象
|
||||||
|
func (e *LineApiUserGroup) Update(c *dto.LineApiUserGroupUpdateReq, p *actions.DataPermission) error {
|
||||||
|
var err error
|
||||||
|
var data = models.LineApiUserGroup{}
|
||||||
|
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("LineApiUserGroupService Save error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove 删除LineApiUserGroup
|
||||||
|
func (e *LineApiUserGroup) Remove(d *dto.LineApiUserGroupDeleteReq, p *actions.DataPermission) error {
|
||||||
|
var data models.LineApiUserGroup
|
||||||
|
|
||||||
|
db := e.Orm.Model(&data).
|
||||||
|
Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).Delete(&data, d.GetId())
|
||||||
|
if err := db.Error; err != nil {
|
||||||
|
e.Log.Errorf("Service RemoveLineApiUserGroup error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权删除该数据")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineApiUserGroup) GetOptions(req *dto.LineApiUserGroupGetOptionsReq, data *[]dto.LineApiUserGroupOptions, p *actions.DataPermission) error {
|
||||||
|
var err error
|
||||||
|
var items []models.LineApiUserGroup
|
||||||
|
|
||||||
|
e.Orm.Model(&models.LineApiUserGroup{}).
|
||||||
|
Where("exchange_type =?", req.ExchangeType).
|
||||||
|
Scopes(
|
||||||
|
actions.Permission(models.LineApiUserGroup{}.TableName(), p),
|
||||||
|
).Find(&items)
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
ids := []int{}
|
||||||
|
userIds := strings.Split(item.UserId, ",")
|
||||||
|
|
||||||
|
for _, id := range userIds {
|
||||||
|
val, _ := strconv.Atoi(id)
|
||||||
|
ids = append(ids, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = append(*data, dto.LineApiUserGroupOptions{
|
||||||
|
Label: item.GroupName,
|
||||||
|
Id: item.Id,
|
||||||
|
Value: ids,
|
||||||
|
Disabled: item.Status != 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
@ -374,9 +374,34 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddPreOrder 单个添加
|
// 单个新增订单
|
||||||
func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataPermission, errs *[]error, tickerSymbol string) error {
|
func (e *LinePreOrder) AddPreOrderCheck(req *dto.LineAddPreOrderReq, p *actions.DataPermission, errs *[]error, tickerSymbol string) error {
|
||||||
|
apiUserService := LineApiUser{Service: e.Service}
|
||||||
|
apiIds := []int{}
|
||||||
apiUserIds := strings.Split(req.ApiUserId, ",")
|
apiUserIds := strings.Split(req.ApiUserId, ",")
|
||||||
|
for _, v := range apiUserIds {
|
||||||
|
apiId, _ := strconv.Atoi(v)
|
||||||
|
apiIds = append(apiIds, apiId)
|
||||||
|
}
|
||||||
|
|
||||||
|
activeApiIds, _ := apiUserService.GetActiveApis(apiIds)
|
||||||
|
|
||||||
|
if len(activeApiIds) == 0 {
|
||||||
|
*errs = append(*errs, errors.New("api用户不存在或未激活"))
|
||||||
|
} else {
|
||||||
|
for _, item := range apiIds {
|
||||||
|
if !utility.ContainsInt(activeApiIds, item) {
|
||||||
|
*errs = append(*errs, fmt.Errorf("api用户未激活:%v", item))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.AddPreOrder(req, activeApiIds, p, errs, tickerSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPreOrder 单个添加
|
||||||
|
func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int, p *actions.DataPermission, errs *[]error, tickerSymbol string) error {
|
||||||
if req.SaveTemplate == "2" || req.SaveTemplate == "1" { //2 = 只保存模板 1= 保存模板并下单
|
if req.SaveTemplate == "2" || req.SaveTemplate == "1" { //2 = 只保存模板 1= 保存模板并下单
|
||||||
var templateLog dto.LineAddPreOrderReq
|
var templateLog dto.LineAddPreOrderReq
|
||||||
copier.Copy(&templateLog, req)
|
copier.Copy(&templateLog, req)
|
||||||
@ -412,7 +437,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
|
|
||||||
for _, id := range apiUserIds {
|
for _, id := range apiUserIds {
|
||||||
if req.Site == "SELL" && req.SymbolType == global.SYMBOL_SPOT {
|
if req.Site == "SELL" && req.SymbolType == global.SYMBOL_SPOT {
|
||||||
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 现货不支持卖出操作", id, req.Symbol))
|
*errs = append(*errs, fmt.Errorf("api_id:%v 获取交易对:%s 现货不支持卖出操作", id, req.Symbol))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var AddOrder models.LinePreOrder
|
var AddOrder models.LinePreOrder
|
||||||
@ -500,7 +525,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||||
AddOrder.ApiId, _ = strconv.Atoi(id)
|
AddOrder.ApiId = id
|
||||||
AddOrder.Symbol = req.Symbol
|
AddOrder.Symbol = req.Symbol
|
||||||
AddOrder.QuoteSymbol = symbolInfo.QuoteAsset
|
AddOrder.QuoteSymbol = symbolInfo.QuoteAsset
|
||||||
AddOrder.Pid = 0
|
AddOrder.Pid = 0
|
||||||
@ -651,14 +676,20 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
profitOrder.Rate = "0"
|
profitOrder.Rate = "0"
|
||||||
} else {
|
} else {
|
||||||
if strings.ToUpper(req.Site) == "BUY" {
|
if strings.ToUpper(req.Site) == "BUY" {
|
||||||
profitOrder.Site = "SELL"
|
// profitOrder.Site = "SELL"
|
||||||
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
|
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
} else {
|
} else {
|
||||||
profitOrder.Site = "BUY"
|
// profitOrder.Site = "BUY"
|
||||||
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
|
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
}
|
}
|
||||||
profitOrder.Rate = req.Profit
|
profitOrder.Rate = req.Profit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.ToUpper(req.Site) == "BUY" {
|
||||||
|
profitOrder.Site = "SELL"
|
||||||
|
} else {
|
||||||
|
profitOrder.Site = "BUY"
|
||||||
|
}
|
||||||
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||||
profitOrder.Pid = AddOrder.Id
|
profitOrder.Pid = AddOrder.Id
|
||||||
profitOrder.OrderType = 1
|
profitOrder.OrderType = 1
|
||||||
@ -696,15 +727,21 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
stopOrder.Rate = "0"
|
stopOrder.Rate = "0"
|
||||||
} else {
|
} else {
|
||||||
if strings.ToUpper(req.Site) == "BUY" {
|
if strings.ToUpper(req.Site) == "BUY" {
|
||||||
stopOrder.Site = "SELL"
|
// stopOrder.Site = "SELL"
|
||||||
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Sub(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
|
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Sub(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
} else {
|
} else {
|
||||||
stopOrder.Site = "BUY"
|
// stopOrder.Site = "BUY"
|
||||||
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Add(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
|
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Add(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
stopOrder.Rate = req.ReducePriceRatio.String()
|
stopOrder.Rate = req.ReducePriceRatio.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.ToUpper(req.Site) == "BUY" {
|
||||||
|
stopOrder.Site = "SELL"
|
||||||
|
} else {
|
||||||
|
stopOrder.Site = "BUY"
|
||||||
|
}
|
||||||
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||||
stopOrder.Pid = AddOrder.Id
|
stopOrder.Pid = AddOrder.Id
|
||||||
stopOrder.MainId = AddOrder.Id
|
stopOrder.MainId = AddOrder.Id
|
||||||
@ -1078,10 +1115,34 @@ func (e *LinePreOrder) CheckRepeatOrder(symbolType int, apiUserId, site, baseCoi
|
|||||||
|
|
||||||
// AddBatchPreOrder 批量添加
|
// AddBatchPreOrder 批量添加
|
||||||
func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p *actions.DataPermission, errs *[]error) error {
|
func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p *actions.DataPermission, errs *[]error) error {
|
||||||
|
// apiIds := []int{}
|
||||||
|
// apiUserIds := strings.Split(batchReq.ApiUserId, ",")
|
||||||
|
// apiUserService := LineApiUser{Service: e.Service}
|
||||||
|
|
||||||
|
// for _, v := range apiUserIds {
|
||||||
|
// apiId, _ := strconv.Atoi(v)
|
||||||
|
// apiIds = append(apiIds, apiId)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// activeIds, err := apiUserService.GetActiveApis(apiIds)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if len(activeIds) == 0 {
|
||||||
|
// return errors.New("没有可用的api")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for _, v := range apiIds {
|
||||||
|
// if !utility.ContainsInt(activeIds, v) {
|
||||||
|
// *errs = append(*errs, errors.New("api_id:"+strconv.Itoa(v)+"不可用"))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if batchReq.SaveTemplate == "2" || batchReq.SaveTemplate == "1" { //2 = 只保存模板 1= 保存模板并下单
|
if batchReq.SaveTemplate == "2" || batchReq.SaveTemplate == "1" { //2 = 只保存模板 1= 保存模板并下单
|
||||||
var templateLog dto.LineBatchAddPreOrderReq
|
var templateLog dto.LineBatchAddPreOrderReq
|
||||||
copier.Copy(&templateLog, batchReq)
|
copier.Copy(&templateLog, batchReq)
|
||||||
//templateLog = *batchReq
|
|
||||||
templateLog.SaveTemplate = "0"
|
templateLog.SaveTemplate = "0"
|
||||||
templateLog.TemplateName = ""
|
templateLog.TemplateName = ""
|
||||||
marshal, _ := sonic.Marshal(templateLog)
|
marshal, _ := sonic.Marshal(templateLog)
|
||||||
@ -1112,80 +1173,81 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
|
|||||||
}
|
}
|
||||||
|
|
||||||
//脚本次数
|
//脚本次数
|
||||||
if batchReq.OrderNum > 0 {
|
// if batchReq.OrderNum > 0 {
|
||||||
var tickerSymbol string
|
apiUserIds := strings.Split(batchReq.ApiUserId, ",")
|
||||||
if batchReq.SymbolType == global.SYMBOL_SPOT {
|
var tickerSymbol string
|
||||||
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
|
if batchReq.SymbolType == global.SYMBOL_SPOT {
|
||||||
} else {
|
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
|
||||||
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.ProfitNumRatio = batchReq.ProfitNumRatio
|
|
||||||
req.ProfitTpTpPriceRatio = batchReq.ProfitTpTpPriceRatio
|
|
||||||
req.ProfitTpSlPriceRatio = batchReq.ProfitTpSlPriceRatio
|
|
||||||
req.Ext = batchReq.Ext
|
|
||||||
req.SymbolType = batchReq.SymbolType
|
|
||||||
// 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
|
|
||||||
req.CreateBy = batchReq.CreateBy
|
|
||||||
|
|
||||||
e.AddPreOrder(&req, p, errs, tickerSymbol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
} else {
|
} else {
|
||||||
*errs = append(*errs, errors.New("请选择运行次数"))
|
tickerSymbol = helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = ""
|
||||||
|
logParams.ApiUserId = id
|
||||||
|
marshal, _ := sonic.Marshal(logParams)
|
||||||
|
log.ApiId = utility.ToInt64(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
|
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.ProfitNumRatio = batchReq.ProfitNumRatio
|
||||||
|
req.ProfitTpTpPriceRatio = batchReq.ProfitTpTpPriceRatio
|
||||||
|
req.ProfitTpSlPriceRatio = batchReq.ProfitTpSlPriceRatio
|
||||||
|
req.Ext = batchReq.Ext
|
||||||
|
req.SymbolType = batchReq.SymbolType
|
||||||
|
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
|
||||||
|
req.CreateBy = batchReq.CreateBy
|
||||||
|
|
||||||
|
e.AddPreOrderCheck(&req, p, errs, tickerSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
// } else {
|
||||||
|
// *errs = append(*errs, errors.New("请选择运行次数"))
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuickAddPreOrder 模板快速下单
|
// QuickAddPreOrder 模板快速下单
|
||||||
@ -1204,7 +1266,8 @@ func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *ac
|
|||||||
} else {
|
} else {
|
||||||
tickerSymbol = helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val()
|
tickerSymbol = helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val()
|
||||||
}
|
}
|
||||||
err := e.AddPreOrder(&addPreOrderParams, p, errs, tickerSymbol)
|
err := e.AddPreOrderCheck(&addPreOrderParams, p, errs, tickerSymbol)
|
||||||
|
// err := e.AddPreOrder(&addPreOrderParams, p, errs, tickerSymbol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", addPreOrderParams.ApiUserId, addPreOrderParams.Symbol))
|
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", addPreOrderParams.ApiUserId, addPreOrderParams.Symbol))
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -26,7 +26,7 @@ func (e *LineSymbolGroup) GetPage(c *dto.LineSymbolGroupGetPageReq, p *actions.D
|
|||||||
Scopes(
|
Scopes(
|
||||||
cDto.MakeCondition(c.GetNeedSearch()),
|
cDto.MakeCondition(c.GetNeedSearch()),
|
||||||
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||||
actions.Permission(data.TableName(), p),
|
// actions.Permission(data.TableName(), p),
|
||||||
)
|
)
|
||||||
if c.ExchangeType != "" {
|
if c.ExchangeType != "" {
|
||||||
query = query.Where("exchange_type = ?", c.ExchangeType)
|
query = query.Where("exchange_type = ?", c.ExchangeType)
|
||||||
|
|||||||
@ -718,6 +718,7 @@ func (e *LineUser) ResetPassword(req *dto.LineUserResetPwdReq) int {
|
|||||||
func (e *LineUser) OpenStatus(req *dto.OpenStatusReq, userId int) int {
|
func (e *LineUser) OpenStatus(req *dto.OpenStatusReq, userId int) int {
|
||||||
var apiUser models.LineApiUser
|
var apiUser models.LineApiUser
|
||||||
user := models.LineUser{}
|
user := models.LineUser{}
|
||||||
|
apiUserService := LineApiUser{Service: e.Service}
|
||||||
e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser)
|
e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser)
|
||||||
|
|
||||||
if apiUser.ApiSecret == "" || apiUser.ApiKey == "" {
|
if apiUser.ApiSecret == "" || apiUser.ApiKey == "" {
|
||||||
@ -752,10 +753,31 @@ func (e *LineUser) OpenStatus(req *dto.OpenStatusReq, userId int) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Update("open_status", req.Status).Error
|
apiUser.OpenStatus = int64(req.Status)
|
||||||
|
updateGroups, _ := apiUserService.GetUpdateGroups(apiUser.Id)
|
||||||
|
|
||||||
|
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if err := e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Update("open_status", req.Status).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Save(&updateGroups).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return statuscode.ServerError
|
return statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val, _ := sonic.MarshalString(apiUser)
|
||||||
|
|
||||||
|
if val != "" {
|
||||||
|
if err := helper.DefaultRedis.SetString(fmt.Sprintf(rediskey.API_USER, userId), val); err != nil {
|
||||||
|
logger.Error("保存api user redis 失败", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return statuscode.OK
|
return statuscode.OK
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,15 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
cDto "go-admin/common/dto"
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,6 +63,13 @@ func (e *SysConfig) Insert(c *dto.SysConfigControl) error {
|
|||||||
e.Log.Errorf("Service InsertSysConfig error:%s", err)
|
e.Log.Errorf("Service InsertSysConfig error:%s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key := fmt.Sprintf(rediskey.SysConfigKey, c.ConfigKey)
|
||||||
|
content, _ := sonic.MarshalString(data)
|
||||||
|
|
||||||
|
if content != "" {
|
||||||
|
helper.DefaultRedis.SetString(key, content)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +87,13 @@ func (e *SysConfig) Update(c *dto.SysConfigControl) error {
|
|||||||
}
|
}
|
||||||
if db.RowsAffected == 0 {
|
if db.RowsAffected == 0 {
|
||||||
return errors.New("无权更新该数据")
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
key := fmt.Sprintf(rediskey.SysConfigKey, c.ConfigKey)
|
||||||
|
content, _ := sonic.MarshalString(model)
|
||||||
|
|
||||||
|
if content != "" {
|
||||||
|
helper.DefaultRedis.SetString(key, content)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -133,7 +150,6 @@ func (e *SysConfig) UpdateForSet(c *[]dto.GetSetSysConfigReq) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -143,6 +159,9 @@ func (e *SysConfig) UpdateForSet(c *[]dto.GetSetSysConfigReq) error {
|
|||||||
func (e *SysConfig) Remove(d *dto.SysConfigDeleteReq) error {
|
func (e *SysConfig) Remove(d *dto.SysConfigDeleteReq) error {
|
||||||
var err error
|
var err error
|
||||||
var data models.SysConfig
|
var data models.SysConfig
|
||||||
|
keys := make([]string, 0)
|
||||||
|
|
||||||
|
e.Orm.Model(&data).Where("id IN ?", d.Ids).Pluck("config_key", &keys)
|
||||||
|
|
||||||
db := e.Orm.Delete(&data, d.Ids)
|
db := e.Orm.Delete(&data, d.Ids)
|
||||||
if err = db.Error; err != nil {
|
if err = db.Error; err != nil {
|
||||||
@ -153,6 +172,14 @@ func (e *SysConfig) Remove(d *dto.SysConfigDeleteReq) error {
|
|||||||
err = errors.New("无权删除该数据")
|
err = errors.New("无权删除该数据")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
cacheKey := fmt.Sprintf(rediskey.SysConfigKey, key)
|
||||||
|
if err = helper.DefaultRedis.DeleteString(cacheKey); err != nil {
|
||||||
|
e.Log.Errorf("Service RemoveSysConfig error:%s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,12 @@ package jobs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
models2 "go-admin/app/jobs/models"
|
||||||
|
"time"
|
||||||
|
|
||||||
log "github.com/go-admin-team/go-admin-core/logger"
|
log "github.com/go-admin-team/go-admin-core/logger"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk"
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
models2 "go-admin/app/jobs/models"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
|
|
||||||
@ -40,6 +41,12 @@ type ExecJob struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *ExecJob) Run() {
|
func (e *ExecJob) Run() {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
log.Errorf("脚本任务失败:%v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
var obj = jobList[e.InvokeTarget]
|
var obj = jobList[e.InvokeTarget]
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
|
|||||||
261
app/jobs/jobs.go
261
app/jobs/jobs.go
@ -26,6 +26,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
|
|
||||||
@ -158,7 +159,6 @@ func (t AutoPlaceOrder) Exec(arg interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t LimitOrderTimeoutDuration) Exec(arg interface{}) error {
|
func (t LimitOrderTimeoutDuration) Exec(arg interface{}) error {
|
||||||
|
|
||||||
str := time.Now().Format(timeFormat) + " [INFO] JobCore ClearLogJob exec success"
|
str := time.Now().Format(timeFormat) + " [INFO] JobCore ClearLogJob exec success"
|
||||||
defer logger.Info(str)
|
defer logger.Info(str)
|
||||||
var db *gorm.DB
|
var db *gorm.DB
|
||||||
@ -188,7 +188,10 @@ func (t LimitOrderTimeoutDuration) Exec(arg interface{}) error {
|
|||||||
defer lock.Release()
|
defer lock.Release()
|
||||||
limitOrderTimeoutDuration := utility.StringAsInt64(resp.ConfigValue)
|
limitOrderTimeoutDuration := utility.StringAsInt64(resp.ConfigValue)
|
||||||
orders := make([]models.LinePreOrder, 0)
|
orders := make([]models.LinePreOrder, 0)
|
||||||
err := db.Model(&models.LinePreOrder{}).Where("status = '5' AND main_order_type = 'LIMIT' AND order_type in ('4') AND updated_at < ?", time.Now().Add(-time.Duration(limitOrderTimeoutDuration)*time.Second)).Find(&orders).Error
|
err := db.Model(&models.LinePreOrder{}).
|
||||||
|
Where("status = '5' AND main_order_type = 'LIMIT' AND order_type in ('4') AND updated_at < ?", time.Now().Add(-time.Duration(limitOrderTimeoutDuration)*time.Second)).
|
||||||
|
Preload("Childs").
|
||||||
|
Find(&orders).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -228,6 +231,7 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
|||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
err = spotApi.CancelOpenOrderByOrderSn(apiUserinfo, order.Symbol, order.OrderSn)
|
err = spotApi.CancelOpenOrderByOrderSn(apiUserinfo, order.Symbol, order.OrderSn)
|
||||||
if err == nil || strings.Contains(err.Error(), "该交易对没有订单") {
|
if err == nil || strings.Contains(err.Error(), "该交易对没有订单") {
|
||||||
|
err = nil
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,11 +241,12 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
|||||||
} else {
|
} else {
|
||||||
var remainingQuantity decimal.Decimal
|
var remainingQuantity decimal.Decimal
|
||||||
spotOrder, err := spotApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
spotOrder, err := spotApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
||||||
|
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
origQty := utility.StrToDecimal(spotOrder.OrigQuoteOrderQty)
|
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||||
excuteQty := utility.StrToDecimal(spotOrder.ExecutedQty)
|
excuteQty := utility.StrToDecimal(spotOrder.ExecutedQty)
|
||||||
remainingQuantity = origQty.Sub(excuteQty).Abs()
|
remainingQuantity = origQty.Sub(excuteQty).Abs().Truncate(int32(tradeSet.AmountDigit))
|
||||||
}
|
}
|
||||||
|
|
||||||
if remainingQuantity.Cmp(decimal.Zero) <= 0 {
|
if remainingQuantity.Cmp(decimal.Zero) <= 0 {
|
||||||
@ -249,36 +254,62 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
maxMarketQty := decimal.NewFromFloat(tradeSet.MarketMaxQty).Truncate(int32(tradeSet.AmountDigit))
|
||||||
newClientOrderId := snowflakehelper.GetOrderId()
|
|
||||||
|
|
||||||
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
// if config.ApplicationConfig.Mode == "dev" {
|
||||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单源订单号:%s ", order.OrderSn)
|
// maxMarketQty = decimal.NewFromFloat(10)
|
||||||
order.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
// }
|
||||||
order.MainOrderType = "MARKET"
|
|
||||||
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn, "main_order_type": order.MainOrderType}).Error
|
|
||||||
|
|
||||||
if err != nil {
|
if remainingQuantity.Cmp(maxMarketQty) > 0 && maxMarketQty.Cmp(decimal.Zero) > 0 {
|
||||||
logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err))
|
multiple := remainingQuantity.Div(maxMarketQty).Abs().IntPart()
|
||||||
return err
|
remainder := remainingQuantity.Mod(maxMarketQty)
|
||||||
}
|
saveOrders := make([]models.LinePreOrder, 0)
|
||||||
params := binanceservice.OrderPlacementService{
|
|
||||||
ApiId: order.ApiId,
|
desc := fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
||||||
Symbol: order.Symbol,
|
|
||||||
Side: order.Site,
|
// 创建 multiple 个订单
|
||||||
Type: "MARKET",
|
for i := 0; i < int(multiple); i++ {
|
||||||
TimeInForce: "GTC",
|
saveOrders = append(saveOrders, createNewOrder(order, maxMarketQty, desc))
|
||||||
Price: utility.StringToDecimal(order.Price),
|
}
|
||||||
StopPrice: utility.StrToDecimal(order.Price),
|
|
||||||
Quantity: remainingQuantity,
|
// 处理余数
|
||||||
NewClientOrderId: utility.Int64ToString(newClientOrderId),
|
if remainder.Cmp(decimal.Zero) > 0 {
|
||||||
}
|
saveOrders = append(saveOrders, createNewOrder(order, remainder.Truncate(int32(tradeSet.AmountDigit)), desc))
|
||||||
if err := spotApi.OrderPlace(db, params); err != nil {
|
}
|
||||||
logger.Error(fmt.Sprintf("重新下市价单失败 err:%+v", err))
|
|
||||||
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + "err:" + err.Error()}).Error
|
if err := db.Create(&saveOrders).Error; err != nil {
|
||||||
|
logger.Errorf("市价订单拆分后保存失败,err:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for index := range saveOrders {
|
||||||
|
newNum := utility.StrToDecimal(saveOrders[index].Num)
|
||||||
|
|
||||||
|
if err := newSpotOrderClosePosition(saveOrders[index], newNum, spotApi, db); err != nil {
|
||||||
|
logger.Errorf("市价订单拆分后保存失败,err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if index == len(saveOrders)-1 {
|
||||||
|
orderCopy := saveOrders[index] // 复制数据
|
||||||
|
|
||||||
|
binanceservice.HandleSpotMarketSliceTakeProfit(db, orderCopy, order.Id, apiUserinfo, tradeSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newClientOrderId := snowflakehelper.GetOrderId()
|
||||||
|
|
||||||
|
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
|
order.Desc = fmt.Sprintf("取消限价单,重下市价单源订单号:%s ", order.OrderSn)
|
||||||
|
order.OrderSn = utility.Int64ToString(newClientOrderId)
|
||||||
|
order.MainOrderType = "MARKET"
|
||||||
|
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn, "main_order_type": order.MainOrderType}).Error
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("下单失败后修改订单失败")
|
logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := newSpotOrderClosePosition(order, remainingQuantity, spotApi, db); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,12 +318,38 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 现货市价单平仓
|
||||||
|
func newSpotOrderClosePosition(order models.LinePreOrder, remainingQuantity decimal.Decimal, spotApi binanceservice.SpotRestApi, db *gorm.DB) error {
|
||||||
|
params := binanceservice.OrderPlacementService{
|
||||||
|
ApiId: order.ApiId,
|
||||||
|
Symbol: order.Symbol,
|
||||||
|
Side: order.Site,
|
||||||
|
Type: "MARKET",
|
||||||
|
TimeInForce: "GTC",
|
||||||
|
Price: utility.StringToDecimal(order.Price),
|
||||||
|
StopPrice: utility.StrToDecimal(order.Price),
|
||||||
|
Quantity: remainingQuantity,
|
||||||
|
NewClientOrderId: order.OrderSn,
|
||||||
|
}
|
||||||
|
if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
|
||||||
|
logger.Error(fmt.Sprintf("重新下市价单失败 err:%+v", err))
|
||||||
|
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + "err:" + err.Error()}).Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("下单失败后修改订单失败")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ReFutOrderPlace 重下合约市价单
|
// ReFutOrderPlace 重下合约市价单
|
||||||
func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.LinePreOrder, apiUserinfo models.LineApiUser, futApi binanceservice.FutRestApi) error {
|
func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.LinePreOrder, apiUserinfo models.LineApiUser, futApi binanceservice.FutRestApi) error {
|
||||||
var err error
|
var err error
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
err := futApi.CancelFutOrder(apiUserinfo, order.Symbol, order.OrderSn)
|
err := futApi.CancelFutOrder(apiUserinfo, order.Symbol, order.OrderSn)
|
||||||
if err == nil || strings.Contains(err.Error(), "该交易对没有订单") {
|
if err == nil || strings.Contains(err.Error(), "该交易对没有订单") {
|
||||||
|
err = nil
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,11 +359,12 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
|||||||
} else {
|
} else {
|
||||||
var remainingQuantity decimal.Decimal
|
var remainingQuantity decimal.Decimal
|
||||||
spotOrder, err := futApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
spotOrder, err := futApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
||||||
|
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 1)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||||
excuteQty := utility.StrToDecimal(spotOrder.ExecutedQty)
|
excuteQty := utility.StrToDecimal(spotOrder.ExecutedQty)
|
||||||
remainingQuantity = origQty.Sub(excuteQty).Abs()
|
remainingQuantity = origQty.Sub(excuteQty).Abs().Truncate(int32(tradeSet.AmountDigit))
|
||||||
}
|
}
|
||||||
|
|
||||||
if remainingQuantity.Cmp(decimal.Zero) <= 0 {
|
if remainingQuantity.Cmp(decimal.Zero) <= 0 {
|
||||||
@ -314,51 +372,62 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
qty := decimal.NewFromFloat(tradeSet.MarketMaxQty)
|
||||||
|
maxMarketQty := qty.Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
|
||||||
newClientOrderId := snowflakehelper.GetOrderId()
|
// if config.ApplicationConfig.Mode == "dev" {
|
||||||
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
// maxMarketQty = decimal.NewFromFloat(10)
|
||||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
|
||||||
order.OrderSn = utility.Int64ToString(newClientOrderId)
|
|
||||||
|
|
||||||
// var newOrder models.LinePreOrder
|
|
||||||
// copier.Copy(&newOrder, order)
|
|
||||||
// newOrder.Id = 0
|
|
||||||
// newOrder.OrderSn = utility.Int64ToString(newClientOrderId)
|
|
||||||
// newOrder.CreatedAt = time.Now()
|
|
||||||
// newOrder.MainOrderType = "MARKET"
|
|
||||||
// err = db.Model(&models.LinePreOrder{}).Create(&newOrder).Error
|
|
||||||
|
|
||||||
var positionSide string
|
|
||||||
|
|
||||||
if order.Site == "BUY" {
|
|
||||||
positionSide = "SHORT"
|
|
||||||
} else {
|
|
||||||
positionSide = "LONG"
|
|
||||||
}
|
|
||||||
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn}).Error
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(fmt.Sprintf("生成合约新市价单失败 err:%+v", err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// params := binanceservice.FutOrderPlace{
|
|
||||||
// ApiId: order.ApiId,
|
|
||||||
// Symbol: order.Symbol,
|
|
||||||
// Side: order.Site,
|
|
||||||
// Quantity: remainingQuantity,
|
|
||||||
// Price: utility.StringToDecimal(order.Price),
|
|
||||||
// SideType: "MARKET",
|
|
||||||
// OpenOrder: 0,
|
|
||||||
// OrderType: "MARKET",
|
|
||||||
// NewClientOrderId: utility.Int64ToString(newClientOrderId),
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if err := futApi.ClosePositionLoop(order.Symbol, order.OrderSn, remainingQuantity, order.Site, positionSide, apiUserinfo, "MARKET", "0", decimal.Zero, 3); err != nil {
|
//数量超过最大数量,则拆单
|
||||||
logger.Error(fmt.Sprintf("重新下合约市价单失败 err:%+v", err))
|
if remainingQuantity.Cmp(maxMarketQty) > 0 && maxMarketQty.Cmp(decimal.Zero) > 0 {
|
||||||
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + " err:" + err.Error()}).Error
|
multiple := remainingQuantity.Div(maxMarketQty).Abs().IntPart()
|
||||||
|
remainder := remainingQuantity.Mod(maxMarketQty)
|
||||||
|
saveOrders := make([]models.LinePreOrder, 0)
|
||||||
|
|
||||||
|
desc := fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
||||||
|
|
||||||
|
// 创建 multiple 个订单
|
||||||
|
for i := 0; i < int(multiple); i++ {
|
||||||
|
saveOrders = append(saveOrders, createNewOrder(order, maxMarketQty, desc))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理余数
|
||||||
|
if remainder.Cmp(decimal.Zero) > 0 {
|
||||||
|
saveOrders = append(saveOrders, createNewOrder(order, remainder.Truncate(int32(tradeSet.AmountDigit)), desc))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Create(&saveOrders).Error; err != nil {
|
||||||
|
logger.Errorf("市价订单拆分后保存失败,err:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for index := range saveOrders {
|
||||||
|
newNum := utility.StrToDecimal(saveOrders[index].Num)
|
||||||
|
|
||||||
|
if err := newOrderClosePosition(saveOrders[index], futApi, newNum.Truncate(int32(tradeSet.AmountDigit)), apiUserinfo, db); err != nil {
|
||||||
|
logger.Errorf("市价单拆分后下单失败 orderSn:%s, err:%s", saveOrders[index].OrderSn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if index == len(saveOrders)-1 {
|
||||||
|
orderCopy := saveOrders[index] // 复制数据
|
||||||
|
binanceservice.HandleMarketSliceTakeProfit(db, orderCopy, order.Id, apiUserinfo, tradeSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newClientOrderId := snowflakehelper.GetOrderId()
|
||||||
|
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
|
order.Desc = fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
||||||
|
order.OrderSn = utility.Int64ToString(newClientOrderId)
|
||||||
|
|
||||||
|
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn}).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(fmt.Sprintf("生成合约新市价单失败 err:%+v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = newOrderClosePosition(order, futApi, remainingQuantity, apiUserinfo, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("下单失败后修改订单失败")
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -366,6 +435,54 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 复制订单
|
||||||
|
func createNewOrder(order models.LinePreOrder, num decimal.Decimal, desc string) models.LinePreOrder {
|
||||||
|
newOrder := models.LinePreOrder{}
|
||||||
|
copier.Copy(&newOrder, order)
|
||||||
|
|
||||||
|
newOrder.Id = 0
|
||||||
|
newOrder.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||||
|
newOrder.Num = num.String()
|
||||||
|
newOrder.Desc = desc
|
||||||
|
newOrder.MainOrderType = "MARKET"
|
||||||
|
newOrder.Status = 0
|
||||||
|
|
||||||
|
// 重新创建 Childs,并正确赋值 `Pid`
|
||||||
|
var newChilds []models.LinePreOrder
|
||||||
|
for _, child := range order.Childs {
|
||||||
|
newChild := child
|
||||||
|
newChild.Id = 0
|
||||||
|
newChild.Pid = 0
|
||||||
|
newChild.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||||
|
newChild.CreatedAt = time.Now()
|
||||||
|
newChilds = append(newChilds, newChild)
|
||||||
|
}
|
||||||
|
newOrder.Childs = newChilds // 重新赋值子订单,避免浅拷贝问题
|
||||||
|
|
||||||
|
return newOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新市价单
|
||||||
|
func newOrderClosePosition(order models.LinePreOrder, futApi binanceservice.FutRestApi, remainingQuantity decimal.Decimal, apiUserinfo models.LineApiUser, db *gorm.DB) error {
|
||||||
|
var positionSide string
|
||||||
|
|
||||||
|
if order.Site == "BUY" {
|
||||||
|
positionSide = "SHORT"
|
||||||
|
} else {
|
||||||
|
positionSide = "LONG"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := futApi.ClosePositionLoop(order.Symbol, order.OrderSn, remainingQuantity, order.Site, positionSide, apiUserinfo, "MARKET", "0", decimal.Zero, 3); err != nil {
|
||||||
|
logger.Error(fmt.Sprintf("重新下合约市价单失败 err:%+v", err))
|
||||||
|
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + " err:" + err.Error()}).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("下单失败后修改订单失败")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (l ListenSymbol) Exec(arg interface{}) error {
|
func (l ListenSymbol) Exec(arg interface{}) error {
|
||||||
str := time.Now().Format(timeFormat) + " [INFO] JobCore ClearLogJob exec success"
|
str := time.Now().Format(timeFormat) + " [INFO] JobCore ClearLogJob exec success"
|
||||||
defer logger.Info(str)
|
defer logger.Info(str)
|
||||||
|
|||||||
159
app/jobs/jobs_test.go
Normal file
159
app/jobs/jobs_test.go
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
"go-admin/services/binanceservice"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/config"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 测试现货限价转市价订单
|
||||||
|
func TestSpotLimitTransferJob(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "3")
|
||||||
|
|
||||||
|
job := LimitOrderTimeoutDuration{}
|
||||||
|
orders := make([]models.LinePreOrder, 0)
|
||||||
|
err := db.Model(&models.LinePreOrder{}).
|
||||||
|
Where("order_sn =?", "393609596205268992").
|
||||||
|
Preload("Childs").
|
||||||
|
Find(&orders).Error
|
||||||
|
// job.Exec([]string{})
|
||||||
|
|
||||||
|
config.ApplicationConfig.Mode = "dev"
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("获取订单失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, order := range orders {
|
||||||
|
apiInfo, err := binanceservice.GetApiInfo(49)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("获取api信息失败 %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
spotApi := binanceservice.SpotRestApi{}
|
||||||
|
err = job.ReSpotOrderPlace(db, order, apiInfo, spotApi)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("下单失败 %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试限价转市价订单
|
||||||
|
func TestLimitTransferJob(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "3")
|
||||||
|
|
||||||
|
job := LimitOrderTimeoutDuration{}
|
||||||
|
orders := make([]models.LinePreOrder, 0)
|
||||||
|
err := db.Model(&models.LinePreOrder{}).
|
||||||
|
Where("order_sn =?", "393573282378416128").
|
||||||
|
Preload("Childs").
|
||||||
|
Find(&orders).Error
|
||||||
|
// job.Exec([]string{})
|
||||||
|
|
||||||
|
config.ApplicationConfig.Mode = "dev"
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("获取订单失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, order := range orders {
|
||||||
|
apiInfo, err := binanceservice.GetApiInfo(49)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("获取api信息失败 %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
futApi := binanceservice.FutRestApi{}
|
||||||
|
err = job.ReFutOrderPlace(db, order, apiInfo, futApi)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("下单失败 %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReduce(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "3")
|
||||||
|
|
||||||
|
futApi := binanceservice.FutRestApi{}
|
||||||
|
// params := binanceservice.FutOrderPlace{
|
||||||
|
// Symbol: "ADAUSDT",
|
||||||
|
// ApiId: 49,
|
||||||
|
// Side: ,
|
||||||
|
// }
|
||||||
|
apiInfo, err := binanceservice.GetApiInfo(49)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("获取api信息失败 %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = futApi.ClosePositionLoop("ADAUSDT", "393573282378416128", decimal.NewFromInt(21), "SELL", "LONG", apiInfo, "LIMIT", "0", decimal.NewFromFloat(0.76), 3)
|
||||||
|
|
||||||
|
fmt.Printf("报错 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试现货下单
|
||||||
|
func TestReduceSpot(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "3")
|
||||||
|
|
||||||
|
spotApi := binanceservice.SpotRestApi{}
|
||||||
|
// params := binanceservice.FutOrderPlace{
|
||||||
|
// Symbol: "ADAUSDT",
|
||||||
|
// ApiId: 49,
|
||||||
|
// Side: ,
|
||||||
|
// }
|
||||||
|
apiInfo, err := binanceservice.GetApiInfo(49)
|
||||||
|
fmt.Sprintf("%v", apiInfo)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Printf("获取api信息失败 %v", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
err = spotApi.CancelOpenOrderByOrderSn(apiInfo, "ADAUSDT", "393609596188491776")
|
||||||
|
|
||||||
|
fmt.Printf("取消报错 %v", err)
|
||||||
|
|
||||||
|
params := binanceservice.OrderPlacementService{
|
||||||
|
ApiId: 49,
|
||||||
|
Side: "SELL",
|
||||||
|
Type: "LIMIT",
|
||||||
|
TimeInForce: "GTC",
|
||||||
|
Symbol: "ADAUSDT",
|
||||||
|
Price: decimal.NewFromFloat(0.76),
|
||||||
|
Quantity: decimal.NewFromInt(21),
|
||||||
|
NewClientOrderId: "393609596205268992",
|
||||||
|
}
|
||||||
|
err = spotApi.OrderPlaceLoop(db, params, 3)
|
||||||
|
|
||||||
|
fmt.Printf("报错 %v", err)
|
||||||
|
}
|
||||||
@ -44,6 +44,9 @@ const (
|
|||||||
SpotCallBack = "spot_callback:%s" //现货回调 {ordersn}
|
SpotCallBack = "spot_callback:%s" //现货回调 {ordersn}
|
||||||
FutCallBack = "fut_callback:%s" //合约回调 {ordersn}
|
FutCallBack = "fut_callback:%s" //合约回调 {ordersn}
|
||||||
|
|
||||||
|
FutReducecCallback = "fut_reduce_callback:%v_%s" //合约减仓回调 {apiid,symbol}
|
||||||
|
SpotReduceCallback = "spot_reduce_callback:%v_%s" //现货减仓回调 {apiid,symbol}
|
||||||
|
|
||||||
//需要清理键值---------BEGIN---------------
|
//需要清理键值---------BEGIN---------------
|
||||||
|
|
||||||
SpotStopLossList = "spot_stoploss_list:%s" //现货止损待触发列表 {交易所类型code}
|
SpotStopLossList = "spot_stoploss_list:%s" //现货止损待触发列表 {交易所类型code}
|
||||||
|
|||||||
6
common/const/rediskey/sys_config.go
Normal file
6
common/const/rediskey/sys_config.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package rediskey
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SysConfigKey 系统配置 {configKey}
|
||||||
|
SysConfigKey = "sys_config:%s"
|
||||||
|
)
|
||||||
@ -9,13 +9,13 @@ import (
|
|||||||
"go-admin/config"
|
"go-admin/config"
|
||||||
"go-admin/pkg/httputils"
|
"go-admin/pkg/httputils"
|
||||||
"go-admin/services/binanceservice"
|
"go-admin/services/binanceservice"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
"go-admin/services/futureservice"
|
"go-admin/services/futureservice"
|
||||||
"go-admin/services/scriptservice"
|
"go-admin/services/scriptservice"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
log "github.com/go-admin-team/go-admin-core/logger"
|
|
||||||
"github.com/go-admin-team/go-admin-core/sdk"
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@ -29,12 +29,20 @@ func BusinessInit(db *gorm.DB) {
|
|||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//初始化参数配置
|
||||||
|
cacheservice.InitConfigCache(db)
|
||||||
|
|
||||||
//初始化订单配置
|
//初始化订单配置
|
||||||
binanceservice.ResetSystemSetting(db)
|
binanceservice.ResetSystemSetting(db)
|
||||||
|
lineApiUser := service.LineApiUser{}
|
||||||
|
lineApiUser.Orm = db
|
||||||
|
if err := lineApiUser.InitCache(); err != nil {
|
||||||
|
logger.Errorf("初始化api用户失败:%v", err)
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
//币安 现货交易对
|
//币安 现货交易对
|
||||||
SpotCurrencyInit()
|
SpotCurrencyInit()
|
||||||
|
|
||||||
//币安 合约交易对
|
//币安 合约交易对
|
||||||
FuturesInit()
|
FuturesInit()
|
||||||
|
|
||||||
@ -101,7 +109,7 @@ func loadApiUser(db *gorm.DB) error {
|
|||||||
users := make([]models.LineApiUser, 0)
|
users := make([]models.LineApiUser, 0)
|
||||||
|
|
||||||
if err := db.Model(&models.LineApiUser{}).Where("open_status =1").Find(&users).Error; err != nil {
|
if err := db.Model(&models.LineApiUser{}).Where("open_status =1").Find(&users).Error; err != nil {
|
||||||
log.Error("loadApiUser:", err)
|
logger.Error("loadApiUser:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +119,7 @@ func loadApiUser(db *gorm.DB) error {
|
|||||||
|
|
||||||
if val != "" {
|
if val != "" {
|
||||||
if err := helper.DefaultRedis.SetString(key, val); err != nil {
|
if err := helper.DefaultRedis.SetString(key, val); err != nil {
|
||||||
log.Error("loadApiUser 保存redis:", err)
|
logger.Error("loadApiUser 保存redis:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +127,7 @@ func loadApiUser(db *gorm.DB) error {
|
|||||||
groups := make([]models.LineApiGroup, 0)
|
groups := make([]models.LineApiGroup, 0)
|
||||||
|
|
||||||
if err := db.Model(&models.LineApiGroup{}).Find(&groups).Error; err != nil {
|
if err := db.Model(&models.LineApiGroup{}).Find(&groups).Error; err != nil {
|
||||||
log.Error("loadApiGroup:", err)
|
logger.Error("loadApiGroup:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ settings:
|
|||||||
|
|
||||||
# redis 配置
|
# redis 配置
|
||||||
redis:
|
redis:
|
||||||
addr: "192.168.1.12:6379"
|
addr: "127.0.0.1:6379"
|
||||||
password: ""
|
password: ""
|
||||||
db: 2
|
db: 2
|
||||||
# 雪花算法设备id
|
# 雪花算法设备id
|
||||||
|
|||||||
@ -15,24 +15,26 @@ type Coin struct {
|
|||||||
|
|
||||||
// TradeSet vts_tradeset 交易配置
|
// TradeSet vts_tradeset 交易配置
|
||||||
type TradeSet struct {
|
type TradeSet struct {
|
||||||
ID int `db:"id" json:"id"`
|
ID int `db:"id" json:"id"`
|
||||||
AmountDigit int `db:"amountdigit"` //基础币种计数精度
|
AmountDigit int `db:"amountdigit"` //基础币种计数精度
|
||||||
PriceDigit int `db:"pricecdigit" json:"pricecdigit"` //价格小数点位数
|
PriceDigit int `db:"pricecdigit" json:"pricecdigit"` //价格小数点位数
|
||||||
Currency string `db:"currency" json:"currency"` //法币
|
Currency string `db:"currency" json:"currency"` //法币
|
||||||
Coin string `db:"coin" json:"coin"` //币种
|
Coin string `db:"coin" json:"coin"` //币种
|
||||||
PriceChange float64 `db:"pricechange" json:"pricechange"` //价格波动价位
|
PriceChange float64 `db:"pricechange" json:"pricechange"` //价格波动价位
|
||||||
MinBuyVal float64 `db:"minbuyval"` //最小下单金额
|
MinBuyVal float64 `db:"minbuyval"` //最小下单金额
|
||||||
OpenPrice float64 `db:"openprice"` //开盘价格
|
OpenPrice float64 `db:"openprice"` //开盘价格
|
||||||
LastPrice string `json:"last"` //最新价格
|
LastPrice string `json:"last"` //最新价格
|
||||||
HighPrice string `json:"high"` //24小时最高价
|
HighPrice string `json:"high"` //24小时最高价
|
||||||
LowPrice string `json:"low"` //24小时最低价
|
LowPrice string `json:"low"` //24小时最低价
|
||||||
Volume string `json:"volume"` //24小时成数量
|
Volume string `json:"volume"` //24小时成数量
|
||||||
QuoteVolume string `json:"quote"` //24小时成交金额
|
QuoteVolume string `json:"quote"` //24小时成交金额
|
||||||
MinQty float64 `json:"minQty"` //最小交易数量
|
MinQty float64 `json:"minQty"` //限价单最小交易数量
|
||||||
MaxQty float64 `json:"maxQty"` //最大交易数量
|
MaxQty float64 `json:"maxQty"` //限价单最大交易数量
|
||||||
MaxNotional string `json:"MaxNotional` //最大名义价值
|
MarketMaxQty float64 `json:"marketQty"` //市价单最大交易数量
|
||||||
MinNotional string `json:"MinNotional` //最大名义价值
|
MarketMinQty float64 `json:"marketMinQty"` //市价单最小交易数量
|
||||||
E int64 `json:"-"` //推送时间
|
MaxNotional string `json:"MaxNotional` //最大名义价值
|
||||||
|
MinNotional string `json:"MinNotional` //最大名义价值
|
||||||
|
E int64 `json:"-"` //推送时间
|
||||||
}
|
}
|
||||||
|
|
||||||
//CommissionType int `db:"commissiontype"` //手续费:1买,2卖,3双向
|
//CommissionType int `db:"commissiontype"` //手续费:1买,2卖,3双向
|
||||||
|
|||||||
54
services/binanceservice/futures_callback.go
Normal file
54
services/binanceservice/futures_callback.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package binanceservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/pkg/utility"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
|
"go-admin/services/positionservice"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
models2 "go-admin/models"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleMarketSliceTakeProfit
|
||||||
|
// @Description: 限价拆分为市价后处理止盈止损
|
||||||
|
func HandleMarketSliceTakeProfit(db *gorm.DB, orderCopy models.LinePreOrder, extOrderId int, apiUserInfo models.LineApiUser, tradeSet models2.TradeSet) {
|
||||||
|
HandleNextFuturesReduce(db, apiUserInfo, orderCopy, tradeSet)
|
||||||
|
|
||||||
|
//延时执行
|
||||||
|
time.AfterFunc(15*time.Second, func() {
|
||||||
|
utility.SafeGo(func() {
|
||||||
|
orderExt := models.LinePreOrderExt{}
|
||||||
|
db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt)
|
||||||
|
positionService := positionservice.BinancePositionManagement{}
|
||||||
|
var side = ""
|
||||||
|
|
||||||
|
if orderCopy.OrderType != 0 {
|
||||||
|
if orderCopy.Site == "BUY" {
|
||||||
|
side = "SELL"
|
||||||
|
} else {
|
||||||
|
side = "BUY"
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
side = orderCopy.Site
|
||||||
|
}
|
||||||
|
|
||||||
|
positionData, err := positionService.GetPosition(orderCopy.ApiId, orderCopy.SymbolType, orderCopy.ExchangeType, orderCopy.Symbol, side)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("获取持仓信息失败,err:", err)
|
||||||
|
} else {
|
||||||
|
sysConfig := cacheservice.GetConfigCacheByKey(db, "market_take_profit_ratio")
|
||||||
|
stopSysConfig := cacheservice.GetConfigCacheByKey(db, "market_stop_loss_ratio")
|
||||||
|
marketTakeProfitRatio := utility.StrToDecimal(sysConfig.ConfigValue)
|
||||||
|
marketStopLossRatio := utility.StrToDecimal(stopSysConfig.ConfigValue)
|
||||||
|
|
||||||
|
FutTakeProfit(db, &orderCopy, apiUserInfo, tradeSet, positionData, orderExt, marketTakeProfitRatio, marketStopLossRatio)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -226,6 +226,11 @@ func GetAndReloadSymbols(data *map[string]models.TradeSet) error {
|
|||||||
tradeSet.MinBuyVal = utility.StringAsFloat(*filter.MinPrice)
|
tradeSet.MinBuyVal = utility.StringAsFloat(*filter.MinPrice)
|
||||||
case "LOT_SIZE":
|
case "LOT_SIZE":
|
||||||
tradeSet.AmountDigit = utility.GetPrecision(*filter.StepSize)
|
tradeSet.AmountDigit = utility.GetPrecision(*filter.StepSize)
|
||||||
|
tradeSet.MaxQty = utility.StringAsFloat(*filter.MaxQty)
|
||||||
|
tradeSet.MinQty = utility.StringAsFloat(*filter.MinQty)
|
||||||
|
case "MARKET_LOT_SIZE":
|
||||||
|
tradeSet.MarketMaxQty = utility.StringAsFloat(*filter.MaxQty)
|
||||||
|
tradeSet.MarketMinQty = utility.StringAsFloat(*filter.MinQty)
|
||||||
case "MIN_NOTIONAL":
|
case "MIN_NOTIONAL":
|
||||||
tradeSet.MinNotional = *filter.Notional
|
tradeSet.MinNotional = *filter.Notional
|
||||||
case "MAX_NOTIONAL":
|
case "MAX_NOTIONAL":
|
||||||
|
|||||||
@ -11,12 +11,14 @@ import (
|
|||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/helper"
|
"go-admin/common/helper"
|
||||||
models2 "go-admin/models"
|
models2 "go-admin/models"
|
||||||
|
"go-admin/models/positiondto"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
log "github.com/go-admin-team/go-admin-core/logger"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -148,26 +150,53 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
positionData := savePosition(db, preOrder)
|
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutReducecCallback, preOrder.ApiId, preOrder.Symbol), 120, 20, 100*time.Millisecond)
|
||||||
|
|
||||||
|
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||||
|
log.Error("获取锁失败", err)
|
||||||
|
return
|
||||||
|
} else if ok {
|
||||||
|
defer lock.Release()
|
||||||
|
positionData := savePosition(db, preOrder)
|
||||||
|
|
||||||
|
//市价单就跳出 市价减仓不设止盈止损
|
||||||
|
if preOrder.MainOrderType == "MARKET" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//亏损大于0 重新计算比例
|
||||||
|
FutTakeProfit(db, preOrder, apiUserInfo, tradeSet, positionData, orderExt, decimal.Zero, decimal.Zero)
|
||||||
|
//处理下一个减仓
|
||||||
|
HandleNextFuturesReduce(db, apiUserInfo, *preOrder, tradeSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 减仓处理止盈止损
|
||||||
|
func FutTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder, apiUserInfo DbModels.LineApiUser, tradeSet models2.TradeSet,
|
||||||
|
positionData positiondto.PositionDto, orderExt DbModels.LinePreOrderExt, manualTakeRatio, manualStopRatio decimal.Decimal) bool {
|
||||||
orders := make([]models.LinePreOrder, 0)
|
orders := make([]models.LinePreOrder, 0)
|
||||||
if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status = 0", preOrder.Id).Find(&orders).Error; err != nil {
|
if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status = 0", preOrder.Id).Find(&orders).Error; err != nil {
|
||||||
logger.Errorf("handleMainReduceFilled 获取待触发订单失败,订单号:%s", preOrder.OrderSn)
|
logger.Errorf("handleMainReduceFilled 获取待触发订单失败,订单号:%s", preOrder.OrderSn)
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
totalNum := getFuturesPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet)
|
totalNum := getFuturesPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet)
|
||||||
price := utility.StrToDecimal(preOrder.Price).Truncate(int32(tradeSet.PriceDigit))
|
price := utility.StrToDecimal(preOrder.Price).Truncate(int32(tradeSet.PriceDigit))
|
||||||
futApi := FutRestApi{}
|
futApi := FutRestApi{}
|
||||||
mainId := preOrder.Id
|
|
||||||
|
|
||||||
if preOrder.MainId > 0 {
|
|
||||||
mainId = preOrder.MainId
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range orders {
|
for _, v := range orders {
|
||||||
if v.OrderType == 1 {
|
if v.OrderType == 1 {
|
||||||
//亏损大于0 重新计算比例
|
//手动设置百分比
|
||||||
if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
|
if manualTakeRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
v.Rate = manualTakeRatio.String()
|
||||||
|
percentag := manualTakeRatio.Div(decimal.NewFromInt(100))
|
||||||
|
|
||||||
|
if positionData.PositionSide == "LONG" {
|
||||||
|
v.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
|
} else {
|
||||||
|
v.Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
|
}
|
||||||
|
} else if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
|
||||||
percentag := positionData.TotalLoss.Div(totalNum).Div(price).Mul(decimal.NewFromInt(100))
|
percentag := positionData.TotalLoss.Div(totalNum).Div(price).Mul(decimal.NewFromInt(100))
|
||||||
percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2)
|
percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2)
|
||||||
v.Rate = percentag.String()
|
v.Rate = percentag.String()
|
||||||
@ -182,9 +211,32 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
|
|
||||||
processFutTakeProfitOrder(db, futApi, v, totalNum)
|
processFutTakeProfitOrder(db, futApi, v, totalNum)
|
||||||
} else if v.OrderType == 2 {
|
} else if v.OrderType == 2 {
|
||||||
|
if manualStopRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
v.Rate = manualStopRatio.String()
|
||||||
|
percentag := manualStopRatio.Div(decimal.NewFromInt(100))
|
||||||
|
|
||||||
|
if positionData.PositionSide == "LONG" {
|
||||||
|
v.Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
|
} else {
|
||||||
|
v.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
|
}
|
||||||
|
}
|
||||||
processFutStopLossOrder(db, v, utility.StrToDecimal(v.Price), totalNum)
|
processFutStopLossOrder(db, v, utility.StrToDecimal(v.Price), totalNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理下一个待触发
|
||||||
|
func HandleNextFuturesReduce(db *gorm.DB, apiUserInfo DbModels.LineApiUser, preOrdedr DbModels.LinePreOrder, tradeSet models2.TradeSet) {
|
||||||
|
mainId := preOrdedr.Id
|
||||||
|
|
||||||
|
if preOrdedr.MainId > 0 {
|
||||||
|
mainId = preOrdedr.MainId
|
||||||
|
}
|
||||||
|
|
||||||
|
totalNum := getFuturesPositionAvailableQuantity(db, apiUserInfo, &preOrdedr, tradeSet)
|
||||||
nextFuturesReduceTrigger(db, mainId, totalNum, tradeSet)
|
nextFuturesReduceTrigger(db, mainId, totalNum, tradeSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +359,7 @@ func handleClosePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
|
|
||||||
if apiUserInfo.Id > 0 {
|
if apiUserInfo.Id > 0 {
|
||||||
mainIds := []int{preOrder.MainId}
|
mainIds := []int{preOrder.MainId}
|
||||||
if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
|
if err := CancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
|
||||||
logger.Errorf("平仓单成功 取消其它订单失败 订单号:%s:", err)
|
logger.Errorf("平仓单成功 取消其它订单失败 订单号:%s:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,7 +380,7 @@ func handleStopLoss(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
|
|
||||||
if apiUserInfo.Id > 0 {
|
if apiUserInfo.Id > 0 {
|
||||||
mainIds := []int{preOrder.MainId}
|
mainIds := []int{preOrder.MainId}
|
||||||
if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
|
if err := CancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
|
||||||
logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err)
|
logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,7 +408,7 @@ func handleTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
|
|
||||||
if apiUserInfo.Id > 0 {
|
if apiUserInfo.Id > 0 {
|
||||||
mainIds := []int{preOrder.MainId}
|
mainIds := []int{preOrder.MainId}
|
||||||
if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
|
if err := CancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
|
||||||
logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err)
|
logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,7 +560,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd
|
|||||||
switch order.OrderType {
|
switch order.OrderType {
|
||||||
case 1: // 止盈
|
case 1: // 止盈
|
||||||
//亏损大于0 重新计算比例
|
//亏损大于0 重新计算比例
|
||||||
if first && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
|
if first && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 && preOrder.SignPriceType != "mixture" {
|
||||||
percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100))
|
percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100))
|
||||||
percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2)
|
percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2)
|
||||||
order.Rate = percentag.String()
|
order.Rate = percentag.String()
|
||||||
@ -591,14 +643,14 @@ func cancelPositionOtherOrders(apiUserInfo DbModels.LineApiUser, db *gorm.DB, pr
|
|||||||
|
|
||||||
// 批量取消订单
|
// 批量取消订单
|
||||||
|
|
||||||
err = cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, changeMainOrderStatus)
|
err = CancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, changeMainOrderStatus)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据mainid 取消订单
|
// 根据mainid 取消订单
|
||||||
// @changeMainOrderStatus 是否更新主单状态
|
// @changeMainOrderStatus 是否更新主单状态
|
||||||
func cancelMainOrders(mainIds []int, db *gorm.DB, apiUserInfo DbModels.LineApiUser, symbol string, changeMainOrderStatus bool) error {
|
func CancelMainOrders(mainIds []int, db *gorm.DB, apiUserInfo DbModels.LineApiUser, symbol string, changeMainOrderStatus bool) error {
|
||||||
if len(mainIds) > 0 {
|
if len(mainIds) > 0 {
|
||||||
orderSns, err := GetOpenOrderSns(db, mainIds)
|
orderSns, err := GetOpenOrderSns(db, mainIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
63
services/binanceservice/spot_callback.go
Normal file
63
services/binanceservice/spot_callback.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package binanceservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
models2 "go-admin/models"
|
||||||
|
"go-admin/pkg/utility"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
|
"go-admin/services/positionservice"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleMarketSliceTakeProfit
|
||||||
|
// @Description: 限价拆分为市价后处理止盈止损
|
||||||
|
func HandleSpotMarketSliceTakeProfit(db *gorm.DB, orderCopy models.LinePreOrder, extOrderId int, apiUserInfo models.LineApiUser, tradeSet models2.TradeSet) {
|
||||||
|
mainId := orderCopy.Id
|
||||||
|
|
||||||
|
if orderCopy.MainId > 0 {
|
||||||
|
mainId = orderCopy.MainId
|
||||||
|
}
|
||||||
|
totalNum := getSpotPositionAvailableQuantity(db, apiUserInfo, &orderCopy, tradeSet) //getSpotTotalNum(apiUserInfo, preOrder, tradeSet)
|
||||||
|
totalNum = totalNum.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
nextSpotReduceTrigger(db, mainId, totalNum, tradeSet)
|
||||||
|
|
||||||
|
//延时执行
|
||||||
|
time.AfterFunc(15*time.Second, func() {
|
||||||
|
utility.SafeGo(func() {
|
||||||
|
orderExt := models.LinePreOrderExt{}
|
||||||
|
db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt)
|
||||||
|
positionService := positionservice.BinancePositionManagement{}
|
||||||
|
var side = ""
|
||||||
|
|
||||||
|
if orderCopy.OrderType != 0 {
|
||||||
|
if orderCopy.Site == "BUY" {
|
||||||
|
side = "SELL"
|
||||||
|
} else {
|
||||||
|
side = "BUY"
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
side = orderCopy.Site
|
||||||
|
}
|
||||||
|
|
||||||
|
positionData, err := positionService.GetPosition(orderCopy.ApiId, orderCopy.SymbolType, orderCopy.ExchangeType, orderCopy.Symbol, side)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("获取持仓信息失败,err:", err)
|
||||||
|
} else {
|
||||||
|
sysConfig := cacheservice.GetConfigCacheByKey(db, "market_take_profit_ratio")
|
||||||
|
stopSysConfig := cacheservice.GetConfigCacheByKey(db, "market_stop_loss_ratio")
|
||||||
|
marketTakeProfitRatio := utility.StrToDecimal(sysConfig.ConfigValue)
|
||||||
|
marketStopLossRatio := utility.StrToDecimal(stopSysConfig.ConfigValue)
|
||||||
|
totalNum := getSpotPositionAvailableQuantity(db, apiUserInfo, &orderCopy, tradeSet) //getSpotTotalNum(apiUserInfo, preOrder, tradeSet)
|
||||||
|
totalNum = totalNum.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
|
||||||
|
SpotTakeProfit(db, &orderCopy, totalNum, positionData, orderExt, tradeSet, marketTakeProfitRatio, marketStopLossRatio)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
log "github.com/go-admin-team/go-admin-core/logger"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -173,34 +174,60 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
|
|
||||||
orderExt := models.LinePreOrderExt{}
|
orderExt := models.LinePreOrderExt{}
|
||||||
positionData := savePosition(db, preOrder)
|
positionData := savePosition(db, preOrder)
|
||||||
orders := make([]models.LinePreOrder, 0)
|
|
||||||
// rate := utility.StringAsFloat(preOrder.Rate)
|
|
||||||
|
|
||||||
if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id =? ", preOrder.MainId).Update("reduce_status", 1).Error; err != nil {
|
if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id =? ", preOrder.MainId).Update("reduce_status", 1).Error; err != nil {
|
||||||
logger.Errorf("handleMainReduceFilled 更新主单减仓状态失败,订单号:%s", preOrder.OrderSn)
|
logger.Errorf("handleMainReduceFilled 更新主单减仓状态失败,订单号:%s", preOrder.OrderSn)
|
||||||
}
|
}
|
||||||
db.Model(&orderExt).Where("order_id =?", preOrder.Id).Find(&orderExt)
|
db.Model(&orderExt).Where("order_id =?", preOrder.Id).Find(&orderExt)
|
||||||
|
|
||||||
// 100%减仓 终止流程
|
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotReduceCallback, preOrder.ApiId, preOrder.Symbol), 120, 20, 100*time.Millisecond)
|
||||||
if orderExt.AddPositionVal.Cmp(decimal.NewFromInt(100)) >= 0 {
|
|
||||||
//缓存
|
|
||||||
removeSpotLossAndAddPosition(preOrder.MainId, preOrder.OrderSn)
|
|
||||||
removePosition(db, preOrder)
|
|
||||||
|
|
||||||
ids := []int{preOrder.MainId, preOrder.Pid}
|
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6", ids).Update("status", 9).Error; err != nil {
|
log.Error("获取锁失败", err)
|
||||||
logger.Info("100%减仓完毕,终结流程")
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
} else if ok {
|
||||||
|
defer lock.Release()
|
||||||
|
// 100%减仓 终止流程
|
||||||
|
if orderExt.AddPositionVal.Cmp(decimal.NewFromInt(100)) >= 0 {
|
||||||
|
//缓存
|
||||||
|
removeSpotLossAndAddPosition(preOrder.MainId, preOrder.OrderSn)
|
||||||
|
removePosition(db, preOrder)
|
||||||
|
|
||||||
totalNum := getSpotPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet) //getSpotTotalNum(apiUserInfo, preOrder, tradeSet)
|
ids := []int{preOrder.MainId, preOrder.Pid}
|
||||||
totalNum = totalNum.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit))
|
if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6", ids).Update("status", 9).Error; err != nil {
|
||||||
|
logger.Info("100%减仓完毕,终结流程")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//市价单跳出
|
||||||
|
if preOrder.MainOrderType == "MARKET" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
totalNum := getSpotPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet) //getSpotTotalNum(apiUserInfo, preOrder, tradeSet)
|
||||||
|
totalNum = totalNum.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
//亏损大于0 重新计算比例
|
||||||
|
SpotTakeProfit(db, preOrder, totalNum, positionData, orderExt, tradeSet, decimal.Zero, decimal.Zero)
|
||||||
|
|
||||||
|
mainId := preOrder.Id
|
||||||
|
|
||||||
|
if preOrder.MainId > 0 {
|
||||||
|
mainId = preOrder.MainId
|
||||||
|
}
|
||||||
|
|
||||||
|
nextSpotReduceTrigger(db, mainId, totalNum, tradeSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SpotTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder, totalNum decimal.Decimal,
|
||||||
|
positionData positiondto.PositionDto, orderExt DbModels.LinePreOrderExt, tradeSet models2.TradeSet, manualTakeRatio, manualStopRatio decimal.Decimal) bool {
|
||||||
price := utility.StrToDecimal(preOrder.Price)
|
price := utility.StrToDecimal(preOrder.Price)
|
||||||
|
orders := make([]models.LinePreOrder, 0)
|
||||||
|
|
||||||
if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status=0", preOrder.Id).Find(&orders).Error; err != nil {
|
if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status=0", preOrder.Id).Find(&orders).Error; err != nil {
|
||||||
logger.Errorf("获取减仓单止盈止损失败 err:%v", err)
|
logger.Errorf("获取减仓单止盈止损失败 err:%v", err)
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
spotApi := SpotRestApi{}
|
spotApi := SpotRestApi{}
|
||||||
@ -209,8 +236,17 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
orders[index].Num = totalNum.String()
|
orders[index].Num = totalNum.String()
|
||||||
|
|
||||||
if orders[index].OrderType == 1 {
|
if orders[index].OrderType == 1 {
|
||||||
//亏损大于0 重新计算比例
|
//手动设置百分比
|
||||||
if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
|
if manualTakeRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
orders[index].Rate = manualTakeRatio.String()
|
||||||
|
percentag := manualTakeRatio.Div(decimal.NewFromInt(100))
|
||||||
|
|
||||||
|
if positionData.PositionSide == "LONG" {
|
||||||
|
orders[index].Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
|
} else {
|
||||||
|
orders[index].Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
|
}
|
||||||
|
} else if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
|
||||||
percentag := positionData.TotalLoss.Div(totalNum).Div(price).Mul(decimal.NewFromInt(100))
|
percentag := positionData.TotalLoss.Div(totalNum).Div(price).Mul(decimal.NewFromInt(100))
|
||||||
percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2)
|
percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2)
|
||||||
orders[index].Rate = percentag.String()
|
orders[index].Rate = percentag.String()
|
||||||
@ -220,17 +256,20 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
|
|
||||||
processTakeProfitOrder(db, spotApi, orders[index])
|
processTakeProfitOrder(db, spotApi, orders[index])
|
||||||
} else if orders[index].OrderType == 2 {
|
} else if orders[index].OrderType == 2 {
|
||||||
|
if manualStopRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
orders[index].Rate = manualStopRatio.String()
|
||||||
|
percentag := manualStopRatio.Div(decimal.NewFromInt(100))
|
||||||
|
|
||||||
|
if positionData.PositionSide == "LONG" {
|
||||||
|
orders[index].Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
|
} else {
|
||||||
|
orders[index].Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
|
}
|
||||||
|
}
|
||||||
processStopLossOrder(orders[index])
|
processStopLossOrder(orders[index])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
mainId := preOrder.Id
|
|
||||||
|
|
||||||
if preOrder.MainId > 0 {
|
|
||||||
mainId = preOrder.MainId
|
|
||||||
}
|
|
||||||
|
|
||||||
nextSpotReduceTrigger(db, mainId, totalNum, tradeSet)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 缓存下一个减仓单
|
// 缓存下一个减仓单
|
||||||
@ -751,7 +790,7 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd
|
|||||||
switch order.OrderType {
|
switch order.OrderType {
|
||||||
case 1: // 止盈
|
case 1: // 止盈
|
||||||
//亏损大于0 重新计算比例
|
//亏损大于0 重新计算比例
|
||||||
if fist && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
|
if fist && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 && preOrder.SignPriceType != "mixture" {
|
||||||
percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100))
|
percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100))
|
||||||
|
|
||||||
if fist {
|
if fist {
|
||||||
|
|||||||
@ -43,6 +43,9 @@ func GetSpotSymbols() (map[string]models.TradeSet, []string, error) {
|
|||||||
tradeSet.AmountDigit = utility.GetPrecision(filter.StepSize)
|
tradeSet.AmountDigit = utility.GetPrecision(filter.StepSize)
|
||||||
tradeSet.MinQty = utility.StringAsFloat(filter.MinQty)
|
tradeSet.MinQty = utility.StringAsFloat(filter.MinQty)
|
||||||
tradeSet.MaxQty = utility.StringAsFloat(filter.MaxQty)
|
tradeSet.MaxQty = utility.StringAsFloat(filter.MaxQty)
|
||||||
|
case "MARKET_LOT_SIZE":
|
||||||
|
tradeSet.MarketMinQty = utility.StringAsFloat(filter.MinQty)
|
||||||
|
tradeSet.MarketMinQty = utility.StringAsFloat(filter.MaxQty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
61
services/cacheservice/config_service.go
Normal file
61
services/cacheservice/config_service.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package cacheservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 加载config缓存
|
||||||
|
func InitConfigCache(db *gorm.DB) {
|
||||||
|
datas := []models.SysConfig{}
|
||||||
|
db.Model(&models.SysConfig{}).Find(&datas)
|
||||||
|
for _, item := range datas {
|
||||||
|
cacheKey := fmt.Sprintf(rediskey.SysConfigKey, item.ConfigKey)
|
||||||
|
|
||||||
|
content, err := sonic.Marshal(item)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(content) > 0 {
|
||||||
|
helper.DefaultRedis.SetString(cacheKey, item.ConfigValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 sys config缓存
|
||||||
|
func GetConfigCacheByKey(db *gorm.DB, key string) models.SysConfig {
|
||||||
|
cacheKey := fmt.Sprintf(rediskey.SysConfigKey, key)
|
||||||
|
val, _ := helper.DefaultRedis.GetString(key)
|
||||||
|
result := models.SysConfig{}
|
||||||
|
|
||||||
|
if val == "" {
|
||||||
|
sonic.Unmarshal([]byte(val), &result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Id == 0 {
|
||||||
|
if err := db.Model(&result).Where("config_key = ?", key).First(&result).Error; err != nil {
|
||||||
|
logger.Errorf("GetConfigCacheByKey %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Id > 0 {
|
||||||
|
content, err := sonic.Marshal(result)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("GetConfigCacheByKey %s", err.Error())
|
||||||
|
} else {
|
||||||
|
helper.DefaultRedis.SetString(cacheKey, string(content))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user