1撤销限价后 市价分单
This commit is contained in:
@ -52,11 +52,11 @@ func (e LineApiUser) GetPage(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
for i, apiUser := range list {
|
||||
if apiUser.UserId <= 0 {
|
||||
list[i].OpenStatus = 1
|
||||
}
|
||||
}
|
||||
// for i, apiUser := range list {
|
||||
// if apiUser.UserId <= 0 {
|
||||
// list[i].OpenStatus = 1
|
||||
// }
|
||||
// }
|
||||
|
||||
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)
|
||||
errs := make([]error, 0)
|
||||
errStr := make([]string, 0)
|
||||
var msg string
|
||||
var tickerSymbol string
|
||||
if req.SymbolType == global.SYMBOL_SPOT {
|
||||
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
|
||||
} else {
|
||||
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 {
|
||||
//e.Logger.Error(err)
|
||||
for _, err2 := range errs {
|
||||
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)
|
||||
errStr := make([]string, 0)
|
||||
userId := user.GetUserId(c)
|
||||
|
||||
var msg string
|
||||
if userId <= 0 {
|
||||
e.Error(500, nil, "用户不存在")
|
||||
return
|
||||
}
|
||||
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 {
|
||||
//e.Logger.Error(err)
|
||||
for _, err2 := range errs {
|
||||
errStr = append(errStr, err2.Error())
|
||||
}
|
||||
e.Error(500, nil, strings.Join(errStr, ","))
|
||||
return
|
||||
msg = strings.Join(errStr, ",")
|
||||
}
|
||||
e.OK(nil, "操作成功")
|
||||
e.OK(msg, "操作成功")
|
||||
}
|
||||
|
||||
// QuickAddPreOrder 模板快速下单
|
||||
@ -409,22 +417,27 @@ func (e LinePreOrder) QuickAddPreOrder(c *gin.Context) {
|
||||
errs := make([]error, 0)
|
||||
errStr := make([]string, 0)
|
||||
userId := user.GetUserId(c)
|
||||
var msg string
|
||||
|
||||
if userId <= 0 {
|
||||
e.Error(500, nil, "用户不存在")
|
||||
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 {
|
||||
//e.Logger.Error(err)
|
||||
for _, err2 := range errs {
|
||||
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, "创建失败")
|
||||
return
|
||||
}
|
||||
|
||||
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:"->"`
|
||||
AddPositionStatus int `json:"add_position_status" gorm:"->"`
|
||||
ReduceStatus int `json:"reduce_status" gorm:"->"`
|
||||
Childs []LinePreOrder `json:"childs" gorm:"foreignKey:pid;references:id"`
|
||||
// LinePreOrder 线上预埋单\
|
||||
models.ModelTime
|
||||
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 {
|
||||
dto.Pagination `search:"-"`
|
||||
ExchangeType string `form:"exchangeType" search:"-"`
|
||||
OpenStatus *int `form:"openStatus" search:"-" comment:"开启状态 0-关闭 1-开启"`
|
||||
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"` //订单类型
|
||||
Symbol string `json:"symbol"` //交易对
|
||||
ApiUserId string `json:"api_id" ` //下单用户
|
||||
ApiIdType int `json:"api_id_type"` //下单用户类型
|
||||
ApiUserGroupId int `json:"api_user_group_id"` //下单用户组
|
||||
Site string `json:"site" ` //购买方向
|
||||
BuyPrice string `json:"buy_price" vd:"$>0"` //购买金额 U
|
||||
PricePattern string `json:"price_pattern"` //价格模式
|
||||
@ -368,6 +370,8 @@ type LineBatchAddPreOrderReq struct {
|
||||
SymbolGroupId string `json:"symbol_group_id"` //交易对组id
|
||||
Symbol string `json:"symbol"` //交易对
|
||||
ApiUserId string `json:"api_id"` //下单用户
|
||||
ApiIdType int `json:"api_id_type"` //下单用户类型
|
||||
ApiUserGroupId int `json:"api_user_group_id"` //下单用户组
|
||||
Site string `json:"site"` //购买方向
|
||||
BuyPrice string `json:"buy_price"` //购买金额 U
|
||||
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)
|
||||
}
|
||||
|
||||
if c.OpenStatus != nil {
|
||||
query.Where("open_status = ?", c.OpenStatus)
|
||||
}
|
||||
|
||||
err = query.
|
||||
Find(list).Limit(-1).Offset(-1).
|
||||
Count(count).Error
|
||||
@ -188,6 +192,7 @@ func OpenUserBinanceWebsocket(item models.LineApiUser) {
|
||||
func (e *LineApiUser) Update(c *dto.LineApiUserUpdateReq, p *actions.DataPermission) error {
|
||||
var err error
|
||||
var data = models.LineApiUser{}
|
||||
|
||||
e.Orm.Scopes(
|
||||
actions.Permission(data.TableName(), p),
|
||||
).First(&data, c.GetId())
|
||||
@ -195,14 +200,31 @@ func (e *LineApiUser) Update(c *dto.LineApiUserUpdateReq, p *actions.DataPermiss
|
||||
|
||||
c.Generate(&data)
|
||||
|
||||
db := e.Orm.Save(&data)
|
||||
if err = db.Error; err != nil {
|
||||
e.Log.Errorf("LineApiUserService Save error:%s \r\n", err)
|
||||
updateGroups, err := e.GetUpdateGroups(c.Id)
|
||||
|
||||
//事务
|
||||
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
|
||||
}
|
||||
if db.RowsAffected == 0 {
|
||||
return errors.New("无权更新该数据")
|
||||
}
|
||||
|
||||
e.saveCache(data)
|
||||
|
||||
@ -224,6 +246,24 @@ func (e *LineApiUser) Update(c *dto.LineApiUserUpdateReq, p *actions.DataPermiss
|
||||
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
|
||||
func (e *LineApiUser) Remove(d *dto.LineApiUserDeleteReq, p *actions.DataPermission) error {
|
||||
var data models.LineApiUser
|
||||
@ -347,3 +387,30 @@ func (e *LineApiUser) GetMainUser(req *dto.GetMainUserReq, list *[]models.LineAp
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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, ",")
|
||||
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= 保存模板并下单
|
||||
var templateLog dto.LineAddPreOrderReq
|
||||
copier.Copy(&templateLog, req)
|
||||
@ -412,7 +437,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
|
||||
for _, id := range apiUserIds {
|
||||
if req.Site == "SELL" && req.SymbolType == global.SYMBOL_SPOT {
|
||||
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 现货不支持卖出操作", id, req.Symbol))
|
||||
*errs = append(*errs, fmt.Errorf("api_id:%v 获取交易对:%s 现货不支持卖出操作", id, req.Symbol))
|
||||
continue
|
||||
}
|
||||
var AddOrder models.LinePreOrder
|
||||
@ -500,7 +525,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
continue
|
||||
}
|
||||
AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
AddOrder.ApiId, _ = strconv.Atoi(id)
|
||||
AddOrder.ApiId = id
|
||||
AddOrder.Symbol = req.Symbol
|
||||
AddOrder.QuoteSymbol = symbolInfo.QuoteAsset
|
||||
AddOrder.Pid = 0
|
||||
@ -651,14 +676,20 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
profitOrder.Rate = "0"
|
||||
} else {
|
||||
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()
|
||||
} 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.Rate = req.Profit
|
||||
}
|
||||
|
||||
if strings.ToUpper(req.Site) == "BUY" {
|
||||
profitOrder.Site = "SELL"
|
||||
} else {
|
||||
profitOrder.Site = "BUY"
|
||||
}
|
||||
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
profitOrder.Pid = AddOrder.Id
|
||||
profitOrder.OrderType = 1
|
||||
@ -696,15 +727,21 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
stopOrder.Rate = "0"
|
||||
} else {
|
||||
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()
|
||||
} 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.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.Pid = AddOrder.Id
|
||||
stopOrder.MainId = AddOrder.Id
|
||||
@ -1078,10 +1115,34 @@ func (e *LinePreOrder) CheckRepeatOrder(symbolType int, apiUserId, site, baseCoi
|
||||
|
||||
// AddBatchPreOrder 批量添加
|
||||
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= 保存模板并下单
|
||||
var templateLog dto.LineBatchAddPreOrderReq
|
||||
copier.Copy(&templateLog, batchReq)
|
||||
//templateLog = *batchReq
|
||||
templateLog.SaveTemplate = "0"
|
||||
templateLog.TemplateName = ""
|
||||
marshal, _ := sonic.Marshal(templateLog)
|
||||
@ -1112,80 +1173,81 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
|
||||
}
|
||||
|
||||
//脚本次数
|
||||
if batchReq.OrderNum > 0 {
|
||||
var tickerSymbol string
|
||||
if batchReq.SymbolType == global.SYMBOL_SPOT {
|
||||
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
|
||||
} else {
|
||||
tickerSymbol = helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val()
|
||||
}
|
||||
apiUserIds := strings.Split(batchReq.ApiUserId, ",")
|
||||
if batchReq.Script == "1" {
|
||||
//scriptLogs := make([]models.LinePreScript, 0)
|
||||
logParams := *batchReq
|
||||
for _, id := range apiUserIds {
|
||||
for j := 1; j <= batchReq.OrderNum; j++ {
|
||||
var log models.LinePreScript
|
||||
logParams.SaveTemplate = "0"
|
||||
logParams.TemplateName = ""
|
||||
logParams.Script = ""
|
||||
marshal, _ := sonic.Marshal(logParams)
|
||||
log.ApiId = int64(utility.StringToInt(id))
|
||||
log.ScriptNum = int64(j)
|
||||
log.ScriptParams = string(marshal)
|
||||
log.AdminId = 0
|
||||
log.Status = "0"
|
||||
//scriptLogs = append(scriptLogs, log)
|
||||
err := e.Orm.Model(&models.LinePreScript{}).Create(&log).Error
|
||||
if err != nil {
|
||||
*errs = append(*errs, fmt.Errorf("记录脚本失败:%+v", err.Error()))
|
||||
return nil
|
||||
}
|
||||
helper.DefaultRedis.RPushList(rediskey.PreOrderScriptList, utility.IntToString(log.Id))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
for _, id := range apiUserIds {
|
||||
for j := 0; j < batchReq.OrderNum; j++ {
|
||||
symbols := strings.Split(batchReq.Symbol, ",")
|
||||
for _, symbol := range symbols {
|
||||
var req dto.LineAddPreOrderReq
|
||||
req.ExchangeType = batchReq.ExchangeType
|
||||
req.OrderType = batchReq.OrderType
|
||||
req.Symbol = symbol
|
||||
req.ApiUserId = id
|
||||
req.Site = batchReq.Site
|
||||
req.BuyPrice = batchReq.BuyPrice
|
||||
req.PricePattern = batchReq.PricePattern
|
||||
req.Price = batchReq.Price
|
||||
req.Profit = batchReq.Profit
|
||||
req.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
|
||||
// if batchReq.OrderNum > 0 {
|
||||
apiUserIds := strings.Split(batchReq.ApiUserId, ",")
|
||||
var tickerSymbol string
|
||||
if batchReq.SymbolType == global.SYMBOL_SPOT {
|
||||
tickerSymbol = helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
|
||||
} 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
|
||||
}
|
||||
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 模板快速下单
|
||||
@ -1204,7 +1266,8 @@ func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *ac
|
||||
} else {
|
||||
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 {
|
||||
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", addPreOrderParams.ApiUserId, addPreOrderParams.Symbol))
|
||||
continue
|
||||
|
||||
@ -26,7 +26,7 @@ func (e *LineSymbolGroup) GetPage(c *dto.LineSymbolGroupGetPageReq, p *actions.D
|
||||
Scopes(
|
||||
cDto.MakeCondition(c.GetNeedSearch()),
|
||||
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||
actions.Permission(data.TableName(), p),
|
||||
// actions.Permission(data.TableName(), p),
|
||||
)
|
||||
if 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 {
|
||||
var apiUser models.LineApiUser
|
||||
user := models.LineUser{}
|
||||
apiUserService := LineApiUser{Service: e.Service}
|
||||
e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser)
|
||||
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
@ -2,11 +2,15 @@ package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"go-admin/app/admin/models"
|
||||
"go-admin/app/admin/service/dto"
|
||||
"go-admin/common/const/rediskey"
|
||||
cDto "go-admin/common/dto"
|
||||
"go-admin/common/helper"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"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)
|
||||
return err
|
||||
}
|
||||
|
||||
key := fmt.Sprintf(rediskey.SysConfigKey, c.ConfigKey)
|
||||
content, _ := sonic.MarshalString(data)
|
||||
|
||||
if content != "" {
|
||||
helper.DefaultRedis.SetString(key, content)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -76,7 +87,13 @@ func (e *SysConfig) Update(c *dto.SysConfigControl) error {
|
||||
}
|
||||
if db.RowsAffected == 0 {
|
||||
return errors.New("无权更新该数据")
|
||||
}
|
||||
|
||||
key := fmt.Sprintf(rediskey.SysConfigKey, c.ConfigKey)
|
||||
content, _ := sonic.MarshalString(model)
|
||||
|
||||
if content != "" {
|
||||
helper.DefaultRedis.SetString(key, content)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -133,7 +150,6 @@ func (e *SysConfig) UpdateForSet(c *[]dto.GetSetSysConfigReq) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -143,6 +159,9 @@ func (e *SysConfig) UpdateForSet(c *[]dto.GetSetSysConfigReq) error {
|
||||
func (e *SysConfig) Remove(d *dto.SysConfigDeleteReq) error {
|
||||
var err error
|
||||
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)
|
||||
if err = db.Error; err != nil {
|
||||
@ -153,6 +172,14 @@ func (e *SysConfig) Remove(d *dto.SysConfigDeleteReq) error {
|
||||
err = errors.New("无权删除该数据")
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@ -2,11 +2,12 @@ package jobs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
models2 "go-admin/app/jobs/models"
|
||||
"time"
|
||||
|
||||
log "github.com/go-admin-team/go-admin-core/logger"
|
||||
"github.com/go-admin-team/go-admin-core/sdk"
|
||||
models2 "go-admin/app/jobs/models"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
@ -40,6 +41,12 @@ type ExecJob struct {
|
||||
}
|
||||
|
||||
func (e *ExecJob) Run() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Errorf("脚本任务失败:%v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
startTime := time.Now()
|
||||
var obj = jobList[e.InvokeTarget]
|
||||
if obj == nil {
|
||||
|
||||
261
app/jobs/jobs.go
261
app/jobs/jobs.go
@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/driver/mysql"
|
||||
|
||||
@ -158,7 +159,6 @@ func (t AutoPlaceOrder) Exec(arg interface{}) error {
|
||||
}
|
||||
|
||||
func (t LimitOrderTimeoutDuration) Exec(arg interface{}) error {
|
||||
|
||||
str := time.Now().Format(timeFormat) + " [INFO] JobCore ClearLogJob exec success"
|
||||
defer logger.Info(str)
|
||||
var db *gorm.DB
|
||||
@ -188,7 +188,10 @@ func (t LimitOrderTimeoutDuration) Exec(arg interface{}) error {
|
||||
defer lock.Release()
|
||||
limitOrderTimeoutDuration := utility.StringAsInt64(resp.ConfigValue)
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -228,6 +231,7 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
||||
for i := 0; i < 3; i++ {
|
||||
err = spotApi.CancelOpenOrderByOrderSn(apiUserinfo, order.Symbol, order.OrderSn)
|
||||
if err == nil || strings.Contains(err.Error(), "该交易对没有订单") {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -237,11 +241,12 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
||||
} else {
|
||||
var remainingQuantity decimal.Decimal
|
||||
spotOrder, err := spotApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||
|
||||
if err == nil {
|
||||
origQty := utility.StrToDecimal(spotOrder.OrigQuoteOrderQty)
|
||||
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||
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 {
|
||||
@ -249,36 +254,62 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
||||
return nil
|
||||
}
|
||||
|
||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||
newClientOrderId := snowflakehelper.GetOrderId()
|
||||
maxMarketQty := decimal.NewFromFloat(tradeSet.MarketMaxQty).Truncate(int32(tradeSet.AmountDigit))
|
||||
|
||||
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单源订单号:%s ", order.OrderSn)
|
||||
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 config.ApplicationConfig.Mode == "dev" {
|
||||
// maxMarketQty = decimal.NewFromFloat(10)
|
||||
// }
|
||||
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err))
|
||||
return err
|
||||
}
|
||||
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: utility.Int64ToString(newClientOrderId),
|
||||
}
|
||||
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 remainingQuantity.Cmp(maxMarketQty) > 0 && maxMarketQty.Cmp(decimal.Zero) > 0 {
|
||||
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 := 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 {
|
||||
logger.Error("下单失败后修改订单失败")
|
||||
logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
if err := newSpotOrderClosePosition(order, remainingQuantity, spotApi, db); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -287,12 +318,38 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
||||
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 重下合约市价单
|
||||
func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.LinePreOrder, apiUserinfo models.LineApiUser, futApi binanceservice.FutRestApi) error {
|
||||
var err error
|
||||
for i := 0; i < 3; i++ {
|
||||
err := futApi.CancelFutOrder(apiUserinfo, order.Symbol, order.OrderSn)
|
||||
if err == nil || strings.Contains(err.Error(), "该交易对没有订单") {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -302,11 +359,12 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
||||
} else {
|
||||
var remainingQuantity decimal.Decimal
|
||||
spotOrder, err := futApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 1)
|
||||
|
||||
if err == nil {
|
||||
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||
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 {
|
||||
@ -314,51 +372,62 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
||||
return nil
|
||||
}
|
||||
|
||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||
qty := decimal.NewFromFloat(tradeSet.MarketMaxQty)
|
||||
maxMarketQty := qty.Truncate(int32(tradeSet.AmountDigit))
|
||||
|
||||
newClientOrderId := snowflakehelper.GetOrderId()
|
||||
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
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 config.ApplicationConfig.Mode == "dev" {
|
||||
// maxMarketQty = decimal.NewFromFloat(10)
|
||||
// }
|
||||
|
||||
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 remainingQuantity.Cmp(maxMarketQty) > 0 && maxMarketQty.Cmp(decimal.Zero) > 0 {
|
||||
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 {
|
||||
logger.Error("下单失败后修改订单失败")
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -366,6 +435,54 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
||||
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 {
|
||||
str := time.Now().Format(timeFormat) + " [INFO] JobCore ClearLogJob exec success"
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user