Compare commits
12 Commits
9ca1cd9a19
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e4286de50 | |||
| 0f9b966fdb | |||
| 7b50873de3 | |||
| 44ba8bfbf1 | |||
| 79af1ab2c1 | |||
| e3a737a7d6 | |||
| d4c8e692a7 | |||
| a9fc1c87f5 | |||
| 1512216bab | |||
| 8e8c78ec0b | |||
| cdd3f951a2 | |||
| 0b95e32655 |
205
app/admin/apis/line_reduce_strategy.go
Normal file
205
app/admin/apis/line_reduce_strategy.go
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
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 LineReduceStrategy struct {
|
||||||
|
api.Api
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取减仓策略列表
|
||||||
|
// @Summary 获取减仓策略列表
|
||||||
|
// @Description 获取减仓策略列表
|
||||||
|
// @Tags 减仓策略
|
||||||
|
// @Param name query string false "减仓策略名称"
|
||||||
|
// @Param status query string false "状态 1-启用 2-禁用"
|
||||||
|
// @Param pageSize query int false "页条数"
|
||||||
|
// @Param pageIndex query int false "页码"
|
||||||
|
// @Success 200 {object} response.Response{data=response.Page{list=[]models.LineReduceStrategy}} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategy) GetPage(c *gin.Context) {
|
||||||
|
req := dto.LineReduceStrategyGetPageReq{}
|
||||||
|
s := service.LineReduceStrategy{}
|
||||||
|
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.LineReduceStrategy, 0)
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
err = s.GetPage(&req, p, &list, &count)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取减仓策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取减仓策略
|
||||||
|
// @Summary 获取减仓策略
|
||||||
|
// @Description 获取减仓策略
|
||||||
|
// @Tags 减仓策略
|
||||||
|
// @Param id path int false "id"
|
||||||
|
// @Success 200 {object} response.Response{data=models.LineReduceStrategy} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy/{id} [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategy) Get(c *gin.Context) {
|
||||||
|
req := dto.LineReduceStrategyGetReq{}
|
||||||
|
s := service.LineReduceStrategy{}
|
||||||
|
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.LineReduceStrategy
|
||||||
|
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
err = s.Get(&req, p, &object)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取减仓策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(object, "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建减仓策略
|
||||||
|
// @Summary 创建减仓策略
|
||||||
|
// @Description 创建减仓策略
|
||||||
|
// @Tags 减仓策略
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.LineReduceStrategyInsertReq true "data"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy [post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategy) Insert(c *gin.Context) {
|
||||||
|
req := dto.LineReduceStrategyInsertReq{}
|
||||||
|
s := service.LineReduceStrategy{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.Valid(); err != nil {
|
||||||
|
e.Error(500, err, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置创建人
|
||||||
|
req.SetCreateBy(user.GetUserId(c))
|
||||||
|
|
||||||
|
err = s.Insert(&req)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("创建减仓策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(req.GetId(), "创建成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改减仓策略
|
||||||
|
// @Summary 修改减仓策略
|
||||||
|
// @Description 修改减仓策略
|
||||||
|
// @Tags 减仓策略
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param id path int true "id"
|
||||||
|
// @Param data body dto.LineReduceStrategyUpdateReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy/{id} [put]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategy) Update(c *gin.Context) {
|
||||||
|
req := dto.LineReduceStrategyUpdateReq{}
|
||||||
|
s := service.LineReduceStrategy{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.Valid(); err != nil {
|
||||||
|
e.Error(500, err, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.SetUpdateBy(user.GetUserId(c))
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
|
||||||
|
err = s.Update(&req, p)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("修改减仓策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(req.GetId(), "修改成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除减仓策略
|
||||||
|
// @Summary 删除减仓策略
|
||||||
|
// @Description 删除减仓策略
|
||||||
|
// @Tags 减仓策略
|
||||||
|
// @Param data body dto.LineReduceStrategyDeleteReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategy) Delete(c *gin.Context) {
|
||||||
|
s := service.LineReduceStrategy{}
|
||||||
|
req := dto.LineReduceStrategyDeleteReq{}
|
||||||
|
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("删除减仓策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(req.GetId(), "删除成功")
|
||||||
|
}
|
||||||
191
app/admin/apis/line_reduce_strategy_item.go
Normal file
191
app/admin/apis/line_reduce_strategy_item.go
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
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 LineReduceStrategyItem struct {
|
||||||
|
api.Api
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取减仓策略明细列表
|
||||||
|
// @Summary 获取减仓策略明细列表
|
||||||
|
// @Description 获取减仓策略明细列表
|
||||||
|
// @Tags 减仓策略明细
|
||||||
|
// @Param pageSize query int false "页条数"
|
||||||
|
// @Param pageIndex query int false "页码"
|
||||||
|
// @Success 200 {object} response.Response{data=response.Page{list=[]models.LineReduceStrategyItem}} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy-item [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategyItem) GetPage(c *gin.Context) {
|
||||||
|
req := dto.LineReduceStrategyItemGetPageReq{}
|
||||||
|
s := service.LineReduceStrategyItem{}
|
||||||
|
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.LineReduceStrategyItem, 0)
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
err = s.GetPage(&req, p, &list, &count)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取减仓策略明细失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取减仓策略明细
|
||||||
|
// @Summary 获取减仓策略明细
|
||||||
|
// @Description 获取减仓策略明细
|
||||||
|
// @Tags 减仓策略明细
|
||||||
|
// @Param id path int false "id"
|
||||||
|
// @Success 200 {object} response.Response{data=models.LineReduceStrategyItem} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy-item/{id} [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategyItem) Get(c *gin.Context) {
|
||||||
|
req := dto.LineReduceStrategyItemGetReq{}
|
||||||
|
s := service.LineReduceStrategyItem{}
|
||||||
|
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.LineReduceStrategyItem
|
||||||
|
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
err = s.Get(&req, p, &object)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取减仓策略明细失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK( object, "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建减仓策略明细
|
||||||
|
// @Summary 创建减仓策略明细
|
||||||
|
// @Description 创建减仓策略明细
|
||||||
|
// @Tags 减仓策略明细
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.LineReduceStrategyItemInsertReq true "data"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy-item [post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategyItem) Insert(c *gin.Context) {
|
||||||
|
req := dto.LineReduceStrategyItemInsertReq{}
|
||||||
|
s := service.LineReduceStrategyItem{}
|
||||||
|
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))
|
||||||
|
|
||||||
|
err = s.Insert(&req)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("创建减仓策略明细失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(req.GetId(), "创建成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改减仓策略明细
|
||||||
|
// @Summary 修改减仓策略明细
|
||||||
|
// @Description 修改减仓策略明细
|
||||||
|
// @Tags 减仓策略明细
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param id path int true "id"
|
||||||
|
// @Param data body dto.LineReduceStrategyItemUpdateReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy-item/{id} [put]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategyItem) Update(c *gin.Context) {
|
||||||
|
req := dto.LineReduceStrategyItemUpdateReq{}
|
||||||
|
s := service.LineReduceStrategyItem{}
|
||||||
|
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.Update(&req, p)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("修改减仓策略明细失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK( req.GetId(), "修改成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除减仓策略明细
|
||||||
|
// @Summary 删除减仓策略明细
|
||||||
|
// @Description 删除减仓策略明细
|
||||||
|
// @Tags 减仓策略明细
|
||||||
|
// @Param data body dto.LineReduceStrategyItemDeleteReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
|
||||||
|
// @Router /api/v1/line-reduce-strategy-item [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineReduceStrategyItem) Delete(c *gin.Context) {
|
||||||
|
s := service.LineReduceStrategyItem{}
|
||||||
|
req := dto.LineReduceStrategyItemDeleteReq{}
|
||||||
|
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("删除减仓策略明细失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK( req.GetId(), "删除成功")
|
||||||
|
}
|
||||||
206
app/admin/apis/line_strategy_template.go
Normal file
206
app/admin/apis/line_strategy_template.go
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
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 LineStrategyTemplate struct {
|
||||||
|
api.Api
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取波段策略列表
|
||||||
|
// @Summary 获取波段策略列表
|
||||||
|
// @Description 获取波段策略列表
|
||||||
|
// @Tags 波段策略
|
||||||
|
// @Param direction query int false "涨跌方向 1-涨 2-跌"
|
||||||
|
// @Param percentag query decimal.Decimal false "涨跌点数"
|
||||||
|
// @Param compareType query int false "比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "
|
||||||
|
// @Param pageSize query int false "页条数"
|
||||||
|
// @Param pageIndex query int false "页码"
|
||||||
|
// @Success 200 {object} response.Response{data=response.Page{list=[]models.LineStrategyTemplate}} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-strategy-template [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineStrategyTemplate) GetPage(c *gin.Context) {
|
||||||
|
req := dto.LineStrategyTemplateGetPageReq{}
|
||||||
|
s := service.LineStrategyTemplate{}
|
||||||
|
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.LineStrategyTemplate, 0)
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
err = s.GetPage(&req, p, &list, &count)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取波段策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取波段策略
|
||||||
|
// @Summary 获取波段策略
|
||||||
|
// @Description 获取波段策略
|
||||||
|
// @Tags 波段策略
|
||||||
|
// @Param id path int false "id"
|
||||||
|
// @Success 200 {object} response.Response{data=models.LineStrategyTemplate} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-strategy-template/{id} [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineStrategyTemplate) Get(c *gin.Context) {
|
||||||
|
req := dto.LineStrategyTemplateGetReq{}
|
||||||
|
s := service.LineStrategyTemplate{}
|
||||||
|
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.LineStrategyTemplate
|
||||||
|
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
err = s.Get(&req, p, &object)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取波段策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(object, "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建波段策略
|
||||||
|
// @Summary 创建波段策略
|
||||||
|
// @Description 创建波段策略
|
||||||
|
// @Tags 波段策略
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.LineStrategyTemplateInsertReq true "data"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
|
||||||
|
// @Router /api/v1/line-strategy-template [post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineStrategyTemplate) Insert(c *gin.Context) {
|
||||||
|
req := dto.LineStrategyTemplateInsertReq{}
|
||||||
|
s := service.LineStrategyTemplate{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.Valid(); err != nil {
|
||||||
|
e.Error(500, err, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置创建人
|
||||||
|
req.SetCreateBy(user.GetUserId(c))
|
||||||
|
|
||||||
|
err = s.Insert(&req)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("创建波段策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(req.GetId(), "创建成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改波段策略
|
||||||
|
// @Summary 修改波段策略
|
||||||
|
// @Description 修改波段策略
|
||||||
|
// @Tags 波段策略
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param id path int true "id"
|
||||||
|
// @Param data body dto.LineStrategyTemplateUpdateReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
|
||||||
|
// @Router /api/v1/line-strategy-template/{id} [put]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineStrategyTemplate) Update(c *gin.Context) {
|
||||||
|
req := dto.LineStrategyTemplateUpdateReq{}
|
||||||
|
s := service.LineStrategyTemplate{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.Valid(); err != nil {
|
||||||
|
e.Error(500, err, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.SetUpdateBy(user.GetUserId(c))
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
|
||||||
|
err = s.Update(&req, p)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("修改波段策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(req.GetId(), "修改成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除波段策略
|
||||||
|
// @Summary 删除波段策略
|
||||||
|
// @Description 删除波段策略
|
||||||
|
// @Tags 波段策略
|
||||||
|
// @Param data body dto.LineStrategyTemplateDeleteReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
|
||||||
|
// @Router /api/v1/line-strategy-template [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineStrategyTemplate) Delete(c *gin.Context) {
|
||||||
|
s := service.LineStrategyTemplate{}
|
||||||
|
req := dto.LineStrategyTemplateDeleteReq{}
|
||||||
|
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("删除波段策略失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(req.GetId(), "删除成功")
|
||||||
|
}
|
||||||
193
app/admin/apis/line_symbol_price.go
Normal file
193
app/admin/apis/line_symbol_price.go
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
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 LineSymbolPrice struct {
|
||||||
|
api.Api
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取缓存价格交易对列表
|
||||||
|
// @Summary 获取缓存价格交易对列表
|
||||||
|
// @Description 获取缓存价格交易对列表
|
||||||
|
// @Tags 缓存价格交易对
|
||||||
|
// @Param symbol query string false "交易对"
|
||||||
|
// @Param status query int false "状态 1-启用 2-禁用"
|
||||||
|
// @Param pageSize query int false "页条数"
|
||||||
|
// @Param pageIndex query int false "页码"
|
||||||
|
// @Success 200 {object} response.Response{data=response.Page{list=[]models.LineSymbolPrice}} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-symbol-price [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineSymbolPrice) GetPage(c *gin.Context) {
|
||||||
|
req := dto.LineSymbolPriceGetPageReq{}
|
||||||
|
s := service.LineSymbolPrice{}
|
||||||
|
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.LineSymbolPrice, 0)
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
err = s.GetPage(&req, p, &list, &count)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取缓存价格交易对失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取缓存价格交易对
|
||||||
|
// @Summary 获取缓存价格交易对
|
||||||
|
// @Description 获取缓存价格交易对
|
||||||
|
// @Tags 缓存价格交易对
|
||||||
|
// @Param id path int false "id"
|
||||||
|
// @Success 200 {object} response.Response{data=models.LineSymbolPrice} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-symbol-price/{id} [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineSymbolPrice) Get(c *gin.Context) {
|
||||||
|
req := dto.LineSymbolPriceGetReq{}
|
||||||
|
s := service.LineSymbolPrice{}
|
||||||
|
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.LineSymbolPrice
|
||||||
|
|
||||||
|
p := actions.GetPermissionFromContext(c)
|
||||||
|
err = s.Get(&req, p, &object)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("获取缓存价格交易对失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK( object, "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建缓存价格交易对
|
||||||
|
// @Summary 创建缓存价格交易对
|
||||||
|
// @Description 创建缓存价格交易对
|
||||||
|
// @Tags 缓存价格交易对
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.LineSymbolPriceInsertReq true "data"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
|
||||||
|
// @Router /api/v1/line-symbol-price [post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineSymbolPrice) Insert(c *gin.Context) {
|
||||||
|
req := dto.LineSymbolPriceInsertReq{}
|
||||||
|
s := service.LineSymbolPrice{}
|
||||||
|
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))
|
||||||
|
|
||||||
|
err = s.Insert(&req)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("创建缓存价格交易对失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(req.GetId(), "创建成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改缓存价格交易对
|
||||||
|
// @Summary 修改缓存价格交易对
|
||||||
|
// @Description 修改缓存价格交易对
|
||||||
|
// @Tags 缓存价格交易对
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param id path int true "id"
|
||||||
|
// @Param data body dto.LineSymbolPriceUpdateReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
|
||||||
|
// @Router /api/v1/line-symbol-price/{id} [put]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineSymbolPrice) Update(c *gin.Context) {
|
||||||
|
req := dto.LineSymbolPriceUpdateReq{}
|
||||||
|
s := service.LineSymbolPrice{}
|
||||||
|
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.Update(&req, p)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("修改缓存价格交易对失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK( req.GetId(), "修改成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除缓存价格交易对
|
||||||
|
// @Summary 删除缓存价格交易对
|
||||||
|
// @Description 删除缓存价格交易对
|
||||||
|
// @Tags 缓存价格交易对
|
||||||
|
// @Param data body dto.LineSymbolPriceDeleteReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
|
||||||
|
// @Router /api/v1/line-symbol-price [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e LineSymbolPrice) Delete(c *gin.Context) {
|
||||||
|
s := service.LineSymbolPrice{}
|
||||||
|
req := dto.LineSymbolPriceDeleteReq{}
|
||||||
|
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("删除缓存价格交易对失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK( req.GetId(), "删除成功")
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go-admin/common/models"
|
"go-admin/common/models"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LineApiUser struct {
|
type LineApiUser struct {
|
||||||
@ -9,22 +10,21 @@ type LineApiUser struct {
|
|||||||
|
|
||||||
ExchangeType string `json:"exchangeType" gorm:"type:varchar(20);comment:交易所类型(字典 exchange_type)"`
|
ExchangeType string `json:"exchangeType" gorm:"type:varchar(20);comment:交易所类型(字典 exchange_type)"`
|
||||||
UserId int64 `json:"userId" gorm:"type:int unsigned;comment:用户id"`
|
UserId int64 `json:"userId" gorm:"type:int unsigned;comment:用户id"`
|
||||||
JysId int64 `json:"jysId" gorm:"type:int;comment:关联交易所账号id"`
|
|
||||||
ApiName string `json:"apiName" gorm:"type:varchar(255);comment:api用户名"`
|
ApiName string `json:"apiName" gorm:"type:varchar(255);comment:api用户名"`
|
||||||
ApiKey string `json:"apiKey" gorm:"type:varchar(255);comment:apiKey"`
|
ApiKey string `json:"apiKey" gorm:"type:varchar(255);comment:apiKey"`
|
||||||
ApiSecret string `json:"apiSecret" gorm:"type:varchar(255);comment:apiSecret"`
|
ApiSecret string `json:"apiSecret" gorm:"type:varchar(255);comment:apiSecret"`
|
||||||
IpAddress string `json:"ipAddress" gorm:"type:varchar(255);comment:代理地址"`
|
IpAddress string `json:"ipAddress" gorm:"type:varchar(255);comment:代理地址"`
|
||||||
UserPass string `json:"userPass" gorm:"type:varchar(255);comment:代码账号密码"`
|
UserPass string `json:"userPass" gorm:"type:varchar(255);comment:代码账号密码"`
|
||||||
AdminId int64 `json:"adminId" gorm:"type:int unsigned;comment:管理员id"`
|
// AdminId int64 `json:"adminId" gorm:"type:int unsigned;comment:管理员id"`
|
||||||
Affiliation int64 `json:"affiliation" gorm:"type:int;comment:归属:1=现货,2=合约,3=现货合约"`
|
Affiliation int64 `json:"affiliation" gorm:"type:int;comment:归属:1=现货,2=合约,3=现货合约"`
|
||||||
AdminShow int64 `json:"adminShow" gorm:"type:int;comment:是否超管可见:1=是,0=否"`
|
AdminShow int64 `json:"adminShow" gorm:"type:int;comment:是否超管可见:1=是,0=否"`
|
||||||
Site string `json:"site" gorm:"type:enum('1','2','3');comment:允许下单的方向:1=多;2=空;3=多空"`
|
Site string `json:"site" gorm:"type:enum('1','2','3');comment:允许下单的方向:1=多;2=空;3=多空"`
|
||||||
Subordinate string `json:"subordinate" gorm:"type:enum('0','1','2');comment:从属关系:0=未绑定关系;1=主账号;2=副帐号"`
|
Subordinate string `json:"subordinate" gorm:"type:enum('0','1','2');comment:从属关系:0=未绑定关系;1=主账号;2=副帐号"`
|
||||||
GroupId int64 `json:"groupId" gorm:"type:int unsigned;comment:所属组id"`
|
GroupId int64 `json:"groupId" gorm:"type:int unsigned;comment:所属组id"`
|
||||||
OpenStatus int64 `json:"openStatus" gorm:"type:int unsigned;comment:开启状态 0=关闭 1=开启"`
|
OpenStatus int64 `json:"openStatus" gorm:"type:int unsigned;comment:开启状态 0=关闭 1=开启"`
|
||||||
|
|
||||||
SpotLastTime string `json:"spotLastTime" gorm:"-"` //现货websocket最后通信时间
|
SpotLastTime *time.Time `json:"spotLastTime" gorm:"-"` //现货websocket最后通信时间
|
||||||
FuturesLastTime string `json:"futuresLastTime" gorm:"-"` //合约websocket最后通信时间
|
FuturesLastTime *time.Time `json:"futuresLastTime" gorm:"-"` //合约websocket最后通信时间
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
}
|
}
|
||||||
|
|||||||
27
app/admin/models/line_order_reduce_strategy.go
Normal file
27
app/admin/models/line_order_reduce_strategy.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "go-admin/common/models"
|
||||||
|
|
||||||
|
type LineOrderReduceStrategy struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
OrderId int `json:"orderId" gorm:"type:bigint;not null;comment:订单ID"`
|
||||||
|
ReduceStrategyId int `json:"reduceStrategyId" gorm:"type:bigint;not null;comment:减仓策略ID"`
|
||||||
|
ItemContent string `json:"itemContent" gorm:"type:text;not null;comment:策略明细json"`
|
||||||
|
Actived int `json:"actived" gorm:"type:tinyint;comment:"是否已减仓 1=已减仓 2=未减仓""`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (LineOrderReduceStrategy) TableName() string {
|
||||||
|
return "line_order_reduce_strategy"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineOrderReduceStrategy) Generate() models.ActiveRecord {
|
||||||
|
o := *e
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineOrderReduceStrategy) GetId() interface{} {
|
||||||
|
return e.Id
|
||||||
|
}
|
||||||
@ -9,38 +9,41 @@ import (
|
|||||||
|
|
||||||
type LinePreOrder struct {
|
type LinePreOrder struct {
|
||||||
models.Model
|
models.Model
|
||||||
ExchangeType string `json:"exchangeType" gorm:"type:varchar(20);comment:交易所类型 (字典 exchange_type)"`
|
ExchangeType string `json:"exchangeType" gorm:"type:varchar(20);comment:交易所类型 (字典 exchange_type)"`
|
||||||
Pid int `json:"pid" gorm:"type:int unsigned;omitempty;comment:pid"`
|
StrategyTemplateType int `json:"strategyTemplateType" gorm:"type:tinyint;comment:策略类型 0-无 1-波段涨跌幅"`
|
||||||
MainId int `json:"mainId" gorm:"type:int;comment:主单id"`
|
Pid int `json:"pid" gorm:"type:int unsigned;omitempty;comment:pid"`
|
||||||
ApiId int `json:"apiId" gorm:"type:varchar(255);omitempty;comment:api用户"`
|
MainId int `json:"mainId" gorm:"type:int;comment:主单id"`
|
||||||
GroupId string `json:"groupId" gorm:"type:int unsigned;omitempty;comment:交易对组id"`
|
ApiId int `json:"apiId" gorm:"type:varchar(255);omitempty;comment:api用户"`
|
||||||
Symbol string `json:"symbol" gorm:"type:varchar(255);omitempty;comment:交易对"`
|
GroupId string `json:"groupId" gorm:"type:int unsigned;omitempty;comment:交易对组id"`
|
||||||
QuoteSymbol string `json:"quoteSymbol" gorm:"type:varchar(255);omitempty;comment:计较货币"`
|
Symbol string `json:"symbol" gorm:"type:varchar(255);omitempty;comment:交易对"`
|
||||||
SignPrice string `json:"signPrice" gorm:"type:decimal(18,8);omitempty;comment:对标价"`
|
QuoteSymbol string `json:"quoteSymbol" gorm:"type:varchar(255);omitempty;comment:计较货币"`
|
||||||
SignPriceU decimal.Decimal `json:"signPriceU" gorm:"type:decimal(18,8);omitempty;comment:交易对对标U的行情价"`
|
SignPrice string `json:"signPrice" gorm:"type:decimal(18,8);omitempty;comment:对标价"`
|
||||||
SignPriceType string `json:"signPriceType" gorm:"type:enum('new','tall','low','mixture','entrust','add');omitempty;comment:对标价类型: new=最新价格;tall=24小时最高;low=24小时最低;mixture=标记价;entrust=委托实价;add=补仓"`
|
SignPriceU decimal.Decimal `json:"signPriceU" gorm:"type:decimal(18,8);omitempty;comment:交易对对标U的行情价"`
|
||||||
Rate string `json:"rate" gorm:"type:decimal(18,2);omitempty;comment:下单百分比"`
|
SignPriceType string `json:"signPriceType" gorm:"type:enum('new','tall','low','mixture','entrust','add');omitempty;comment:对标价类型: new=最新价格;tall=24小时最高;low=24小时最低;mixture=标记价;entrust=委托实价;add=补仓"`
|
||||||
Price string `json:"price" gorm:"type:decimal(18,8);omitempty;comment:触发价格"`
|
Rate string `json:"rate" gorm:"type:decimal(18,2);omitempty;comment:下单百分比"`
|
||||||
Num string `json:"num" gorm:"type:decimal(18,8);omitempty;comment:购买数量"`
|
Price string `json:"price" gorm:"type:decimal(18,8);omitempty;comment:触发价格"`
|
||||||
BuyPrice string `json:"buyPrice" gorm:"type:decimal(18,8);omitempty;comment:购买金额"`
|
Num string `json:"num" gorm:"type:decimal(18,8);omitempty;comment:购买数量"`
|
||||||
SymbolType int `json:"symbolType" gorm:"type:int;comment:交易对类型:1=现货;2=合约"`
|
BuyPrice string `json:"buyPrice" gorm:"type:decimal(18,8);omitempty;comment:购买金额"`
|
||||||
OrderCategory int `json:"orderCategory" gorm:"type:int;comment:订单类型: 1=主单 2=对冲单 3-加仓单"`
|
SymbolType int `json:"symbolType" gorm:"type:int;comment:交易对类型:1=现货;2=合约"`
|
||||||
Site string `json:"site" gorm:"type:enum('BUY','SELL');omitempty;comment:购买方向:BUY=买;SELL=卖"`
|
OrderCategory int `json:"orderCategory" gorm:"type:int;comment:订单类型: 1=主单 2=对冲单 3-加仓单"`
|
||||||
OrderSn string `json:"orderSn" gorm:"type:varchar(255);omitempty;comment:订单号"`
|
Site string `json:"site" gorm:"type:enum('BUY','SELL');omitempty;comment:购买方向:BUY=买;SELL=卖"`
|
||||||
OrderType int `json:"orderType" gorm:"type:int;omitempty;comment:订单类型:0=主单 1=止盈 2=止损 3=平仓 4=减仓"`
|
OrderSn string `json:"orderSn" gorm:"type:varchar(255);omitempty;comment:订单号"`
|
||||||
Desc string `json:"desc" gorm:"type:text;omitempty;comment:订单描述"`
|
OrderType int `json:"orderType" gorm:"type:int;omitempty;comment:订单类型:0=主单 1=止盈 2=止损 3=平仓 4=减仓"`
|
||||||
Status int `json:"status" gorm:"type:int;omitempty;comment:是否被触发:0=待触发;1=已触发;2=下单失败;4=已取消;5=委托中;6=已成交;9=已平仓"`
|
Desc string `json:"desc" gorm:"type:text;omitempty;comment:订单描述"`
|
||||||
CoverType int `json:"coverType" gorm:"type:int unsigned;omitempty;comment:对冲类型 1= 现货对合约 2=合约对合约 3 合约对现货"`
|
Status int `json:"status" gorm:"type:int;omitempty;comment:是否被触发:0=待触发;1=已触发;2=下单失败;4=已取消;5=委托中;6=已成交;9=已平仓"`
|
||||||
ExpireTime time.Time `json:"expireTime" gorm:"comment:过期时间"`
|
CoverType int `json:"coverType" gorm:"type:int unsigned;omitempty;comment:对冲类型 1= 现货对合约 2=合约对合约 3 合约对现货"`
|
||||||
MainOrderType string `json:"mainOrderType" gorm:"type:enum;comment:第一笔(主单类型) 限价(LIMIT)市价(MARKET)"`
|
ExpireTime time.Time `json:"expireTime" gorm:"comment:过期时间"`
|
||||||
LossAmount decimal.Decimal `json:"lossAmount" gorm:"type:decimal(18,8);comment:亏损金额(U)"`
|
MainOrderType string `json:"mainOrderType" gorm:"type:enum;comment:第一笔(主单类型) 限价(LIMIT)市价(MARKET)"`
|
||||||
TriggerTime *time.Time `json:"triggerTime" gorm:"type:datetime;comment:触发时间"`
|
LossAmount decimal.Decimal `json:"lossAmount" gorm:"type:decimal(18,8);comment:亏损金额(U)"`
|
||||||
Child []LinePreOrder `json:"child" gorm:"-"`
|
TriggerTime *time.Time `json:"triggerTime" gorm:"type:datetime;comment:触发时间"`
|
||||||
ApiName string `json:"api_name" gorm:"->"`
|
Child []LinePreOrder `json:"child" gorm:"-"`
|
||||||
ChildNum int64 `json:"child_num" gorm:"->"`
|
ApiName string `json:"api_name" gorm:"->"`
|
||||||
AddPositionStatus int `json:"add_position_status" gorm:"->"`
|
ChildNum int64 `json:"child_num" gorm:"->"`
|
||||||
ReduceStatus int `json:"reduce_status" gorm:"->"`
|
AddPositionStatus int `json:"add_position_status" gorm:"->"`
|
||||||
Childs []LinePreOrder `json:"childs" gorm:"foreignKey:pid;references:id"`
|
ReduceStatus int `json:"reduce_status" gorm:"->"`
|
||||||
|
Childs []LinePreOrder `json:"childs" gorm:"foreignKey:pid;references:id"`
|
||||||
|
ReduceOrderId int `json:"reduceOrderId" gorm:"type:bigint;comment:主减仓单id"`
|
||||||
|
// OrderReduceStrategy LineOrderReduceStrategy `json:"-" gorm:"foreignKey:order_id;references:id"`
|
||||||
// LinePreOrder 线上预埋单\
|
// LinePreOrder 线上预埋单\
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
|
|||||||
28
app/admin/models/line_reduce_strategy.go
Normal file
28
app/admin/models/line_reduce_strategy.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineReduceStrategy struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
Name string `json:"name" gorm:"type:varchar(50);comment:减仓策略名称"`
|
||||||
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"`
|
||||||
|
Items []LineReduceStrategyItem `json:"items" gorm:"foreignKey:ReduceStrategyId;references:Id"`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (LineReduceStrategy) TableName() string {
|
||||||
|
return "line_reduce_strategy"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineReduceStrategy) Generate() models.ActiveRecord {
|
||||||
|
o := *e
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineReduceStrategy) GetId() interface{} {
|
||||||
|
return e.Id
|
||||||
|
}
|
||||||
32
app/admin/models/line_reduce_strategy_item.go
Normal file
32
app/admin/models/line_reduce_strategy_item.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/models"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineReduceStrategyItem struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
ReduceStrategyId int `json:"reduceStrategyId" gorm:"type:bigint;comment:减仓策略id"`
|
||||||
|
LossPercent decimal.Decimal `json:"lossPercent" gorm:"type:decimal(10,2);comment:亏损百分比"`
|
||||||
|
QuantityPercent decimal.Decimal `json:"quantityPercent" gorm:"type:decimal(10,2);comment:减仓数量百分比"`
|
||||||
|
OrderType string `json:"orderType" gorm:"type:varchar(20);comment:订单类型 LIMIT-限价 MARKET-市价"`
|
||||||
|
ReduceStrategy LineReduceStrategy `json:"reduceStrategy" gorm:"foreignKey:ReduceStrategyId;"`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (LineReduceStrategyItem) TableName() string {
|
||||||
|
return "line_reduce_strategy_item"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineReduceStrategyItem) Generate() models.ActiveRecord {
|
||||||
|
o := *e
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineReduceStrategyItem) GetId() interface{} {
|
||||||
|
return e.Id
|
||||||
|
}
|
||||||
33
app/admin/models/line_strategy_template.go
Normal file
33
app/admin/models/line_strategy_template.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/models"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineStrategyTemplate struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
Name string `json:"name" gorm:"type:varchar(50);comment:策略名称"`
|
||||||
|
Direction int `json:"direction" gorm:"type:tinyint;comment:涨跌方向 1-涨 2-跌"`
|
||||||
|
Percentag decimal.Decimal `json:"percentag" gorm:"type:decimal(10,2);comment:涨跌点数"`
|
||||||
|
CompareType int `json:"compareType" gorm:"type:tinyint;comment:比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "`
|
||||||
|
TimeSlotStart int `json:"timeSlotStart" gorm:"type:int;comment:时间段开始(分)"`
|
||||||
|
// TimeSlotEnd int `json:"timeSlotEnd" gorm:"type:int;comment:时间断截至(分)"`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (LineStrategyTemplate) TableName() string {
|
||||||
|
return "line_strategy_template"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineStrategyTemplate) Generate() models.ActiveRecord {
|
||||||
|
o := *e
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineStrategyTemplate) GetId() interface{} {
|
||||||
|
return e.Id
|
||||||
|
}
|
||||||
29
app/admin/models/line_symbol_price.go
Normal file
29
app/admin/models/line_symbol_price.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
|
||||||
|
"go-admin/common/models"
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineSymbolPrice struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
Symbol string `json:"symbol" gorm:"type:varchar(15);comment:交易对"`
|
||||||
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (LineSymbolPrice) TableName() string {
|
||||||
|
return "line_symbol_price"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineSymbolPrice) Generate() models.ActiveRecord {
|
||||||
|
o := *e
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineSymbolPrice) GetId() interface{} {
|
||||||
|
return e.Id
|
||||||
|
}
|
||||||
@ -9,13 +9,14 @@ import (
|
|||||||
type LineSystemSetting struct {
|
type LineSystemSetting struct {
|
||||||
models.Model
|
models.Model
|
||||||
|
|
||||||
Time int64 `json:"time" gorm:"type:int;comment:导入:挂单时长达到时间后失效"`
|
Time int64 `json:"time" gorm:"type:int;comment:导入:挂单时长达到时间后失效"`
|
||||||
BatchTime int64 `json:"batchTime" gorm:"type:int;comment:批量:挂单时长达到时间后失效"`
|
BatchTime int64 `json:"batchTime" gorm:"type:int;comment:批量:挂单时长达到时间后失效"`
|
||||||
ProfitRate string `json:"profitRate" gorm:"type:decimal(10,2);comment:平仓盈利比例"`
|
ProfitRate string `json:"profitRate" gorm:"type:decimal(10,2);comment:平仓盈利比例"`
|
||||||
CoverOrderTypeBRate string `json:"coverOrderTypeBRate" gorm:"type:decimal(10,2);comment:b账户限价补单的买入百分比"`
|
CoverOrderTypeBRate string `json:"coverOrderTypeBRate" gorm:"type:decimal(10,2);comment:b账户限价补单的买入百分比"`
|
||||||
StopLossPremium decimal.Decimal `json:"stopLossPremium" gorm:"type:decimal(10,2);comment:限价止损溢价百分比"`
|
StopLossPremium decimal.Decimal `json:"stopLossPremium" gorm:"type:decimal(10,2);comment:限价止损溢价百分比"`
|
||||||
AddPositionPremium decimal.Decimal `json:"addPositionPremium" gorm:"type:decimal(10,2);comment:限价加仓溢价百分比`
|
AddPositionPremium decimal.Decimal `json:"addPositionPremium" gorm:"type:decimal(10,2);comment:限价加仓溢价百分比`
|
||||||
ReducePremium decimal.Decimal `json:"reducePremium" gorm:"type:decimal(10,2);comment:限价减仓溢价百分比"`
|
ReducePremium decimal.Decimal `json:"reducePremium" gorm:"type:decimal(10,2);comment:限价减仓溢价百分比"`
|
||||||
|
ReduceEarlyTriggerPercent decimal.Decimal `json:"reduceEarlyTriggerPercent" gorm:"type:decimal(10,2);comment:减仓提前触发百分比"`
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
}
|
}
|
||||||
|
|||||||
27
app/admin/router/line_reduce_strategy.go
Normal file
27
app/admin/router/line_reduce_strategy.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
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/middleware"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
routerCheckRole = append(routerCheckRole, registerLineReduceStrategyRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerLineReduceStrategyRouter
|
||||||
|
func registerLineReduceStrategyRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||||
|
api := apis.LineReduceStrategy{}
|
||||||
|
r := v1.Group("/line-reduce-strategy").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)
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/admin/router/line_reduce_strategy_item.go
Normal file
27
app/admin/router/line_reduce_strategy_item.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
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/middleware"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
routerCheckRole = append(routerCheckRole, registerLineReduceStrategyItemRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerLineReduceStrategyItemRouter
|
||||||
|
func registerLineReduceStrategyItemRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||||
|
api := apis.LineReduceStrategyItem{}
|
||||||
|
r := v1.Group("/line-reduce-strategy-item").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)
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/admin/router/line_strategy_template.go
Normal file
27
app/admin/router/line_strategy_template.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
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/middleware"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
routerCheckRole = append(routerCheckRole, registerLineStrategyTemplateRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerLineStrategyTemplateRouter
|
||||||
|
func registerLineStrategyTemplateRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||||
|
api := apis.LineStrategyTemplate{}
|
||||||
|
r := v1.Group("/line-strategy-template").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)
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/admin/router/line_symbol_price.go
Normal file
27
app/admin/router/line_symbol_price.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
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/middleware"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
routerCheckRole = append(routerCheckRole, registerLineSymbolPriceRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerLineSymbolPriceRouter
|
||||||
|
func registerLineSymbolPriceRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||||
|
api := apis.LineSymbolPrice{}
|
||||||
|
r := v1.Group("/line-symbol-price").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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,9 +14,9 @@ type LineApiUserGetPageReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LineApiUserOrder struct {
|
type LineApiUserOrder struct {
|
||||||
Id string `form:"idOrder" search:"type:order;column:id;table:line_api_user"`
|
Id string `form:"idOrder" search:"type:order;column:id;table:line_api_user"`
|
||||||
UserId string `form:"userIdOrder" search:"type:order;column:user_id;table:line_api_user"`
|
UserId string `form:"userIdOrder" search:"type:order;column:user_id;table:line_api_user"`
|
||||||
JysId string `form:"jysIdOrder" search:"type:order;column:jys_id;table:line_api_user"`
|
// JysId string `form:"jysIdOrder" search:"type:order;column:jys_id;table:line_api_user"`
|
||||||
ApiName string `form:"apiNameOrder" search:"type:order;column:api_name;table:line_api_user"`
|
ApiName string `form:"apiNameOrder" search:"type:order;column:api_name;table:line_api_user"`
|
||||||
ApiKey string `form:"apiKeyOrder" search:"type:order;column:api_key;table:line_api_user"`
|
ApiKey string `form:"apiKeyOrder" search:"type:order;column:api_key;table:line_api_user"`
|
||||||
ApiSecret string `form:"apiSecretOrder" search:"type:order;column:api_secret;table:line_api_user"`
|
ApiSecret string `form:"apiSecretOrder" search:"type:order;column:api_secret;table:line_api_user"`
|
||||||
@ -44,19 +44,19 @@ type LineApiUserInsertReq struct {
|
|||||||
Id int `json:"-" comment:"id"` // id
|
Id int `json:"-" comment:"id"` // id
|
||||||
ExchangeType string `json:"exchangeType" comment:"交易所code"`
|
ExchangeType string `json:"exchangeType" comment:"交易所code"`
|
||||||
UserId int64 `json:"userId" comment:"用户id"`
|
UserId int64 `json:"userId" comment:"用户id"`
|
||||||
JysId int64 `json:"jysId" comment:"关联交易所账号id"`
|
// JysId int64 `json:"jysId" comment:"关联交易所账号id"`
|
||||||
ApiName string `json:"apiName" comment:"api用户名"`
|
ApiName string `json:"apiName" comment:"api用户名"`
|
||||||
ApiKey string `json:"apiKey" comment:"apiKey"`
|
ApiKey string `json:"apiKey" comment:"apiKey"`
|
||||||
ApiSecret string `json:"apiSecret" comment:"apiSecret"`
|
ApiSecret string `json:"apiSecret" comment:"apiSecret"`
|
||||||
IpAddress string `json:"ipAddress" comment:"代理地址"`
|
IpAddress string `json:"ipAddress" comment:"代理地址"`
|
||||||
UserPass string `json:"userPass" comment:"代码账号密码"`
|
UserPass string `json:"userPass" comment:"代码账号密码"`
|
||||||
AdminId int64 `json:"adminId" comment:"管理员id"`
|
AdminId int64 `json:"adminId" comment:"管理员id"`
|
||||||
Affiliation int64 `json:"affiliation" comment:"归属:1=现货,2=合约,3=现货合约"`
|
Affiliation int64 `json:"affiliation" comment:"归属:1=现货,2=合约,3=现货合约"`
|
||||||
AdminShow int64 `json:"adminShow" comment:"是否超管可见:1=是,0=否"`
|
AdminShow int64 `json:"adminShow" comment:"是否超管可见:1=是,0=否"`
|
||||||
Site string `json:"site" comment:"允许下单的方向:1=多;2=空;3=多空"`
|
Site string `json:"site" comment:"允许下单的方向:1=多;2=空;3=多空"`
|
||||||
Subordinate string `json:"subordinate" comment:"从属关系:0=未绑定关系;1=主账号;2=副帐号"`
|
Subordinate string `json:"subordinate" comment:"从属关系:0=未绑定关系;1=主账号;2=副帐号"`
|
||||||
GroupId int64 `json:"groupId" comment:"所属组id"`
|
GroupId int64 `json:"groupId" comment:"所属组id"`
|
||||||
OpenStatus int64 `json:"openStatus" comment:"开启状态 0=关闭 1=开启"`
|
OpenStatus int64 `json:"openStatus" comment:"开启状态 0=关闭 1=开启"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,13 +66,13 @@ func (s *LineApiUserInsertReq) Generate(model *models.LineApiUser) {
|
|||||||
}
|
}
|
||||||
model.ExchangeType = s.ExchangeType
|
model.ExchangeType = s.ExchangeType
|
||||||
model.UserId = s.UserId
|
model.UserId = s.UserId
|
||||||
model.JysId = s.JysId
|
// model.JysId = s.JysId
|
||||||
model.ApiName = s.ApiName
|
model.ApiName = s.ApiName
|
||||||
model.ApiKey = s.ApiKey
|
model.ApiKey = s.ApiKey
|
||||||
model.ApiSecret = s.ApiSecret
|
model.ApiSecret = s.ApiSecret
|
||||||
model.IpAddress = s.IpAddress
|
model.IpAddress = s.IpAddress
|
||||||
model.UserPass = s.UserPass
|
model.UserPass = s.UserPass
|
||||||
model.AdminId = s.AdminId
|
// model.AdminId = s.AdminId
|
||||||
model.Affiliation = s.Affiliation
|
model.Affiliation = s.Affiliation
|
||||||
model.AdminShow = s.AdminShow
|
model.AdminShow = s.AdminShow
|
||||||
model.Site = s.Site
|
model.Site = s.Site
|
||||||
@ -90,19 +90,19 @@ type LineApiUserUpdateReq struct {
|
|||||||
Id int `uri:"id" comment:"id"` // id
|
Id int `uri:"id" comment:"id"` // id
|
||||||
ExchangeType string `json:"exchangeType" comment:"交易所code"`
|
ExchangeType string `json:"exchangeType" comment:"交易所code"`
|
||||||
UserId int64 `json:"userId" comment:"用户id"`
|
UserId int64 `json:"userId" comment:"用户id"`
|
||||||
JysId int64 `json:"jysId" comment:"关联交易所账号id"`
|
// JysId int64 `json:"jysId" comment:"关联交易所账号id"`
|
||||||
ApiName string `json:"apiName" comment:"api用户名"`
|
ApiName string `json:"apiName" comment:"api用户名"`
|
||||||
ApiKey string `json:"apiKey" comment:"apiKey"`
|
ApiKey string `json:"apiKey" comment:"apiKey"`
|
||||||
ApiSecret string `json:"apiSecret" comment:"apiSecret"`
|
ApiSecret string `json:"apiSecret" comment:"apiSecret"`
|
||||||
IpAddress string `json:"ipAddress" comment:"代理地址"`
|
IpAddress string `json:"ipAddress" comment:"代理地址"`
|
||||||
UserPass string `json:"userPass" comment:"代码账号密码"`
|
UserPass string `json:"userPass" comment:"代码账号密码"`
|
||||||
AdminId int64 `json:"adminId" comment:"管理员id"`
|
// AdminId int64 `json:"adminId" comment:"管理员id"`
|
||||||
Affiliation int64 `json:"affiliation" comment:"归属:1=现货,2=合约,3=现货合约"`
|
Affiliation int64 `json:"affiliation" comment:"归属:1=现货,2=合约,3=现货合约"`
|
||||||
AdminShow int64 `json:"adminShow" comment:"是否超管可见:1=是,0=否"`
|
AdminShow int64 `json:"adminShow" comment:"是否超管可见:1=是,0=否"`
|
||||||
Site string `json:"site" comment:"允许下单的方向:1=多;2=空;3=多空"`
|
Site string `json:"site" comment:"允许下单的方向:1=多;2=空;3=多空"`
|
||||||
Subordinate string `json:"subordinate" comment:"从属关系:0=未绑定关系;1=主账号;2=副帐号"`
|
Subordinate string `json:"subordinate" comment:"从属关系:0=未绑定关系;1=主账号;2=副帐号"`
|
||||||
GroupId int64 `json:"groupId" comment:"所属组id"`
|
GroupId int64 `json:"groupId" comment:"所属组id"`
|
||||||
OpenStatus int64 `json:"openStatus" comment:"开启状态 0=关闭 1=开启"`
|
OpenStatus int64 `json:"openStatus" comment:"开启状态 0=关闭 1=开启"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,13 +112,13 @@ func (s *LineApiUserUpdateReq) Generate(model *models.LineApiUser) {
|
|||||||
}
|
}
|
||||||
model.ExchangeType = s.ExchangeType
|
model.ExchangeType = s.ExchangeType
|
||||||
model.UserId = s.UserId
|
model.UserId = s.UserId
|
||||||
model.JysId = s.JysId
|
// model.JysId = s.JysId
|
||||||
model.ApiName = s.ApiName
|
model.ApiName = s.ApiName
|
||||||
model.ApiKey = s.ApiKey
|
model.ApiKey = s.ApiKey
|
||||||
model.ApiSecret = s.ApiSecret
|
model.ApiSecret = s.ApiSecret
|
||||||
model.IpAddress = s.IpAddress
|
model.IpAddress = s.IpAddress
|
||||||
model.UserPass = s.UserPass
|
model.UserPass = s.UserPass
|
||||||
model.AdminId = s.AdminId
|
// model.AdminId = s.AdminId
|
||||||
model.Affiliation = s.Affiliation
|
model.Affiliation = s.Affiliation
|
||||||
model.AdminShow = s.AdminShow
|
model.AdminShow = s.AdminShow
|
||||||
model.Site = s.Site
|
model.Site = s.Site
|
||||||
|
|||||||
21
app/admin/service/dto/line_order_reduce_strategy.go
Normal file
21
app/admin/service/dto/line_order_reduce_strategy.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import "github.com/shopspring/decimal"
|
||||||
|
|
||||||
|
type LineOrderReduceStrategyResp struct {
|
||||||
|
MainId int `json:"mainId" comment:"主单id"`
|
||||||
|
OrderId int `json:"orderId" comment:"减仓单id"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Side string `json:"side" comment:"BUY SELL"`
|
||||||
|
Items []LineOrderReduceStrategyRespItem `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 减仓节点
|
||||||
|
type LineOrderReduceStrategyRespItem struct {
|
||||||
|
Price decimal.Decimal `json:"p" comment:"下单价"`
|
||||||
|
Num decimal.Decimal `json:"n" comment:"下单数量"`
|
||||||
|
TriggerPrice decimal.Decimal `json:"t" comment:"触发价"`
|
||||||
|
LossPercent decimal.Decimal `json:"l" comment:"亏损百分比"`
|
||||||
|
OrderType string `json:"o" comment:"订单类型 LIMIT-限价 MARKET-市价"`
|
||||||
|
Actived bool `json:"a" comment:"是否触发 "`
|
||||||
|
}
|
||||||
@ -186,6 +186,9 @@ func (s *LinePreOrderDeleteReq) GetId() interface{} {
|
|||||||
|
|
||||||
type LineAddPreOrderReq struct {
|
type LineAddPreOrderReq struct {
|
||||||
ExchangeType string `json:"exchange_type" vd:"len($)>0"` //交易所类型
|
ExchangeType string `json:"exchange_type" vd:"len($)>0"` //交易所类型
|
||||||
|
StrategyTemplateType int `json:"strategy_template_type"` //策略类型 0-无 1-波段涨跌幅
|
||||||
|
StrategyTemplateId int `json:"strategy_template_id"` //策略id
|
||||||
|
ReduceStrategyId int `json:"reduce_strategy_id"` //减仓策略id
|
||||||
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" ` //下单用户
|
||||||
@ -194,11 +197,12 @@ type LineAddPreOrderReq struct {
|
|||||||
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"` //价格模式
|
||||||
Price string `json:"price" vd:"$>0"` //下单价百分比
|
Price string `json:"price"` //下单价百分比
|
||||||
Profit string `json:"profit" vd:"$>0"` //止盈价
|
Profit string `json:"profit" vd:"$>0"` //止盈价
|
||||||
ProfitNumRatio decimal.Decimal `json:"profit_num_ratio"` //止盈数量百分比
|
ProfitNumRatio decimal.Decimal `json:"profit_num_ratio"` //止盈数量百分比
|
||||||
ProfitTpTpPriceRatio decimal.Decimal `json:"profit_tp_tp_price_ratio"` //止盈后止盈价百分比
|
ProfitTpTpPriceRatio decimal.Decimal `json:"profit_tp_tp_price_ratio"` //止盈后止盈价百分比
|
||||||
ProfitTpSlPriceRatio decimal.Decimal `json:"profit_tp_sl_price_ratio"` //止盈后止损价百分比
|
ProfitTpSlPriceRatio decimal.Decimal `json:"profit_tp_sl_price_ratio"` //止盈后止损价百分比
|
||||||
|
StopLoss decimal.Decimal `json:"stop_loss"` //止损价
|
||||||
PriceType string `json:"price_type"` //价格类型
|
PriceType string `json:"price_type"` //价格类型
|
||||||
SaveTemplate string `json:"save_template"` //是否保存模板
|
SaveTemplate string `json:"save_template"` //是否保存模板
|
||||||
TemplateName string `json:"template_name"` //模板名字
|
TemplateName string `json:"template_name"` //模板名字
|
||||||
@ -283,11 +287,15 @@ func (req LineAddPreOrderReq) Valid() error {
|
|||||||
return errors.New("主单减仓价格百分比不能为空")
|
return errors.New("主单减仓价格百分比不能为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.StrategyTemplateType == 1 && req.StrategyTemplateId == 0 {
|
||||||
|
return errors.New("请选择策略")
|
||||||
|
}
|
||||||
|
|
||||||
if req.ReduceNumRatio.IsZero() {
|
if req.ReduceNumRatio.IsZero() {
|
||||||
return errors.New("主单减仓数量百分比不能为空")
|
return errors.New("主单减仓数量百分比不能为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.ReducePriceRatio.IsZero() || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0 {
|
if req.PricePattern != "mixture" && (req.ReducePriceRatio.IsZero() || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0) {
|
||||||
return errors.New("主单减仓价格百分比错误")
|
return errors.New("主单减仓价格百分比错误")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +326,9 @@ func (req LineAddPreOrderReq) Valid() error {
|
|||||||
return fmt.Errorf("%s单下跌价格不能为空", name)
|
return fmt.Errorf("%s单下跌价格不能为空", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.TakeProfitRatio.IsZero() || v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 {
|
if (v.AddType == 2 && v.AddPositionVal.Cmp(decimal.NewFromInt(100)) < 0 && v.TakeProfitRatio.IsZero()) ||
|
||||||
|
(v.AddType == 1 && v.TakeProfitRatio.IsZero()) ||
|
||||||
|
v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 {
|
||||||
return errors.New("止盈价格不正确")
|
return errors.New("止盈价格不正确")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,6 +377,8 @@ type LineTreeOrder struct {
|
|||||||
// LineBatchAddPreOrderReq 批量添加订单请求参数
|
// LineBatchAddPreOrderReq 批量添加订单请求参数
|
||||||
type LineBatchAddPreOrderReq struct {
|
type LineBatchAddPreOrderReq struct {
|
||||||
ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type
|
ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type
|
||||||
|
StrategyTemplateType int `json:"strategy_template_type"` //策略类型 0-无 1-波段涨跌幅
|
||||||
|
StrategyTemplateId int `json:"strategy_template_id"` //策略id
|
||||||
SymbolType int `json:"symbol_type"` //主单交易对类型 0-现货 1-合约
|
SymbolType int `json:"symbol_type"` //主单交易对类型 0-现货 1-合约
|
||||||
OrderType int `json:"order_type"` //订单类型
|
OrderType int `json:"order_type"` //订单类型
|
||||||
SymbolGroupId string `json:"symbol_group_id"` //交易对组id
|
SymbolGroupId string `json:"symbol_group_id"` //交易对组id
|
||||||
@ -404,6 +416,10 @@ func (req LineBatchAddPreOrderReq) CheckParams() error {
|
|||||||
return errors.New("请选择交易所")
|
return errors.New("请选择交易所")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.StrategyTemplateType == 1 && req.StrategyTemplateId == 0 {
|
||||||
|
return errors.New("请选择策略")
|
||||||
|
}
|
||||||
|
|
||||||
if req.ApiUserId == "" {
|
if req.ApiUserId == "" {
|
||||||
return errors.New("选择下单用户")
|
return errors.New("选择下单用户")
|
||||||
}
|
}
|
||||||
@ -431,7 +447,7 @@ func (req LineBatchAddPreOrderReq) CheckParams() error {
|
|||||||
return errors.New("主单减仓数量百分比不能为空")
|
return errors.New("主单减仓数量百分比不能为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0 {
|
if req.PricePattern != "mixture" && (req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0) {
|
||||||
return errors.New("主单减仓价格百分比错误")
|
return errors.New("主单减仓价格百分比错误")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +478,9 @@ func (req LineBatchAddPreOrderReq) CheckParams() error {
|
|||||||
return fmt.Errorf("%s单下跌价格不能为空", name)
|
return fmt.Errorf("%s单下跌价格不能为空", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.TakeProfitRatio.IsZero() || v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 {
|
if (v.AddType == 2 && v.AddPositionVal.Cmp(decimal.NewFromInt(100)) < 0 && v.TakeProfitRatio.IsZero()) ||
|
||||||
|
(v.AddType == 1 && v.TakeProfitRatio.IsZero()) ||
|
||||||
|
v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 {
|
||||||
return errors.New("止盈价格不正确")
|
return errors.New("止盈价格不正确")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,6 +575,17 @@ type PreOrderRedisList struct {
|
|||||||
QuoteSymbol string `json:"quote_symbol"`
|
QuoteSymbol string `json:"quote_symbol"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StrategyOrderRedisList struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Price string `json:"price"`
|
||||||
|
Site string `json:"site"`
|
||||||
|
ApiId int `json:"api_id"`
|
||||||
|
OrderSn string `json:"order_sn"`
|
||||||
|
QuoteSymbol string `json:"quote_symbol"`
|
||||||
|
LineStrategyTemplateRedis
|
||||||
|
}
|
||||||
|
|
||||||
type StopLossRedisList struct {
|
type StopLossRedisList struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
PId int `json:"pid"` //父级id
|
PId int `json:"pid"` //父级id
|
||||||
|
|||||||
159
app/admin/service/dto/line_reduce_strategy.go
Normal file
159
app/admin/service/dto/line_reduce_strategy.go
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/dto"
|
||||||
|
common "go-admin/common/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineReduceStrategyGetPageReq struct {
|
||||||
|
dto.Pagination `search:"-"`
|
||||||
|
Name string `form:"name" search:"type:contains;column:name;table:line_reduce_strategy" comment:"减仓策略名称"`
|
||||||
|
Status string `form:"status" search:"type:exact;column:status;table:line_reduce_strategy" comment:"状态 1-启用 2-禁用"`
|
||||||
|
LineReduceStrategyOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineReduceStrategyOrder struct {
|
||||||
|
Id string `form:"idOrder" search:"type:order;column:id;table:line_reduce_strategy"`
|
||||||
|
Name string `form:"nameOrder" search:"type:order;column:name;table:line_reduce_strategy"`
|
||||||
|
Status string `form:"statusOrder" search:"type:order;column:status;table:line_reduce_strategy"`
|
||||||
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:line_reduce_strategy"`
|
||||||
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:line_reduce_strategy"`
|
||||||
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:line_reduce_strategy"`
|
||||||
|
CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:line_reduce_strategy"`
|
||||||
|
UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:line_reduce_strategy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LineReduceStrategyGetPageReq) GetNeedSearch() interface{} {
|
||||||
|
return *m
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineReduceStrategyInsertReq struct {
|
||||||
|
Id int `json:"-" comment:"主键id"` // 主键id
|
||||||
|
Name string `json:"name" comment:"减仓策略名称"`
|
||||||
|
Status int `json:"status" comment:"状态 1-启用 2-禁用"`
|
||||||
|
Items []LineReduceStrategyItem `json:"items" comment:"减仓单节点"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数校验
|
||||||
|
func (s *LineReduceStrategyInsertReq) Valid() error {
|
||||||
|
if s.Name == "" {
|
||||||
|
return errors.New("减仓策略名称不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Status < 1 || s.Status > 2 {
|
||||||
|
return errors.New("状态值不合法")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.Items) == 0 {
|
||||||
|
return errors.New("减仓策略节点不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
for index, item := range s.Items {
|
||||||
|
if err := item.Valid(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if index > 0 && item.LossPercent.Cmp(s.Items[index-1].LossPercent) <= 0 {
|
||||||
|
return errors.New("亏损比例必须递增")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyInsertReq) Generate(model *models.LineReduceStrategy) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.Name = s.Name
|
||||||
|
model.Status = s.Status
|
||||||
|
|
||||||
|
for _, item := range s.Items {
|
||||||
|
strategyItem := models.LineReduceStrategyItem{}
|
||||||
|
strategyItem.OrderType = item.OrderType
|
||||||
|
strategyItem.LossPercent = item.LossPercent
|
||||||
|
strategyItem.QuantityPercent = item.QuantityPercent
|
||||||
|
|
||||||
|
model.Items = append(model.Items, strategyItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyInsertReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineReduceStrategyUpdateReq struct {
|
||||||
|
Id int `uri:"id" comment:"主键id"` // 主键id
|
||||||
|
Name string `json:"name" comment:"减仓策略名称"`
|
||||||
|
Status int `json:"status" comment:"状态 1-启用 2-禁用"`
|
||||||
|
Items []LineReduceStrategyItem `json:"items" comment:"减仓单节点"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyUpdateReq) Generate(model *models.LineReduceStrategy) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.Name = s.Name
|
||||||
|
model.Status = s.Status
|
||||||
|
|
||||||
|
for _, item := range s.Items {
|
||||||
|
strategyItem := models.LineReduceStrategyItem{}
|
||||||
|
strategyItem.OrderType = item.OrderType
|
||||||
|
strategyItem.LossPercent = item.LossPercent
|
||||||
|
strategyItem.QuantityPercent = item.QuantityPercent
|
||||||
|
|
||||||
|
model.Items = append(model.Items, strategyItem)
|
||||||
|
}
|
||||||
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数校验
|
||||||
|
func (s *LineReduceStrategyUpdateReq) Valid() error {
|
||||||
|
if s.Name == "" {
|
||||||
|
return errors.New("减仓策略名称不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Status < 1 || s.Status > 2 {
|
||||||
|
return errors.New("状态值不合法")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.Items) == 0 {
|
||||||
|
return errors.New("减仓策略节点不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range s.Items {
|
||||||
|
if err := item.Valid(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyUpdateReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineReduceStrategyGetReq 功能获取请求参数
|
||||||
|
type LineReduceStrategyGetReq struct {
|
||||||
|
Id int `uri:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyGetReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineReduceStrategyDeleteReq 功能删除请求参数
|
||||||
|
type LineReduceStrategyDeleteReq struct {
|
||||||
|
Ids []int `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyDeleteReq) GetId() interface{} {
|
||||||
|
return s.Ids
|
||||||
|
}
|
||||||
134
app/admin/service/dto/line_reduce_strategy_item.go
Normal file
134
app/admin/service/dto/line_reduce_strategy_item.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/dto"
|
||||||
|
common "go-admin/common/models"
|
||||||
|
"go-admin/pkg/utility"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineReduceStrategyItemGetPageReq struct {
|
||||||
|
dto.Pagination `search:"-"`
|
||||||
|
LineReduceStrategyItemOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineReduceStrategyItemOrder struct {
|
||||||
|
Id string `form:"idOrder" search:"type:order;column:id;table:line_reduce_strategy_item"`
|
||||||
|
ReduceStrategyId string `form:"reduceStrategyIdOrder" search:"type:order;column:reduce_strategy_id;table:line_reduce_strategy_item"`
|
||||||
|
LossPercent string `form:"lossPercentOrder" search:"type:order;column:loss_percent;table:line_reduce_strategy_item"`
|
||||||
|
OrderType string `form:"orderTypeOrder" search:"type:order;column:order_type;table:line_reduce_strategy_item"`
|
||||||
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:line_reduce_strategy_item"`
|
||||||
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:line_reduce_strategy_item"`
|
||||||
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:line_reduce_strategy_item"`
|
||||||
|
CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:line_reduce_strategy_item"`
|
||||||
|
UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:line_reduce_strategy_item"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LineReduceStrategyItemGetPageReq) GetNeedSearch() interface{} {
|
||||||
|
return *m
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineReduceStrategyItem struct {
|
||||||
|
LossPercent decimal.Decimal `json:"lossPercent" comment:"止损百分比"`
|
||||||
|
QuantityPercent decimal.Decimal `json:"quantityPercent" comment:"数量百分比"`
|
||||||
|
OrderType string `json:"orderType" comment:"订单类型 LIMIT-限价 MARKET-市价"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyItem) Valid() error {
|
||||||
|
|
||||||
|
if s.LossPercent.Cmp(decimal.Zero) <= 0 {
|
||||||
|
return errors.New("百分比不能小于等于0")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.LossPercent.Cmp(decimal.NewFromFloat(100)) >= 0 {
|
||||||
|
return errors.New("百分比不能大于等于100")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.QuantityPercent.Cmp(decimal.Zero) <= 0 {
|
||||||
|
return errors.New("百分比不能小于等于0")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.QuantityPercent.Cmp(decimal.NewFromInt(100)) >= 0 {
|
||||||
|
return errors.New("数量百分比不能大于等于100")
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := []string{"LIMIT", "MARKET"}
|
||||||
|
|
||||||
|
if !utility.ContainsStr(keys, s.OrderType) {
|
||||||
|
return errors.New("订单类型不正确")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineReduceStrategyItemResp struct {
|
||||||
|
ReduceStrategyId int `json:"reduceStrategyId" comment:"减仓策略id"`
|
||||||
|
LossPercent decimal.Decimal `json:"lossPercent" comment:"亏损百分比"`
|
||||||
|
OrderType string `json:"orderType" comment:"订单类型 LIMIT-限价 MARKET-市价"`
|
||||||
|
Actived int `json:"actived" comment:"是否已减仓 1=未减仓 2=已减仓"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineReduceStrategyItemInsertReq struct {
|
||||||
|
Id int `json:"-" comment:"主键id"` // 主键id
|
||||||
|
ReduceStrategyId int `json:"reduceStrategyId" comment:"减仓策略id"`
|
||||||
|
LossPercent decimal.Decimal `json:"lossPercent" comment:"亏损百分比"`
|
||||||
|
OrderType string `json:"orderType" comment:"订单类型 LIMIT-限价 MARKET-市价"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyItemInsertReq) Generate(model *models.LineReduceStrategyItem) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.ReduceStrategyId = s.ReduceStrategyId
|
||||||
|
model.LossPercent = s.LossPercent
|
||||||
|
model.OrderType = s.OrderType
|
||||||
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyItemInsertReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineReduceStrategyItemUpdateReq struct {
|
||||||
|
Id int `uri:"id" comment:"主键id"` // 主键id
|
||||||
|
ReduceStrategyId int `json:"reduceStrategyId" comment:"减仓策略id"`
|
||||||
|
LossPercent decimal.Decimal `json:"lossPercent" comment:"亏损百分比"`
|
||||||
|
OrderType string `json:"orderType" comment:"订单类型 LIMIT-限价 MARKET-市价"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyItemUpdateReq) Generate(model *models.LineReduceStrategyItem) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.ReduceStrategyId = s.ReduceStrategyId
|
||||||
|
model.LossPercent = s.LossPercent
|
||||||
|
model.OrderType = s.OrderType
|
||||||
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyItemUpdateReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineReduceStrategyItemGetReq 功能获取请求参数
|
||||||
|
type LineReduceStrategyItemGetReq struct {
|
||||||
|
Id int `uri:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyItemGetReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineReduceStrategyItemDeleteReq 功能删除请求参数
|
||||||
|
type LineReduceStrategyItemDeleteReq struct {
|
||||||
|
Ids []int `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineReduceStrategyItemDeleteReq) GetId() interface{} {
|
||||||
|
return s.Ids
|
||||||
|
}
|
||||||
174
app/admin/service/dto/line_strategy_template.go
Normal file
174
app/admin/service/dto/line_strategy_template.go
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/dto"
|
||||||
|
common "go-admin/common/models"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineStrategyTemplateGetPageReq struct {
|
||||||
|
dto.Pagination `search:"-"`
|
||||||
|
Direction int `form:"direction" search:"type:exact;column:direction;table:line_strategy_template" comment:"涨跌方向 1-涨 2-跌"`
|
||||||
|
Percentag decimal.Decimal `form:"percentag" search:"type:exact;column:percentag;table:line_strategy_template" comment:"涨跌点数"`
|
||||||
|
CompareType int `form:"compareType" search:"type:exact;column:compare_type;table:line_strategy_template" comment:"比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "`
|
||||||
|
LineStrategyTemplateOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineStrategyTemplateOrder struct {
|
||||||
|
Id string `form:"idOrder" search:"type:order;column:id;table:line_strategy_template"`
|
||||||
|
Direction string `form:"directionOrder" search:"type:order;column:direction;table:line_strategy_template"`
|
||||||
|
Percentag string `form:"percentagOrder" search:"type:order;column:percentag;table:line_strategy_template"`
|
||||||
|
CompareType string `form:"compareTypeOrder" search:"type:order;column:compare_type;table:line_strategy_template"`
|
||||||
|
TimeSlotStart string `form:"timeSlotStartOrder" search:"type:order;column:time_slot_start;table:line_strategy_template"`
|
||||||
|
TimeSlotEnd string `form:"timeSlotEndOrder" search:"type:order;column:time_slot_end;table:line_strategy_template"`
|
||||||
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:line_strategy_template"`
|
||||||
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:line_strategy_template"`
|
||||||
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:line_strategy_template"`
|
||||||
|
CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:line_strategy_template"`
|
||||||
|
UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:line_strategy_template"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LineStrategyTemplateGetPageReq) GetNeedSearch() interface{} {
|
||||||
|
return *m
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineStrategyTemplateInsertReq struct {
|
||||||
|
Id int `json:"-" comment:"主键id"` // 主键id
|
||||||
|
Name string `json:"name" comment:"策略名称"`
|
||||||
|
Direction int `json:"direction" comment:"涨跌方向 1-涨 2-跌"`
|
||||||
|
Percentag decimal.Decimal `json:"percentag" comment:"涨跌点数"`
|
||||||
|
CompareType int `json:"compareType" comment:"比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "`
|
||||||
|
TimeSlotStart int `json:"timeSlotStart" comment:"时间段(分)"`
|
||||||
|
// TimeSlotEnd int `json:"timeSlotEnd" comment:"时间断截至(分)"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
// 交易参数
|
||||||
|
func (s *LineStrategyTemplateInsertReq) Valid() error {
|
||||||
|
if s.Name == "" {
|
||||||
|
return errors.New("策略名称不能为空")
|
||||||
|
}
|
||||||
|
if len(s.Name) > 50 {
|
||||||
|
return errors.New("策略名称长度不能超过50")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Percentag.Cmp(decimal.Zero) <= 0 {
|
||||||
|
return errors.New("涨跌点数不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.CompareType < 1 || s.CompareType > 5 {
|
||||||
|
return errors.New("比较类型不合法")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.TimeSlotStart < 0 {
|
||||||
|
return errors.New("时间段不合法")
|
||||||
|
}
|
||||||
|
|
||||||
|
// if s.TimeSlotEnd < s.TimeSlotStart {
|
||||||
|
// return errors.New("时间段不合法")
|
||||||
|
// }
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineStrategyTemplateInsertReq) Generate(model *models.LineStrategyTemplate) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.Name = s.Name
|
||||||
|
model.Direction = s.Direction
|
||||||
|
model.Percentag = s.Percentag
|
||||||
|
model.CompareType = s.CompareType
|
||||||
|
model.TimeSlotStart = s.TimeSlotStart
|
||||||
|
// model.TimeSlotEnd = s.TimeSlotEnd
|
||||||
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineStrategyTemplateInsertReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineStrategyTemplateUpdateReq struct {
|
||||||
|
Id int `uri:"id" comment:"主键id"` // 主键id
|
||||||
|
Name string `json:"name" comment:"策略名称"`
|
||||||
|
Direction int `json:"direction" comment:"涨跌方向 1-涨 2-跌"`
|
||||||
|
Percentag decimal.Decimal `json:"percentag" comment:"涨跌点数"`
|
||||||
|
CompareType int `json:"compareType" comment:"比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "`
|
||||||
|
TimeSlotStart int `json:"timeSlotStart" comment:"时间段(分)"`
|
||||||
|
// TimeSlotEnd int `json:"timeSlotEnd" comment:"时间断截至(分)"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
// 交易参数
|
||||||
|
func (s *LineStrategyTemplateUpdateReq) Valid() error {
|
||||||
|
if s.Name == "" {
|
||||||
|
return errors.New("策略名称不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.Name) > 50 {
|
||||||
|
return errors.New("策略名称长度不能超过50")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Percentag.Cmp(decimal.Zero) <= 0 {
|
||||||
|
return errors.New("涨跌点数不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.CompareType < 1 || s.CompareType > 5 {
|
||||||
|
return errors.New("比较类型不合法")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.TimeSlotStart < 0 {
|
||||||
|
return errors.New("时间段不合法")
|
||||||
|
}
|
||||||
|
|
||||||
|
// if s.TimeSlotEnd < s.TimeSlotStart {
|
||||||
|
// return errors.New("时间段不合法")
|
||||||
|
// }
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (s *LineStrategyTemplateUpdateReq) Generate(model *models.LineStrategyTemplate) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.Name = s.Name
|
||||||
|
model.Direction = s.Direction
|
||||||
|
model.Percentag = s.Percentag
|
||||||
|
model.CompareType = s.CompareType
|
||||||
|
model.TimeSlotStart = s.TimeSlotStart
|
||||||
|
// model.TimeSlotEnd = s.TimeSlotEnd
|
||||||
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineStrategyTemplateUpdateReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineStrategyTemplateGetReq 功能获取请求参数
|
||||||
|
type LineStrategyTemplateGetReq struct {
|
||||||
|
Id int `uri:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineStrategyTemplateGetReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineStrategyTemplateDeleteReq 功能删除请求参数
|
||||||
|
type LineStrategyTemplateDeleteReq struct {
|
||||||
|
Ids []int `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineStrategyTemplateDeleteReq) GetId() interface{} {
|
||||||
|
return s.Ids
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineStrategyTemplateRedis struct {
|
||||||
|
Direction int `json:"direction" comment:"涨跌方向 1-涨 2-跌"`
|
||||||
|
Percentag decimal.Decimal `json:"percentag" comment:"涨跌点数"`
|
||||||
|
CompareType int `json:"compareType" comment:"比较类型 1-大于 2-大于等于 3-小于 4-小于等于 5等于 "`
|
||||||
|
TimeSlotStart int `json:"timeSlotStart" comment:"时间段开始(分)"`
|
||||||
|
TimeSlotEnd int `json:"timeSlotEnd" comment:"时间断截至(分)"`
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ type LineSymbolGetPageReq struct {
|
|||||||
BaseAsset string `form:"baseAsset" search:"type:contains;column:base_asset;table:line_symbol" comment:"基础货币"`
|
BaseAsset string `form:"baseAsset" search:"type:contains;column:base_asset;table:line_symbol" comment:"基础货币"`
|
||||||
QuoteAsset string `form:"quoteAsset" search:"type:exact;column:quote_asset;table:line_symbol" comment:"计价货币"`
|
QuoteAsset string `form:"quoteAsset" search:"type:exact;column:quote_asset;table:line_symbol" comment:"计价货币"`
|
||||||
Type string `form:"type" search:"type:exact;column:type;table:line_symbol" comment:"交易对类型"`
|
Type string `form:"type" search:"type:exact;column:type;table:line_symbol" comment:"交易对类型"`
|
||||||
|
// StrategyTemplateId int `form:"strategyTemplateId" search:"-" comment:"策略id"`
|
||||||
LineSymbolOrder
|
LineSymbolOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
88
app/admin/service/dto/line_symbol_price.go
Normal file
88
app/admin/service/dto/line_symbol_price.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/dto"
|
||||||
|
common "go-admin/common/models"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineSymbolPriceGetPageReq struct {
|
||||||
|
dto.Pagination `search:"-"`
|
||||||
|
Symbol string `form:"symbol" search:"type:exact;column:symbol;table:line_symbol_price" comment:"交易对"`
|
||||||
|
Status int `form:"status" search:"type:exact;column:status;table:line_symbol_price" comment:"状态 1-启用 2-禁用"`
|
||||||
|
LineSymbolPriceOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineSymbolPriceOrder struct {
|
||||||
|
Id string `form:"idOrder" search:"type:order;column:id;table:line_symbol_price"`
|
||||||
|
Symbol string `form:"symbolOrder" search:"type:order;column:symbol;table:line_symbol_price"`
|
||||||
|
Status string `form:"statusOrder" search:"type:order;column:status;table:line_symbol_price"`
|
||||||
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:line_symbol_price"`
|
||||||
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:line_symbol_price"`
|
||||||
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:line_symbol_price"`
|
||||||
|
CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:line_symbol_price"`
|
||||||
|
UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:line_symbol_price"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LineSymbolPriceGetPageReq) GetNeedSearch() interface{} {
|
||||||
|
return *m
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineSymbolPriceInsertReq struct {
|
||||||
|
Id int `json:"-" comment:"主键id"` // 主键id
|
||||||
|
Symbol string `json:"symbol" comment:"交易对"`
|
||||||
|
Status int `json:"status" comment:"状态 1-启用 2-禁用"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineSymbolPriceInsertReq) Generate(model *models.LineSymbolPrice) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.Symbol = strings.ToUpper(s.Symbol)
|
||||||
|
model.Status = s.Status
|
||||||
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineSymbolPriceInsertReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineSymbolPriceUpdateReq struct {
|
||||||
|
Id int `uri:"id" comment:"主键id"` // 主键id
|
||||||
|
Symbol string `json:"symbol" comment:"交易对"`
|
||||||
|
Status int `json:"status" comment:"状态 1-启用 2-禁用"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineSymbolPriceUpdateReq) Generate(model *models.LineSymbolPrice) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.Symbol = strings.ToUpper(s.Symbol)
|
||||||
|
model.Status = s.Status
|
||||||
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineSymbolPriceUpdateReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineSymbolPriceGetReq 功能获取请求参数
|
||||||
|
type LineSymbolPriceGetReq struct {
|
||||||
|
Id int `uri:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineSymbolPriceGetReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineSymbolPriceDeleteReq 功能删除请求参数
|
||||||
|
type LineSymbolPriceDeleteReq struct {
|
||||||
|
Ids []int `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LineSymbolPriceDeleteReq) GetId() interface{} {
|
||||||
|
return s.Ids
|
||||||
|
}
|
||||||
@ -57,14 +57,15 @@ func (s *LineSystemSettingInsertReq) GetId() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LineSystemSettingUpdateReq struct {
|
type LineSystemSettingUpdateReq struct {
|
||||||
Id int `uri:"id" comment:"id"` // id
|
Id int `uri:"id" comment:"id"` // id
|
||||||
Time int64 `json:"time" comment:"导入:挂单时长达到时间后失效"`
|
Time int64 `json:"time" comment:"导入:挂单时长达到时间后失效"`
|
||||||
BatchTime int64 `json:"batchTime" comment:"批量:挂单时长达到时间后失效"`
|
BatchTime int64 `json:"batchTime" comment:"批量:挂单时长达到时间后失效"`
|
||||||
ProfitRate string `json:"profitRate" comment:"平仓盈利比例"`
|
ProfitRate string `json:"profitRate" comment:"平仓盈利比例"`
|
||||||
CoverOrderTypeBRate string `json:"coverOrderTypeBRate" comment:"b账户限价补单的买入百分比"`
|
CoverOrderTypeBRate string `json:"coverOrderTypeBRate" comment:"b账户限价补单的买入百分比"`
|
||||||
StopLossPremium decimal.Decimal `json:"stopLossPremium" comment:"限价止损溢价"`
|
StopLossPremium decimal.Decimal `json:"stopLossPremium" comment:"限价止损溢价"`
|
||||||
AddPositionPremium decimal.Decimal `json:"addPositionPremium" comment:"限价加仓溢价"`
|
AddPositionPremium decimal.Decimal `json:"addPositionPremium" comment:"限价加仓溢价"`
|
||||||
ReducePremium decimal.Decimal `json:"reducePremium" comment:"限价减仓溢价"`
|
ReducePremium decimal.Decimal `json:"reducePremium" comment:"限价减仓溢价"`
|
||||||
|
ReduceEarlyTriggerPercent decimal.Decimal `json:"reduceEarlyTriggerPercent" comment:"减仓提前触发百分比"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +80,7 @@ func (s *LineSystemSettingUpdateReq) Generate(model *models.LineSystemSetting) {
|
|||||||
model.StopLossPremium = s.StopLossPremium
|
model.StopLossPremium = s.StopLossPremium
|
||||||
model.AddPositionPremium = s.AddPositionPremium
|
model.AddPositionPremium = s.AddPositionPremium
|
||||||
model.ReducePremium = s.ReducePremium
|
model.ReducePremium = s.ReducePremium
|
||||||
|
model.ReduceEarlyTriggerPercent = s.ReduceEarlyTriggerPercent
|
||||||
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,19 +52,19 @@ func (e *LineApiUser) GetPage(c *dto.LineApiUserGetPageReq, p *actions.DataPermi
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var userSub binancedto.UserSubscribeState
|
|
||||||
for index := range *list {
|
for index := range *list {
|
||||||
val, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.USER_SUBSCRIBE, (*list)[index].ApiKey))
|
val, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.USER_SUBSCRIBE, (*list)[index].ApiKey))
|
||||||
|
var userSub binancedto.UserSubscribeState
|
||||||
|
|
||||||
if val != "" {
|
if val != "" {
|
||||||
sonic.Unmarshal([]byte(val), &userSub)
|
sonic.Unmarshal([]byte(val), &userSub)
|
||||||
|
|
||||||
if userSub.FuturesLastTime != nil {
|
if userSub.FuturesLastTime != nil {
|
||||||
(*list)[index].FuturesLastTime = userSub.FuturesLastTime.Format("2006-01-02 15:04:05")
|
(*list)[index].FuturesLastTime = userSub.FuturesLastTime
|
||||||
}
|
}
|
||||||
|
|
||||||
if userSub.SpotLastTime != nil {
|
if userSub.SpotLastTime != nil {
|
||||||
(*list)[index].SpotLastTime = userSub.SpotLastTime.Format("2006-01-02 15:04:05")
|
(*list)[index].SpotLastTime = userSub.SpotLastTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import (
|
|||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
"go-admin/pkg/utility/snowflakehelper"
|
"go-admin/pkg/utility/snowflakehelper"
|
||||||
"go-admin/services/binanceservice"
|
"go-admin/services/binanceservice"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -278,6 +279,8 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi
|
|||||||
futReduceVal, _ := helper.DefaultRedis.GetAllList(spotAddPositionKey)
|
futReduceVal, _ := helper.DefaultRedis.GetAllList(spotAddPositionKey)
|
||||||
spotAddPositionVal, _ := helper.DefaultRedis.GetAllList(futReduceKey)
|
spotAddPositionVal, _ := helper.DefaultRedis.GetAllList(futReduceKey)
|
||||||
spotReduceVal, _ := helper.DefaultRedis.GetAllList(spotReduceKey)
|
spotReduceVal, _ := helper.DefaultRedis.GetAllList(spotReduceKey)
|
||||||
|
spotStrategyMap := e.GetStrategyOrderListMap(1)
|
||||||
|
futStrategyMap := e.GetStrategyOrderListMap(2)
|
||||||
|
|
||||||
for _, v := range futAddPositionVal {
|
for _, v := range futAddPositionVal {
|
||||||
sonic.Unmarshal([]byte(v), &addPosition)
|
sonic.Unmarshal([]byte(v), &addPosition)
|
||||||
@ -336,8 +339,14 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi
|
|||||||
if val, ok := spotRedces[order.Id]; ok {
|
if val, ok := spotRedces[order.Id]; ok {
|
||||||
helper.DefaultRedis.LRem(spotReduceKey, val)
|
helper.DefaultRedis.LRem(spotReduceKey, val)
|
||||||
}
|
}
|
||||||
|
var tradedSetKey string
|
||||||
|
if order.SymbolType == 1 {
|
||||||
|
tradedSetKey = fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol)
|
||||||
|
} else {
|
||||||
|
tradedSetKey = fmt.Sprintf(global.TICKER_FUTURES, order.ExchangeType, order.Symbol)
|
||||||
|
}
|
||||||
|
|
||||||
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol))
|
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, tradedSetKey)
|
||||||
redisList.Price = utility.StringToDecimal(redisList.Price).Truncate(int32(tradeSet.PriceDigit)).String()
|
redisList.Price = utility.StringToDecimal(redisList.Price).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
marshal, _ := sonic.Marshal(redisList)
|
marshal, _ := sonic.Marshal(redisList)
|
||||||
if order.SymbolType == 1 {
|
if order.SymbolType == 1 {
|
||||||
@ -348,6 +357,13 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi
|
|||||||
helper.DefaultRedis.LRem(listKey, string(marshal))
|
helper.DefaultRedis.LRem(listKey, string(marshal))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case order.StrategyTemplateType == 1 && order.SymbolType == 1:
|
||||||
|
e.RemoveStrategyOrderCache(order.Id, order.SymbolType, order.ExchangeType, &spotStrategyMap)
|
||||||
|
case order.StrategyTemplateType == 1 && order.SymbolType == 2:
|
||||||
|
e.RemoveStrategyOrderCache(order.Id, order.SymbolType, order.ExchangeType, &futStrategyMap)
|
||||||
|
}
|
||||||
|
|
||||||
//会影响持仓的
|
//会影响持仓的
|
||||||
removeSymbolKey := fmt.Sprintf("%v_%s_%s_%s_%v", order.ApiId, order.ExchangeType, order.Symbol, order.Site, order.SymbolType)
|
removeSymbolKey := fmt.Sprintf("%v_%s_%s_%s_%v", order.ApiId, order.ExchangeType, order.Symbol, order.Site, order.SymbolType)
|
||||||
|
|
||||||
@ -362,6 +378,7 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi
|
|||||||
}
|
}
|
||||||
|
|
||||||
binanceservice.MainClosePositionClearCache(order.Id, order.SymbolType)
|
binanceservice.MainClosePositionClearCache(order.Id, order.SymbolType)
|
||||||
|
binanceservice.RemoveReduceReduceCacheByMainId(order.Id, order.SymbolType)
|
||||||
|
|
||||||
ints = append(ints, order.Id)
|
ints = append(ints, order.Id)
|
||||||
}
|
}
|
||||||
@ -403,6 +420,15 @@ func (e *LinePreOrder) AddPreOrderCheck(req *dto.LineAddPreOrderReq, p *actions.
|
|||||||
apiIds = append(apiIds, apiId)
|
apiIds = append(apiIds, apiId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.StrategyTemplateType == 1 && req.StrategyTemplateId > 0 {
|
||||||
|
cachePriceSymbols, _ := helper.DefaultRedis.GetAllList(rediskey.CacheSymbolLastPrice)
|
||||||
|
|
||||||
|
if !utility.ContainsStr(cachePriceSymbols, req.Symbol) {
|
||||||
|
*errs = append(*errs, errors.New("交易对涨跌幅缓存不存在"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
activeApiIds, _ := apiUserService.GetActiveApis(apiIds)
|
activeApiIds, _ := apiUserService.GetActiveApis(apiIds)
|
||||||
|
|
||||||
if len(activeApiIds) == 0 {
|
if len(activeApiIds) == 0 {
|
||||||
@ -438,6 +464,17 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
saveTemplateParams.CreateBy = req.CreateBy
|
saveTemplateParams.CreateBy = req.CreateBy
|
||||||
e.Orm.Model(&models.LineOrderTemplateLogs{}).Create(&saveTemplateParams)
|
e.Orm.Model(&models.LineOrderTemplateLogs{}).Create(&saveTemplateParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linestrategyTemplate := models.LineStrategyTemplate{}
|
||||||
|
|
||||||
|
if req.StrategyTemplateId > 0 {
|
||||||
|
e.Orm.Where("id =?", req.StrategyTemplateId).First(&linestrategyTemplate)
|
||||||
|
|
||||||
|
if linestrategyTemplate.Id == 0 {
|
||||||
|
*errs = append(*errs, fmt.Errorf("策略不存在:%v", req.StrategyTemplateId))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
if req.SaveTemplate == "2" {
|
if req.SaveTemplate == "2" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -461,13 +498,13 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
}
|
}
|
||||||
var AddOrder models.LinePreOrder
|
var AddOrder models.LinePreOrder
|
||||||
var profitOrder models.LinePreOrder
|
var profitOrder models.LinePreOrder
|
||||||
var stopOrder models.LinePreOrder
|
var reduceOrder models.LinePreOrder
|
||||||
|
|
||||||
//获取交易对
|
//获取交易对
|
||||||
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key)
|
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key)
|
||||||
tickerPrice := utility.StrToDecimal(tradeSet.LastPrice)
|
tickerPrice := utility.StrToDecimal(tradeSet.LastPrice)
|
||||||
if tickerPrice.Equal(decimal.Zero) { //redis 没有这个值
|
if tickerPrice.Equal(decimal.Zero) { //redis 没有这个值
|
||||||
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 交易行情出错", id, req.Symbol))
|
*errs = append(*errs, fmt.Errorf("api_id:%d 获取交易对:%s 交易行情出错", id, req.Symbol))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,7 +577,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
AddOrder.Num = utility.SafeDiv(buyPrice, fromString).Truncate(int32(tradeSet.AmountDigit)).String()
|
AddOrder.Num = utility.SafeDiv(buyPrice, fromString).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
}
|
}
|
||||||
if utility.StringToFloat64(AddOrder.Num) < tradeSet.MinQty {
|
if utility.StringToFloat64(AddOrder.Num) < tradeSet.MinQty {
|
||||||
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 小于最小下单数量", id, req.Symbol))
|
*errs = append(*errs, fmt.Errorf("api_id:%d 获取交易对:%s 小于最小下单数量", id, req.Symbol))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||||
@ -551,10 +588,11 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
AddOrder.GroupId = "0"
|
AddOrder.GroupId = "0"
|
||||||
AddOrder.Status = 0
|
AddOrder.Status = 0
|
||||||
copier.Copy(&profitOrder, &AddOrder)
|
copier.Copy(&profitOrder, &AddOrder)
|
||||||
copier.Copy(&stopOrder, &AddOrder)
|
copier.Copy(&reduceOrder, &AddOrder)
|
||||||
|
|
||||||
preOrderStatus := models.LinePreOrderStatus{}
|
preOrderStatus := models.LinePreOrderStatus{}
|
||||||
preOrderStatus.OrderSn = AddOrder.OrderSn
|
preOrderStatus.OrderSn = AddOrder.OrderSn
|
||||||
|
mainPrice := utility.StringToDecimal(AddOrder.Price)
|
||||||
|
|
||||||
//订单配置信息
|
//订单配置信息
|
||||||
preOrderExts := make([]models.LinePreOrderExt, 0)
|
preOrderExts := make([]models.LinePreOrderExt, 0)
|
||||||
@ -565,9 +603,16 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
OrderType: req.PriceType,
|
OrderType: req.PriceType,
|
||||||
TakeProfitRatio: utility.StringToDecimal(req.Profit),
|
TakeProfitRatio: utility.StringToDecimal(req.Profit),
|
||||||
TakeProfitNumRatio: req.ProfitNumRatio,
|
TakeProfitNumRatio: req.ProfitNumRatio,
|
||||||
|
StopLossRatio: req.StopLoss,
|
||||||
TpTpPriceRatio: req.ProfitTpTpPriceRatio,
|
TpTpPriceRatio: req.ProfitTpTpPriceRatio,
|
||||||
TpSlPriceRatio: req.ProfitTpSlPriceRatio,
|
TpSlPriceRatio: req.ProfitTpSlPriceRatio,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.PricePattern == "mixture" {
|
||||||
|
defultExt.TakeProfitRatio = mainPrice.Div(utility.StrToDecimal(req.Profit)).Sub(decimal.NewFromInt(1)).Abs().Mul(decimal.NewFromInt(100)).Truncate(2)
|
||||||
|
defultExt.StopLossRatio = mainPrice.Div(req.StopLoss).Sub(decimal.NewFromInt(1)).Abs().Mul(decimal.NewFromInt(100)).Truncate(2)
|
||||||
|
}
|
||||||
|
|
||||||
//减仓单
|
//减仓单
|
||||||
defultExt2 := models.LinePreOrderExt{
|
defultExt2 := models.LinePreOrderExt{
|
||||||
AddType: 2,
|
AddType: 2,
|
||||||
@ -579,18 +624,12 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
TakeProfitNumRatio: decimal.NewFromInt(100), //减仓止盈默认100%
|
TakeProfitNumRatio: decimal.NewFromInt(100), //减仓止盈默认100%
|
||||||
StopLossRatio: req.ReduceStopLossRatio,
|
StopLossRatio: req.ReduceStopLossRatio,
|
||||||
}
|
}
|
||||||
mainPrice := utility.StringToDecimal(AddOrder.Price)
|
|
||||||
mainAmount := utility.SafeDiv(buyPrice, mainPrice)
|
mainAmount := utility.SafeDiv(buyPrice, mainPrice)
|
||||||
defultExt.TotalAfter = utility.StrToDecimal(AddOrder.Num).Truncate(int32(tradeSet.AmountDigit))
|
defultExt.TotalAfter = utility.StrToDecimal(AddOrder.Num).Truncate(int32(tradeSet.AmountDigit))
|
||||||
defultExt2.TotalBefore = defultExt.TotalAfter
|
defultExt2.TotalBefore = defultExt.TotalAfter
|
||||||
|
|
||||||
// if decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Cmp(decimal.Zero) > 0 {
|
|
||||||
default2NumPercent := utility.SafeDiv(decimal.NewFromInt(100).Sub(req.ReduceNumRatio), decimal.NewFromInt(100))
|
default2NumPercent := utility.SafeDiv(decimal.NewFromInt(100).Sub(req.ReduceNumRatio), decimal.NewFromInt(100))
|
||||||
defultExt2.TotalAfter = mainAmount.Mul(default2NumPercent).Truncate(int32(tradeSet.AmountDigit))
|
defultExt2.TotalAfter = mainAmount.Mul(default2NumPercent).Truncate(int32(tradeSet.AmountDigit))
|
||||||
defultExt2.ReTakeRatio = utility.SafeDiv(req.ReducePriceRatio, default2NumPercent).Truncate(2)
|
|
||||||
|
|
||||||
preOrderExts = append(preOrderExts, defultExt)
|
|
||||||
preOrderExts = append(preOrderExts, defultExt2)
|
|
||||||
|
|
||||||
calculateResp := dto.CalculateBreakEvenRatioResp{}
|
calculateResp := dto.CalculateBreakEvenRatioResp{}
|
||||||
mainParam := dto.CalculateBreakEevenRatioReq{
|
mainParam := dto.CalculateBreakEevenRatioReq{
|
||||||
@ -606,15 +645,22 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
AddPositionVal: req.ReduceNumRatio,
|
AddPositionVal: req.ReduceNumRatio,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.PricePattern == "mixture" {
|
||||||
|
mainParam.LossEndPercent = mainPrice.Div(req.ReducePriceRatio).Sub(decimal.NewFromInt(1)).Abs().Mul(decimal.NewFromInt(100)).Truncate(2)
|
||||||
|
defultExt2.PriceRatio = mainParam.LossEndPercent
|
||||||
|
}
|
||||||
|
|
||||||
//计算减仓后
|
//计算减仓后
|
||||||
mainParam.LossEndPercent = req.ReducePriceRatio
|
defultExt2.ReTakeRatio = utility.SafeDiv(mainParam.LossEndPercent, default2NumPercent).Truncate(2)
|
||||||
mainParam.RemainingQuantity = mainAmount
|
mainParam.RemainingQuantity = mainAmount
|
||||||
e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet)
|
e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet)
|
||||||
mainParam.RemainingQuantity = calculateResp.RemainingQuantity //mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
mainParam.RemainingQuantity = calculateResp.RemainingQuantity //mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||||
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU //buyPrice.Mul(req.ReducePriceRatio.Div(decimal.NewFromInt(100)).Truncate(4)).Truncate(int32(tradeSet.PriceDigit))
|
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU //buyPrice.Mul(req.ReducePriceRatio.Div(decimal.NewFromInt(100)).Truncate(4)).Truncate(int32(tradeSet.PriceDigit))
|
||||||
req.ReduceReTakeProfitRatio = calculateResp.Ratio
|
req.ReduceReTakeProfitRatio = calculateResp.Ratio
|
||||||
mainParam.LossBeginPercent = req.ReducePriceRatio
|
mainParam.LossBeginPercent = mainParam.LossEndPercent
|
||||||
defultExt.ReTakeRatio = calculateResp.Ratio
|
// defultExt.ReTakeRatio = calculateResp.Ratio
|
||||||
|
preOrderExts = append(preOrderExts, defultExt)
|
||||||
|
preOrderExts = append(preOrderExts, defultExt2)
|
||||||
|
|
||||||
for index, addPosition := range req.Ext {
|
for index, addPosition := range req.Ext {
|
||||||
ext := models.LinePreOrderExt{
|
ext := models.LinePreOrderExt{
|
||||||
@ -651,11 +697,20 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
preOrderExts = append(preOrderExts, ext)
|
preOrderExts = append(preOrderExts, ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//获取减仓策略
|
||||||
|
var reduceStrategy models.LineReduceStrategy
|
||||||
|
|
||||||
|
if req.ReduceStrategyId > 0 {
|
||||||
|
reduceStrategyService := LineReduceStrategy{Service: e.Service}
|
||||||
|
reduceStrategy, _ = reduceStrategyService.GetById(req.ReduceStrategyId)
|
||||||
|
}
|
||||||
|
|
||||||
//事务添加
|
//事务添加
|
||||||
e.Orm.Transaction(func(tx *gorm.DB) error {
|
e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
reduceOrderStrategys := make([]models.LineOrderReduceStrategy, 0)
|
||||||
err := tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&AddOrder).Error
|
err := tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&AddOrder).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", id, req.Symbol))
|
*errs = append(*errs, fmt.Errorf("api_id:%d 获取交易对:%s 生成订单失败", id, req.Symbol))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,117 +719,72 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
//加仓、减仓状态
|
//加仓、减仓状态
|
||||||
tx.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus)
|
tx.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus)
|
||||||
preOrderExts[0].OrderId = AddOrder.Id
|
preOrderExts[0].OrderId = AddOrder.Id
|
||||||
list := dto.PreOrderRedisList{
|
|
||||||
Id: AddOrder.Id,
|
|
||||||
Symbol: AddOrder.Symbol,
|
|
||||||
Price: AddOrder.Price,
|
|
||||||
Site: AddOrder.Site,
|
|
||||||
ApiId: AddOrder.ApiId,
|
|
||||||
OrderSn: AddOrder.OrderSn,
|
|
||||||
QuoteSymbol: AddOrder.QuoteSymbol,
|
|
||||||
}
|
|
||||||
marshal, _ := sonic.Marshal(&list)
|
|
||||||
var preKey string
|
|
||||||
if AddOrder.SymbolType == global.SYMBOL_SPOT {
|
|
||||||
preKey = fmt.Sprintf(rediskey.PreSpotOrderList, AddOrder.ExchangeType)
|
|
||||||
} else {
|
|
||||||
preKey = fmt.Sprintf(rediskey.PreFutOrderList, AddOrder.ExchangeType)
|
|
||||||
}
|
|
||||||
helper.DefaultRedis.LPushList(preKey, string(marshal))
|
|
||||||
|
|
||||||
//是否有止盈止损订单
|
childOrders, err := makeFuturesTakeAndReduce(&AddOrder, defultExt, tradeSet)
|
||||||
if req.Profit != "" {
|
|
||||||
if req.PricePattern == "mixture" {
|
|
||||||
mixturePrice := utility.StrToDecimal(req.Profit)
|
|
||||||
|
|
||||||
if mixturePrice.Cmp(decimal.Zero) <= 0 {
|
if err != nil {
|
||||||
return fmt.Errorf("止盈价不能小于等于0")
|
logger.Errorf("构建主单止盈止损失败,err:%v", err)
|
||||||
}
|
|
||||||
|
|
||||||
profitOrder.Price = mixturePrice.Truncate(int32(tradeSet.PriceDigit)).String()
|
|
||||||
profitOrder.Rate = "0"
|
|
||||||
} else {
|
|
||||||
if strings.ToUpper(req.Site) == "BUY" {
|
|
||||||
// profitOrder.Site = "SELL"
|
|
||||||
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
|
|
||||||
} else {
|
|
||||||
// profitOrder.Site = "BUY"
|
|
||||||
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
|
|
||||||
}
|
|
||||||
profitOrder.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
|
|
||||||
profitOrder.Status = 0
|
|
||||||
profitOrder.MainId = AddOrder.Id
|
|
||||||
|
|
||||||
if req.ProfitNumRatio.Cmp(decimal.Zero) > 0 {
|
|
||||||
numPercent := utility.SafeDiv(req.ProfitNumRatio, decimal.NewFromInt(100))
|
|
||||||
profitOrder.Num = utility.StrToDecimal(profitOrder.Num).Mul(numPercent).Truncate(int32(tradeSet.AmountDigit)).String()
|
|
||||||
}
|
|
||||||
tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&profitOrder)
|
|
||||||
|
|
||||||
//不全部止盈的时候
|
|
||||||
if req.ProfitNumRatio.Cmp(decimal.Zero) > 0 && req.ProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 {
|
|
||||||
reminQuantity := utility.StrToDecimal(AddOrder.Num).Sub(utility.StrToDecimal(profitOrder.Num))
|
|
||||||
|
|
||||||
childrens, err := makeTpOrder(&profitOrder, reminQuantity, req.ProfitTpTpPriceRatio, req.ProfitTpSlPriceRatio, &tradeSet)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("生成止盈后子订单失败")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Create(&childrens)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(childOrders) > 0 {
|
||||||
|
tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&childOrders)
|
||||||
|
|
||||||
|
for _, childOrder := range childOrders {
|
||||||
|
//不全部止盈的时候
|
||||||
|
if childOrder.OrderType == 1 && req.ProfitNumRatio.Cmp(decimal.Zero) > 0 && req.ProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 {
|
||||||
|
reminQuantity := utility.StrToDecimal(AddOrder.Num).Sub(utility.StrToDecimal(childOrder.Num))
|
||||||
|
|
||||||
|
childrens, err := makeTpOrder(&childOrder, reminQuantity, req.ProfitTpTpPriceRatio, req.ProfitTpSlPriceRatio, &tradeSet)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("生成止盈后子订单失败")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Create(&childrens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//减仓单
|
||||||
if req.ReducePriceRatio.Cmp(decimal.Zero) > 0 {
|
if req.ReducePriceRatio.Cmp(decimal.Zero) > 0 {
|
||||||
if req.PricePattern == "mixture" {
|
if req.PricePattern == "mixture" {
|
||||||
if req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 {
|
if req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 {
|
||||||
return errors.New("检查价格不能小于等于0")
|
return errors.New("检查价格不能小于等于0")
|
||||||
}
|
}
|
||||||
|
|
||||||
stopOrder.Price = req.ReducePriceRatio.Truncate(int32(tradeSet.PriceDigit)).String()
|
reduceOrder.Price = req.ReducePriceRatio.Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
stopOrder.Rate = "0"
|
reduceOrder.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()
|
reduceOrder.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()
|
reduceOrder.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()
|
reduceOrder.Rate = req.ReducePriceRatio.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.ToUpper(req.Site) == "BUY" {
|
if strings.ToUpper(req.Site) == "BUY" {
|
||||||
stopOrder.Site = "SELL"
|
reduceOrder.Site = "SELL"
|
||||||
} else {
|
} else {
|
||||||
stopOrder.Site = "BUY"
|
reduceOrder.Site = "BUY"
|
||||||
}
|
}
|
||||||
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
reduceOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||||
stopOrder.Pid = AddOrder.Id
|
reduceOrder.Pid = AddOrder.Id
|
||||||
stopOrder.MainId = AddOrder.Id
|
reduceOrder.MainId = AddOrder.Id
|
||||||
stopOrder.OrderType = 4
|
reduceOrder.OrderType = 4
|
||||||
stopOrder.Status = 0
|
reduceOrder.Status = 0
|
||||||
stopOrder.BuyPrice = "0"
|
reduceOrder.BuyPrice = "0"
|
||||||
stopNum := utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4))
|
stopNum := utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4))
|
||||||
stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String()
|
reduceOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
stopOrder.ExpireTime = time.Now().AddDate(10, 0, 0)
|
reduceOrder.ExpireTime = time.Now().AddDate(10, 0, 0)
|
||||||
|
|
||||||
tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&stopOrder)
|
tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&reduceOrder)
|
||||||
preOrderExts[1].OrderId = stopOrder.Id
|
preOrderExts[1].OrderId = reduceOrder.Id
|
||||||
if req.ReduceNumRatio.Cmp(decimal.Zero) > 0 && req.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) < 0 {
|
if req.ReduceNumRatio.Cmp(decimal.Zero) > 0 && req.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) < 0 {
|
||||||
if newOrders, err := makeReduceTakeAndStoploss(&stopOrder, defultExt2, tradeSet, false); err != nil {
|
if newOrders, err := makeReduceTakeAndStoploss(&reduceOrder, defultExt2, tradeSet, false); err != nil {
|
||||||
logger.Errorf("主单减仓生成止盈、减仓失败 err:%v", err)
|
logger.Errorf("主单减仓生成止盈、减仓失败 err:%v", err)
|
||||||
return err
|
return err
|
||||||
} else if len(newOrders) > 0 {
|
} else if len(newOrders) > 0 {
|
||||||
@ -784,9 +794,13 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if reduceStrategy.Id > 0 {
|
||||||
|
reduceOrderStrategys = append(reduceOrderStrategys, initOrderReduceStrategy(reduceStrategy, reduceOrder.Id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//添加止盈单
|
//添加后续节点
|
||||||
for index, v := range preOrderExts {
|
for index, v := range preOrderExts {
|
||||||
preOrderExts[index].MainOrderId = AddOrder.Id
|
preOrderExts[index].MainOrderId = AddOrder.Id
|
||||||
if index < 2 {
|
if index < 2 {
|
||||||
@ -825,7 +839,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
}
|
}
|
||||||
|
|
||||||
for index := range orders {
|
for index := range orders {
|
||||||
//减仓单且 减仓比例大于0 小于100 就冲下止盈止损
|
//止盈后止盈止损
|
||||||
if orders[index].OrderType == 1 && v.TakeProfitRatio.Cmp(decimal.Zero) > 0 && v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) < 0 {
|
if orders[index].OrderType == 1 && v.TakeProfitRatio.Cmp(decimal.Zero) > 0 && v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) < 0 {
|
||||||
reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), v, tradeSet, true)
|
reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), v, tradeSet, true)
|
||||||
|
|
||||||
@ -844,19 +858,112 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//减仓单绑定减仓未成交策略
|
||||||
|
if newOrder.OrderType == 4 && reduceStrategy.Id > 0 {
|
||||||
|
reduceOrderStrategys = append(reduceOrderStrategys, initOrderReduceStrategy(reduceStrategy, newOrder.Id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(reduceOrderStrategys) > 0 {
|
||||||
|
if err := tx.Create(reduceOrderStrategys).Error; err != nil {
|
||||||
|
logger.Error("保存减仓未成交策略失败")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tx.Model(&models.LinePreOrderExt{}).Create(&preOrderExts).Error
|
err = tx.Model(&models.LinePreOrderExt{}).Create(&preOrderExts).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
//保存下单缓存
|
||||||
|
return saveOrderCache(req, AddOrder, linestrategyTemplate)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 构建减仓单减仓策略
|
||||||
|
func initOrderReduceStrategy(reduceStrategy models.LineReduceStrategy, orderId int) models.LineOrderReduceStrategy {
|
||||||
|
result := models.LineOrderReduceStrategy{}
|
||||||
|
strategys := make([]dto.LineReduceStrategyItemResp, 0)
|
||||||
|
result.OrderId = orderId
|
||||||
|
result.ReduceStrategyId = reduceStrategy.Id
|
||||||
|
result.Actived = 2
|
||||||
|
|
||||||
|
for _, item := range reduceStrategy.Items {
|
||||||
|
strategys = append(strategys, dto.LineReduceStrategyItemResp{
|
||||||
|
LossPercent: item.LossPercent,
|
||||||
|
OrderType: item.OrderType,
|
||||||
|
Actived: 2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
str, _ := sonic.MarshalString(strategys)
|
||||||
|
|
||||||
|
if str != "" {
|
||||||
|
result.ItemContent = str
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存下单缓存
|
||||||
|
func saveOrderCache(req *dto.LineAddPreOrderReq, AddOrder models.LinePreOrder, linestrategyTemplate models.LineStrategyTemplate) error {
|
||||||
|
var preKey string
|
||||||
|
var marshal []byte
|
||||||
|
|
||||||
|
switch {
|
||||||
|
//策略下单
|
||||||
|
case req.StrategyTemplateType == 1 && req.StrategyTemplateId > 0:
|
||||||
|
|
||||||
|
list := dto.StrategyOrderRedisList{
|
||||||
|
Id: AddOrder.Id,
|
||||||
|
OrderSn: AddOrder.OrderSn,
|
||||||
|
ApiId: AddOrder.ApiId,
|
||||||
|
Symbol: AddOrder.Symbol,
|
||||||
|
Price: AddOrder.Price,
|
||||||
|
Site: AddOrder.Site,
|
||||||
|
QuoteSymbol: AddOrder.QuoteSymbol,
|
||||||
|
}
|
||||||
|
list.Direction = linestrategyTemplate.Direction
|
||||||
|
list.Percentag = linestrategyTemplate.Percentag
|
||||||
|
list.CompareType = linestrategyTemplate.CompareType
|
||||||
|
list.TimeSlotStart = linestrategyTemplate.TimeSlotStart
|
||||||
|
|
||||||
|
marshal, _ = sonic.Marshal(&list)
|
||||||
|
if AddOrder.SymbolType == global.SYMBOL_SPOT {
|
||||||
|
preKey = fmt.Sprintf(rediskey.StrategySpotOrderList, AddOrder.ExchangeType)
|
||||||
|
} else {
|
||||||
|
preKey = fmt.Sprintf(rediskey.StrategyFutOrderList, AddOrder.ExchangeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
//直接下单
|
||||||
|
default:
|
||||||
|
list := dto.PreOrderRedisList{
|
||||||
|
Id: AddOrder.Id,
|
||||||
|
Symbol: AddOrder.Symbol,
|
||||||
|
Price: AddOrder.Price,
|
||||||
|
Site: AddOrder.Site,
|
||||||
|
ApiId: AddOrder.ApiId,
|
||||||
|
OrderSn: AddOrder.OrderSn,
|
||||||
|
QuoteSymbol: AddOrder.QuoteSymbol,
|
||||||
|
}
|
||||||
|
marshal, _ = sonic.Marshal(&list)
|
||||||
|
if AddOrder.SymbolType == global.SYMBOL_SPOT {
|
||||||
|
preKey = fmt.Sprintf(rediskey.PreSpotOrderList, AddOrder.ExchangeType)
|
||||||
|
} else {
|
||||||
|
preKey = fmt.Sprintf(rediskey.PreFutOrderList, AddOrder.ExchangeType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := helper.DefaultRedis.LPushList(preKey, string(marshal))
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// 生成加仓单
|
// 生成加仓单
|
||||||
func createPreAddPosition(preOrder *models.LinePreOrder, v models.LinePreOrderExt, tradeSet models2.TradeSet) models.LinePreOrder {
|
func createPreAddPosition(preOrder *models.LinePreOrder, v models.LinePreOrderExt, tradeSet models2.TradeSet) models.LinePreOrder {
|
||||||
data := models.LinePreOrder{}
|
data := models.LinePreOrder{}
|
||||||
@ -932,7 +1039,6 @@ func createPreReduceOrder(preOrder *models.LinePreOrder, ext models.LinePreOrder
|
|||||||
|
|
||||||
stopOrder.OrderType = 4
|
stopOrder.OrderType = 4
|
||||||
stopOrder.Status = 0
|
stopOrder.Status = 0
|
||||||
stopOrder.Rate = ext.PriceRatio.String()
|
|
||||||
stopOrder.Num = ext.TotalAfter.Sub(ext.TotalBefore).Abs().Truncate(int32(tradeSet.AmountDigit)).String()
|
stopOrder.Num = ext.TotalAfter.Sub(ext.TotalBefore).Abs().Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
stopOrder.BuyPrice = "0"
|
stopOrder.BuyPrice = "0"
|
||||||
stopOrder.Rate = ext.PriceRatio.String()
|
stopOrder.Rate = ext.PriceRatio.String()
|
||||||
@ -959,6 +1065,7 @@ func createPreReduceOrder(preOrder *models.LinePreOrder, ext models.LinePreOrder
|
|||||||
// 构建止盈、止盈止损
|
// 构建止盈、止盈止损
|
||||||
func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) {
|
func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) {
|
||||||
orders := make([]models.LinePreOrder, 0)
|
orders := make([]models.LinePreOrder, 0)
|
||||||
|
mainId := preOrder.Id
|
||||||
var side string
|
var side string
|
||||||
|
|
||||||
if (preOrder.OrderType != 0 && strings.ToUpper(preOrder.Site) == "BUY") || (preOrder.OrderType == 0 && strings.ToUpper(preOrder.Site) == "SELL") {
|
if (preOrder.OrderType != 0 && strings.ToUpper(preOrder.Site) == "BUY") || (preOrder.OrderType == 0 && strings.ToUpper(preOrder.Site) == "SELL") {
|
||||||
@ -967,6 +1074,10 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO
|
|||||||
side = "SELL"
|
side = "SELL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if preOrder.MainId > 0 {
|
||||||
|
mainId = preOrder.MainId
|
||||||
|
}
|
||||||
|
|
||||||
if ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 {
|
if ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 {
|
||||||
// 止盈单
|
// 止盈单
|
||||||
profitOrder := models.LinePreOrder{}
|
profitOrder := models.LinePreOrder{}
|
||||||
@ -977,11 +1088,7 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO
|
|||||||
profitOrder.Pid = preOrder.Id
|
profitOrder.Pid = preOrder.Id
|
||||||
profitOrder.OrderType = 1
|
profitOrder.OrderType = 1
|
||||||
profitOrder.Status = 0
|
profitOrder.Status = 0
|
||||||
profitOrder.MainId = preOrder.Id
|
profitOrder.MainId = mainId
|
||||||
|
|
||||||
if preOrder.MainId > 0 {
|
|
||||||
profitOrder.MainId = preOrder.MainId
|
|
||||||
}
|
|
||||||
profitOrder.BuyPrice = "0"
|
profitOrder.BuyPrice = "0"
|
||||||
profitOrder.Site = side
|
profitOrder.Site = side
|
||||||
|
|
||||||
@ -1007,7 +1114,7 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO
|
|||||||
lossOrder.Pid = preOrder.Id
|
lossOrder.Pid = preOrder.Id
|
||||||
lossOrder.OrderType = 2
|
lossOrder.OrderType = 2
|
||||||
lossOrder.Status = 0
|
lossOrder.Status = 0
|
||||||
lossOrder.MainId = preOrder.MainId
|
lossOrder.MainId = mainId
|
||||||
lossOrder.BuyPrice = "0"
|
lossOrder.BuyPrice = "0"
|
||||||
lossOrder.Num = ext.TotalAfter.Truncate(int32(tradeSet.AmountDigit)).String()
|
lossOrder.Num = ext.TotalAfter.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
lossOrder.Rate = ext.StopLossRatio.Truncate(2).String()
|
lossOrder.Rate = ext.StopLossRatio.Truncate(2).String()
|
||||||
@ -1134,31 +1241,6 @@ 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)
|
||||||
@ -1185,14 +1267,25 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
|
|||||||
var symbolGroupInfo models.LineSymbolGroup
|
var symbolGroupInfo models.LineSymbolGroup
|
||||||
e.Orm.Model(&models.LineSymbolGroup{}).Where("id = ?", utility.StringToInt(batchReq.SymbolGroupId)).Find(&symbolGroupInfo)
|
e.Orm.Model(&models.LineSymbolGroup{}).Where("id = ?", utility.StringToInt(batchReq.SymbolGroupId)).Find(&symbolGroupInfo)
|
||||||
if symbolGroupInfo.Id <= 0 || symbolGroupInfo.Symbol == "" {
|
if symbolGroupInfo.Id <= 0 || symbolGroupInfo.Symbol == "" {
|
||||||
*errs = append(*errs, errors.New(fmt.Sprintf("选择的交易对组:%s不存在或交易对组的交易对为空", batchReq.SymbolGroupId)))
|
*errs = append(*errs, fmt.Errorf("选择的交易对组:%s不存在或交易对组的交易对为空", batchReq.SymbolGroupId))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if batchReq.StrategyTemplateType == 1 && batchReq.StrategyTemplateId > 0 {
|
||||||
|
cachePriceSymbols, _ := helper.DefaultRedis.GetAllList(rediskey.CacheSymbolLastPrice)
|
||||||
|
symbols := strings.Split(symbolGroupInfo.Symbol, ",")
|
||||||
|
|
||||||
|
for _, symbol := range symbols {
|
||||||
|
if !utility.ContainsStr(cachePriceSymbols, symbol) {
|
||||||
|
*errs = append(*errs, fmt.Errorf("交易对[%s]涨跌幅缓存不存在", symbol))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
batchReq.Symbol = symbolGroupInfo.Symbol
|
batchReq.Symbol = symbolGroupInfo.Symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
//脚本次数
|
//脚本次数
|
||||||
// if batchReq.OrderNum > 0 {
|
|
||||||
apiUserIds := strings.Split(batchReq.ApiUserId, ",")
|
apiUserIds := strings.Split(batchReq.ApiUserId, ",")
|
||||||
var tickerSymbol string
|
var tickerSymbol string
|
||||||
if batchReq.SymbolType == global.SYMBOL_SPOT {
|
if batchReq.SymbolType == global.SYMBOL_SPOT {
|
||||||
@ -1217,7 +1310,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
|
|||||||
log.ScriptParams = string(marshal)
|
log.ScriptParams = string(marshal)
|
||||||
log.AdminId = 0
|
log.AdminId = 0
|
||||||
log.Status = "0"
|
log.Status = "0"
|
||||||
//scriptLogs = append(scriptLogs, log)
|
|
||||||
err := e.Orm.Model(&models.LinePreScript{}).Create(&log).Error
|
err := e.Orm.Model(&models.LinePreScript{}).Create(&log).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errs = append(*errs, fmt.Errorf("记录脚本失败:%+v", err.Error()))
|
*errs = append(*errs, fmt.Errorf("记录脚本失败:%+v", err.Error()))
|
||||||
@ -1257,6 +1350,8 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
|
|||||||
req.ReduceStopLossRatio = batchReq.ReduceStopLossRatio
|
req.ReduceStopLossRatio = batchReq.ReduceStopLossRatio
|
||||||
req.ReduceTakeProfitRatio = batchReq.ReduceTakeProfitRatio
|
req.ReduceTakeProfitRatio = batchReq.ReduceTakeProfitRatio
|
||||||
req.CreateBy = batchReq.CreateBy
|
req.CreateBy = batchReq.CreateBy
|
||||||
|
req.StrategyTemplateId = batchReq.StrategyTemplateId
|
||||||
|
req.StrategyTemplateType = batchReq.StrategyTemplateType
|
||||||
|
|
||||||
e.AddPreOrderCheck(&req, p, errs, tickerSymbol)
|
e.AddPreOrderCheck(&req, p, errs, tickerSymbol)
|
||||||
}
|
}
|
||||||
@ -1551,6 +1646,12 @@ func (e *LinePreOrder) ClearAll() error {
|
|||||||
"_PreFutOrderList_",
|
"_PreFutOrderList_",
|
||||||
"spot_reduce_list",
|
"spot_reduce_list",
|
||||||
"futures_reduce_list",
|
"futures_reduce_list",
|
||||||
|
"spot_reduce_strategy_list",
|
||||||
|
"fut_reduce_strategy_list",
|
||||||
|
"future_position",
|
||||||
|
"spot_position",
|
||||||
|
"strategy_spot_order_list",
|
||||||
|
"strategy_fut_order_list",
|
||||||
}
|
}
|
||||||
err = helper.DefaultRedis.DeleteKeysByPrefix(prefixs...)
|
err = helper.DefaultRedis.DeleteKeysByPrefix(prefixs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1558,9 +1659,10 @@ func (e *LinePreOrder) ClearAll() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order") //订单表
|
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order") //订单表
|
||||||
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_status") //订单拓展状态
|
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_status") //订单拓展状态
|
||||||
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_ext") //订单拓展配置
|
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_ext") //订单拓展配置
|
||||||
|
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_order_reduce_strategy") //订单减仓策略配置
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1929,6 +2031,8 @@ func (e *LinePreOrder) ClearUnTriggered() error {
|
|||||||
var orderLists []models.LinePreOrder
|
var orderLists []models.LinePreOrder
|
||||||
positions := map[string]positiondto.LinePreOrderPositioinDelReq{}
|
positions := map[string]positiondto.LinePreOrderPositioinDelReq{}
|
||||||
e.Orm.Model(&models.LinePreOrder{}).Where("main_id = 0 AND pid = 0 AND status = '0'").Find(&orderLists).Unscoped().Delete(&models.LinePreOrder{})
|
e.Orm.Model(&models.LinePreOrder{}).Where("main_id = 0 AND pid = 0 AND status = '0'").Find(&orderLists).Unscoped().Delete(&models.LinePreOrder{})
|
||||||
|
spotStrategyMap := e.GetStrategyOrderListMap(1)
|
||||||
|
futStrategyMap := e.GetStrategyOrderListMap(2)
|
||||||
|
|
||||||
for _, order := range orderLists {
|
for _, order := range orderLists {
|
||||||
redisList := dto.PreOrderRedisList{
|
redisList := dto.PreOrderRedisList{
|
||||||
@ -1940,17 +2044,35 @@ func (e *LinePreOrder) ClearUnTriggered() error {
|
|||||||
OrderSn: order.OrderSn,
|
OrderSn: order.OrderSn,
|
||||||
QuoteSymbol: order.QuoteSymbol,
|
QuoteSymbol: order.QuoteSymbol,
|
||||||
}
|
}
|
||||||
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol))
|
|
||||||
|
var tradedSetKey string
|
||||||
|
if order.SymbolType == 1 {
|
||||||
|
tradedSetKey = fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol)
|
||||||
|
} else {
|
||||||
|
tradedSetKey = fmt.Sprintf(global.TICKER_FUTURES, order.ExchangeType, order.Symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, tradedSetKey)
|
||||||
redisList.Price = utility.StringToDecimal(redisList.Price).Truncate(int32(tradeSet.PriceDigit)).String()
|
redisList.Price = utility.StringToDecimal(redisList.Price).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||||
marshal, _ := sonic.Marshal(redisList)
|
marshal, _ := sonic.Marshal(redisList)
|
||||||
|
|
||||||
if order.SymbolType == 1 {
|
if order.SymbolType == 1 {
|
||||||
key := fmt.Sprintf(rediskey.PreFutOrderList, order.ExchangeType)
|
key := fmt.Sprintf(rediskey.PreFutOrderList, order.ExchangeType)
|
||||||
|
|
||||||
helper.DefaultRedis.LRem(key, string(marshal))
|
helper.DefaultRedis.LRem(key, string(marshal))
|
||||||
} else {
|
} else {
|
||||||
key := fmt.Sprintf(rediskey.PreSpotOrderList, order.ExchangeType)
|
key := fmt.Sprintf(rediskey.PreSpotOrderList, order.ExchangeType)
|
||||||
|
|
||||||
helper.DefaultRedis.LRem(key, string(marshal))
|
helper.DefaultRedis.LRem(key, string(marshal))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case order.StrategyTemplateType == 1 && order.SymbolType == 1:
|
||||||
|
e.RemoveStrategyOrderCache(order.Id, order.SymbolType, order.ExchangeType, &spotStrategyMap)
|
||||||
|
case order.StrategyTemplateType == 1 && order.SymbolType == 2:
|
||||||
|
e.RemoveStrategyOrderCache(order.Id, order.SymbolType, order.ExchangeType, &futStrategyMap)
|
||||||
|
}
|
||||||
|
|
||||||
//会影响持仓的
|
//会影响持仓的
|
||||||
removeSymbolKey := fmt.Sprintf("%v_%s_%s_%s_%v", order.ApiId, order.ExchangeType, order.Symbol, order.Site, order.SymbolType)
|
removeSymbolKey := fmt.Sprintf("%v_%s_%s_%s_%v", order.ApiId, order.ExchangeType, order.Symbol, order.Site, order.SymbolType)
|
||||||
|
|
||||||
@ -1990,6 +2112,60 @@ func (e *LinePreOrder) ClearUnTriggered() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 移除待策略待触发单
|
||||||
|
func (e *LinePreOrder) RemoveStrategyOrderCache(orderId int, symbolType int, exchangeType string, caches *map[string][]dto.StrategyOrderRedisList) {
|
||||||
|
strategys, _ := (*caches)[exchangeType]
|
||||||
|
var strategyListKey string
|
||||||
|
|
||||||
|
if symbolType == 1 {
|
||||||
|
strategyListKey = fmt.Sprintf(rediskey.StrategySpotOrderList, exchangeType)
|
||||||
|
} else {
|
||||||
|
strategyListKey = fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, strategy := range strategys {
|
||||||
|
if strategy.Id == orderId {
|
||||||
|
strategyVal, _ := sonic.MarshalString(strategy)
|
||||||
|
helper.DefaultRedis.LRem(strategyListKey, strategyVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取策略订单缓存列表
|
||||||
|
// symbolType 1现货 2合约
|
||||||
|
func (e *LinePreOrder) GetStrategyOrderListMap(symbolType int) map[string][]dto.StrategyOrderRedisList {
|
||||||
|
result := make(map[string][]dto.StrategyOrderRedisList)
|
||||||
|
var key string
|
||||||
|
exchanges := []string{global.EXCHANGE_BINANCE}
|
||||||
|
|
||||||
|
if symbolType == 1 {
|
||||||
|
key = rediskey.StrategySpotOrderList
|
||||||
|
} else {
|
||||||
|
key = rediskey.StrategyFutOrderList
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, exchange := range exchanges {
|
||||||
|
newKey := fmt.Sprintf(key, exchange)
|
||||||
|
vals, _ := helper.DefaultRedis.GetAllList(newKey)
|
||||||
|
itemData := make([]dto.StrategyOrderRedisList, 0)
|
||||||
|
item := dto.StrategyOrderRedisList{}
|
||||||
|
|
||||||
|
for _, v := range vals {
|
||||||
|
sonic.Unmarshal([]byte(v), &item)
|
||||||
|
|
||||||
|
if item.Id > 0 {
|
||||||
|
itemData = append(itemData, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(itemData) > 0 {
|
||||||
|
result[exchange] = itemData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (e *LinePreOrder) QueryOrder(req *dto.QueryOrderReq) (res interface{}, err error) {
|
func (e *LinePreOrder) QueryOrder(req *dto.QueryOrderReq) (res interface{}, err error) {
|
||||||
var apiUserInfo models.LineApiUser
|
var apiUserInfo models.LineApiUser
|
||||||
e.Orm.Model(&models.LineApiUser{}).Where("id = ?", req.ApiId).Find(&apiUserInfo)
|
e.Orm.Model(&models.LineApiUser{}).Where("id = ?", req.ApiId).Find(&apiUserInfo)
|
||||||
@ -2042,9 +2218,9 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error {
|
|||||||
var tickerPrice decimal.Decimal
|
var tickerPrice decimal.Decimal
|
||||||
|
|
||||||
if req.SymbolType == 1 {
|
if req.SymbolType == 1 {
|
||||||
tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 0)
|
tradeSet, _ = cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, req.Symbol, 0)
|
||||||
} else {
|
} else {
|
||||||
tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 1)
|
tradeSet, _ = cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, req.Symbol, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tradeSet.LastPrice == "" {
|
if tradeSet.LastPrice == "" {
|
||||||
@ -2083,15 +2259,18 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error {
|
|||||||
AddPositionVal: req.ReduceNumRatio,
|
AddPositionVal: req.ReduceNumRatio,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.PricePattern == "mixture" {
|
||||||
|
mainParam.LossEndPercent = price.Div(req.ReducePriceRatio).Sub(decimal.NewFromInt(1)).Abs().Mul(decimal.NewFromInt(100)).Truncate(2)
|
||||||
|
}
|
||||||
|
|
||||||
//计算减仓后
|
//计算减仓后
|
||||||
mainParam.LossEndPercent = req.ReducePriceRatio
|
|
||||||
mainParam.RemainingQuantity = mainAmount
|
mainParam.RemainingQuantity = mainAmount
|
||||||
mainParam.AddType = 2
|
mainParam.AddType = 2
|
||||||
e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet)
|
e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet)
|
||||||
mainParam.RemainingQuantity = calculateResp.RemainingQuantity
|
mainParam.RemainingQuantity = calculateResp.RemainingQuantity
|
||||||
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU
|
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU
|
||||||
req.ReduceReTakeProfitRatio = calculateResp.Ratio
|
req.ReduceReTakeProfitRatio = calculateResp.Ratio
|
||||||
lossBeginPercent = req.ReducePriceRatio
|
lossBeginPercent = mainParam.LossEndPercent
|
||||||
|
|
||||||
//顺序排序
|
//顺序排序
|
||||||
sort.Slice(req.Ext, func(i, j int) bool {
|
sort.Slice(req.Ext, func(i, j int) bool {
|
||||||
@ -2161,164 +2340,3 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 手动加仓
|
|
||||||
// func (e *LinePreOrder) AddPosition(req *dto.LinePreOrderAddPositionReq) error {
|
|
||||||
// lastPositionOrder := models.LinePreOrder{}
|
|
||||||
// var tradeSet models2.TradeSet
|
|
||||||
|
|
||||||
// if req.OrderType == 1 {
|
|
||||||
// tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 0)
|
|
||||||
// } else if req.OrderType == 2 {
|
|
||||||
// tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 1)
|
|
||||||
// } else {
|
|
||||||
// return fmt.Errorf("交易对:%s 订单类型错误", req.Symbol)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if tradeSet.LastPrice == "" {
|
|
||||||
// return fmt.Errorf("交易对:%s 交易对配置错误", req.Symbol)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if err := e.Orm.Model(&lastPositionOrder).Where("symbol =? AND status = 6 AND site =? AND api_id =? AND symbol_type =? AND exchange_type=?",
|
|
||||||
// req.Symbol, req.Site, req.ApiUserId, req.OrderType, req.ExchangeType).Error; err != nil {
|
|
||||||
// logger.Errorf("交易对:%s查询已开仓订单失败", req.Symbol)
|
|
||||||
// return fmt.Errorf("交易对:%s 没有已开仓的订单", req.Symbol)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ext := models.LinePreOrderExt{
|
|
||||||
// MainOrderId: lastPositionOrder.Id,
|
|
||||||
// TakeProfitRatio: req.Profit,
|
|
||||||
// ReducePriceRatio: req.ReducePriceRatio,
|
|
||||||
// ReduceNumRatio: req.ReduceNumRatio,
|
|
||||||
// ReduceTakeProfitRatio: req.ReduceTakeProfitRatio,
|
|
||||||
// ReduceStopLossRatio: req.ReduceStopLossRatio,
|
|
||||||
// AddPositionOrderType: req.AddPositionOrderType,
|
|
||||||
// AddPositionType: 2,
|
|
||||||
// AddPositionVal: req.BuyPrice,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// addPosition := models.LinePreOrder{
|
|
||||||
// SignPrice: tradeSet.LastPrice,
|
|
||||||
// Pid: lastPositionOrder.Id,
|
|
||||||
// MainId: lastPositionOrder.Id,
|
|
||||||
// Symbol: req.Symbol,
|
|
||||||
// QuoteSymbol: tradeSet.Currency,
|
|
||||||
// SignPriceU: utility.StrToDecimal(tradeSet.LastPrice),
|
|
||||||
// ApiId: req.ApiUserId,
|
|
||||||
// Site: req.Site,
|
|
||||||
// ExchangeType: req.ExchangeType,
|
|
||||||
// OrderType: 0,
|
|
||||||
// OrderCategory: 3,
|
|
||||||
// BuyPrice: req.BuyPrice.String(),
|
|
||||||
// Status: 0,
|
|
||||||
// SymbolType: req.OrderType,
|
|
||||||
// MainOrderType: req.AddPositionOrderType,
|
|
||||||
// ExpireTime: time.Now().Add(4),
|
|
||||||
// OrderSn: utility.Int64ToString(snowflakehelper.GetOrderId()),
|
|
||||||
// }
|
|
||||||
|
|
||||||
// tickerPrice := utility.StrToDecimal(tradeSet.LastPrice)
|
|
||||||
// if req.PricePattern == "percentage" {
|
|
||||||
// addPosition.Rate = req.Price.String()
|
|
||||||
// priceRate := req.Price.Div(decimal.NewFromInt(100)) //下单价除100 =0.1
|
|
||||||
|
|
||||||
// if strings.ToUpper(req.Site) == "BUY" { //购买方向
|
|
||||||
// //实际下单价格
|
|
||||||
// truncate := tickerPrice.Mul(decimal.NewFromInt(1).Sub(priceRate)).Truncate(int32(tradeSet.PriceDigit))
|
|
||||||
// addPosition.Price = truncate.String()
|
|
||||||
// } else {
|
|
||||||
// truncate := tickerPrice.Mul(decimal.NewFromInt(1).Add(priceRate)).Truncate(int32(tradeSet.PriceDigit))
|
|
||||||
// addPosition.Price = truncate.String()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// } else { //实际价格下单
|
|
||||||
// addPosition.Price = req.Price.Truncate(int32(tradeSet.PriceDigit)).String()
|
|
||||||
// addPosition.SignPriceType = req.PricePattern
|
|
||||||
// addPosition.Rate = "0"
|
|
||||||
// }
|
|
||||||
// if tradeSet.Currency != "USDT" { //不是U本位
|
|
||||||
// //获取币本位兑换u的价格
|
|
||||||
// ticker2 := models2.TradeSet{}
|
|
||||||
// tickerVal, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.TICKER_SPOT, req.ExchangeType, strings.ToUpper(tradeSet.Coin+"USDT")))
|
|
||||||
|
|
||||||
// if tickerVal == "" {
|
|
||||||
// logger.Error("查询行情失败")
|
|
||||||
// return fmt.Errorf("交易对:%s 获取u本位行情失败", req.Symbol)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err := sonic.Unmarshal([]byte(tickerVal), &ticker2)
|
|
||||||
|
|
||||||
// if ticker2.LastPrice == "" {
|
|
||||||
// logger.Errorf("查询行情失败 %s err:%v", strings.ToUpper(tradeSet.Coin+"USDT"), err)
|
|
||||||
// return fmt.Errorf("交易对:%s 获取u本位行情 反序列化失败", req.Symbol)
|
|
||||||
// }
|
|
||||||
// //LTCBTC --> LTCUSDT
|
|
||||||
// uTickerPrice := utility.StrToDecimal(ticker2.LastPrice) //94069
|
|
||||||
// //换算成U
|
|
||||||
// //div := decimal.NewFromInt(1).Div(uTickerPrice) //0.0000106365
|
|
||||||
// //在换算成对应交易对对应的价值
|
|
||||||
// //LTCBTC --> LTCUSDT == LTCUSDT -- 100.502
|
|
||||||
// div := tickerPrice.Div(decimal.NewFromInt(1).Div(uTickerPrice))
|
|
||||||
// //计算下单数量
|
|
||||||
// addPosition.Num = req.BuyPrice.Div(div).Truncate(int32(tradeSet.AmountDigit)).String()
|
|
||||||
// } else {
|
|
||||||
// fromString, _ := decimal.NewFromString(addPosition.Price)
|
|
||||||
// addPosition.Num = req.BuyPrice.Div(fromString).Truncate(int32(tradeSet.AmountDigit)).String()
|
|
||||||
// }
|
|
||||||
// //事务保存
|
|
||||||
// err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
|
||||||
// //添加加仓单
|
|
||||||
// if err := tx.Create(&addPosition).Error; err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// //止盈、减仓
|
|
||||||
// orders, err := makeFuturesTakeAndReduce(&addPosition, ext, tradeSet)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// logger.Error("构造加仓单止盈、减仓失败")
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if err := e.Orm.Create(&orders).Error; err != nil {
|
|
||||||
// logger.Error("保存加仓单止盈、减仓失败")
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// //处理减仓单
|
|
||||||
// for index := range orders {
|
|
||||||
// //减仓单且 减仓比例大于0 小于100 就冲下止盈止损
|
|
||||||
// if orders[index].OrderType == 4 && ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 && ext.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) < 0 {
|
|
||||||
// reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), ext, tradeSet)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// logger.Error("生产加仓单止盈、减仓失败")
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if len(reduceChildOrders) == 0 {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if err := e.Orm.Create(&reduceChildOrders).Error; err != nil {
|
|
||||||
// logger.Error("报错减仓后止盈止损失败")
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ext.OrderId = addPosition.Id
|
|
||||||
// if err := tx.Create(&ext).Error; err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
// })
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// logger.Errorf("交易对:%s 添加加仓订单失败", req.Symbol)
|
|
||||||
// return fmt.Errorf("交易对:%s 添加加仓订单失败", req.Symbol)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|||||||
1
app/admin/service/line_pre_order_strategy.go
Normal file
1
app/admin/service/line_pre_order_strategy.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package service
|
||||||
178
app/admin/service/line_reduce_strategy.go
Normal file
178
app/admin/service/line_reduce_strategy.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"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"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineReduceStrategy struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取LineReduceStrategy列表
|
||||||
|
func (e *LineReduceStrategy) GetPage(c *dto.LineReduceStrategyGetPageReq, p *actions.DataPermission, list *[]models.LineReduceStrategy, count *int64) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineReduceStrategy
|
||||||
|
|
||||||
|
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("LineReduceStrategyService GetPage error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取LineReduceStrategy对象
|
||||||
|
func (e *LineReduceStrategy) Get(d *dto.LineReduceStrategyGetReq, p *actions.DataPermission, model *models.LineReduceStrategy) error {
|
||||||
|
var data models.LineReduceStrategy
|
||||||
|
|
||||||
|
err := e.Orm.Model(&data).
|
||||||
|
Preload("Items").
|
||||||
|
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 GetLineReduceStrategy error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据id获取对象
|
||||||
|
func (e *LineReduceStrategy) GetById(id int) (models.LineReduceStrategy, error) {
|
||||||
|
result := models.LineReduceStrategy{}
|
||||||
|
key := fmt.Sprintf(rediskey.ReduceStrategy, id)
|
||||||
|
str, _ := helper.DefaultRedis.GetString(key)
|
||||||
|
|
||||||
|
if str != "" {
|
||||||
|
sonic.Unmarshal([]byte(str), &result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Id == 0 {
|
||||||
|
if err := e.Orm.Model(&models.LineReduceStrategy{}).First(&result, id).Error; err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建LineReduceStrategy对象
|
||||||
|
func (e *LineReduceStrategy) Insert(c *dto.LineReduceStrategyInsertReq) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineReduceStrategy
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
e.Orm.Model(&models.LineReduceStrategy{}).Where("name = ?", c.Name).Count(&count)
|
||||||
|
if count > 0 {
|
||||||
|
err = errors.New("策略名称重复")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Generate(&data)
|
||||||
|
err = e.Orm.Create(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("LineReduceStrategyService Insert error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.saveCache(data)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改LineReduceStrategy对象
|
||||||
|
func (e *LineReduceStrategy) Update(c *dto.LineReduceStrategyUpdateReq, p *actions.DataPermission) error {
|
||||||
|
var err error
|
||||||
|
var data = models.LineReduceStrategy{}
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
e.Orm.Model(&models.LineReduceStrategy{}).Where("name = ? AND id !=?", c.Name, c.GetId()).Count(&count)
|
||||||
|
if count > 0 {
|
||||||
|
err = errors.New("策略名称重复")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Orm.Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).First(&data, c.GetId())
|
||||||
|
c.Generate(&data)
|
||||||
|
|
||||||
|
err = e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if errr := tx.Delete(&models.LineReduceStrategyItem{}, "reduce_strategy_id =?", c.GetId()).Error; errr != nil {
|
||||||
|
return errr
|
||||||
|
}
|
||||||
|
|
||||||
|
db := tx.Save(&data)
|
||||||
|
if err = db.Error; err != nil {
|
||||||
|
e.Log.Errorf("LineReduceStrategyService Save error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
e.saveCache(data)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineReduceStrategy) saveCache(data models.LineReduceStrategy) {
|
||||||
|
str, _ := sonic.MarshalString(data)
|
||||||
|
|
||||||
|
if str != "" {
|
||||||
|
key := fmt.Sprintf(rediskey.ReduceStrategy, data.Id)
|
||||||
|
|
||||||
|
if errr := helper.DefaultRedis.SetString(key, str); errr != nil {
|
||||||
|
e.Log.Errorf("LineReduceStrategyService SetString error:%s \r\n", errr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove 删除LineReduceStrategy
|
||||||
|
func (e *LineReduceStrategy) Remove(d *dto.LineReduceStrategyDeleteReq, p *actions.DataPermission) error {
|
||||||
|
var data models.LineReduceStrategy
|
||||||
|
|
||||||
|
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 RemoveLineReduceStrategy error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权删除该数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
key := fmt.Sprintf(rediskey.ReduceStrategy, data.Id)
|
||||||
|
helper.DefaultRedis.DeleteString(key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
109
app/admin/service/line_reduce_strategy_item.go
Normal file
109
app/admin/service/line_reduce_strategy_item.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
cDto "go-admin/common/dto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineReduceStrategyItem struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取LineReduceStrategyItem列表
|
||||||
|
func (e *LineReduceStrategyItem) GetPage(c *dto.LineReduceStrategyItemGetPageReq, p *actions.DataPermission, list *[]models.LineReduceStrategyItem, count *int64) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineReduceStrategyItem
|
||||||
|
|
||||||
|
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("LineReduceStrategyItemService GetPage error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取LineReduceStrategyItem对象
|
||||||
|
func (e *LineReduceStrategyItem) Get(d *dto.LineReduceStrategyItemGetReq, p *actions.DataPermission, model *models.LineReduceStrategyItem) error {
|
||||||
|
var data models.LineReduceStrategyItem
|
||||||
|
|
||||||
|
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 GetLineReduceStrategyItem error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建LineReduceStrategyItem对象
|
||||||
|
func (e *LineReduceStrategyItem) Insert(c *dto.LineReduceStrategyItemInsertReq) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineReduceStrategyItem
|
||||||
|
c.Generate(&data)
|
||||||
|
err = e.Orm.Create(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("LineReduceStrategyItemService Insert error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改LineReduceStrategyItem对象
|
||||||
|
func (e *LineReduceStrategyItem) Update(c *dto.LineReduceStrategyItemUpdateReq, p *actions.DataPermission) error {
|
||||||
|
var err error
|
||||||
|
var data = models.LineReduceStrategyItem{}
|
||||||
|
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("LineReduceStrategyItemService Save error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove 删除LineReduceStrategyItem
|
||||||
|
func (e *LineReduceStrategyItem) Remove(d *dto.LineReduceStrategyItemDeleteReq, p *actions.DataPermission) error {
|
||||||
|
var data models.LineReduceStrategyItem
|
||||||
|
|
||||||
|
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 RemoveLineReduceStrategyItem error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权删除该数据")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
109
app/admin/service/line_strategy_template.go
Normal file
109
app/admin/service/line_strategy_template.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
cDto "go-admin/common/dto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineStrategyTemplate struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取LineStrategyTemplate列表
|
||||||
|
func (e *LineStrategyTemplate) GetPage(c *dto.LineStrategyTemplateGetPageReq, p *actions.DataPermission, list *[]models.LineStrategyTemplate, count *int64) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineStrategyTemplate
|
||||||
|
|
||||||
|
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("LineStrategyTemplateService GetPage error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取LineStrategyTemplate对象
|
||||||
|
func (e *LineStrategyTemplate) Get(d *dto.LineStrategyTemplateGetReq, p *actions.DataPermission, model *models.LineStrategyTemplate) error {
|
||||||
|
var data models.LineStrategyTemplate
|
||||||
|
|
||||||
|
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 GetLineStrategyTemplate error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建LineStrategyTemplate对象
|
||||||
|
func (e *LineStrategyTemplate) Insert(c *dto.LineStrategyTemplateInsertReq) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineStrategyTemplate
|
||||||
|
c.Generate(&data)
|
||||||
|
err = e.Orm.Create(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("LineStrategyTemplateService Insert error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改LineStrategyTemplate对象
|
||||||
|
func (e *LineStrategyTemplate) Update(c *dto.LineStrategyTemplateUpdateReq, p *actions.DataPermission) error {
|
||||||
|
var err error
|
||||||
|
var data = models.LineStrategyTemplate{}
|
||||||
|
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("LineStrategyTemplateService Save error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove 删除LineStrategyTemplate
|
||||||
|
func (e *LineStrategyTemplate) Remove(d *dto.LineStrategyTemplateDeleteReq, p *actions.DataPermission) error {
|
||||||
|
var data models.LineStrategyTemplate
|
||||||
|
|
||||||
|
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 RemoveLineStrategyTemplate error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权删除该数据")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
147
app/admin/service/line_symbol_price.go
Normal file
147
app/admin/service/line_symbol_price.go
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineSymbolPrice struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取LineSymbolPrice列表
|
||||||
|
func (e *LineSymbolPrice) GetPage(c *dto.LineSymbolPriceGetPageReq, p *actions.DataPermission, list *[]models.LineSymbolPrice, count *int64) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineSymbolPrice
|
||||||
|
|
||||||
|
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("LineSymbolPriceService GetPage error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取LineSymbolPrice对象
|
||||||
|
func (e *LineSymbolPrice) Get(d *dto.LineSymbolPriceGetReq, p *actions.DataPermission, model *models.LineSymbolPrice) error {
|
||||||
|
var data models.LineSymbolPrice
|
||||||
|
|
||||||
|
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 GetLineSymbolPrice error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建LineSymbolPrice对象
|
||||||
|
func (e *LineSymbolPrice) Insert(c *dto.LineSymbolPriceInsertReq) error {
|
||||||
|
var err error
|
||||||
|
var data models.LineSymbolPrice
|
||||||
|
c.Generate(&data)
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
e.Orm.Model(&models.LineSymbolPrice{}).Where("symbol = ?", c.Symbol).Count(&count)
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
return errors.New("交易对已存在,请不要重复添加")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.Orm.Create(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("LineSymbolPriceService Insert error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.cacheList()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineSymbolPrice) cacheList() {
|
||||||
|
symbols := make([]string, 0)
|
||||||
|
if err := e.Orm.Model(&models.LineSymbolPrice{}).Where("status =1").Pluck("symbol", &symbols).Error; err != nil {
|
||||||
|
e.Log.Errorf("获取可用交易对失败,err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(symbols) > 0 {
|
||||||
|
if err := helper.DefaultRedis.SetListCache(rediskey.CacheSymbolLastPrice, 0, symbols...); err != nil {
|
||||||
|
e.Log.Errorf("设置可缓存价格交易对失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改LineSymbolPrice对象
|
||||||
|
func (e *LineSymbolPrice) Update(c *dto.LineSymbolPriceUpdateReq, p *actions.DataPermission) error {
|
||||||
|
var err error
|
||||||
|
var data = models.LineSymbolPrice{}
|
||||||
|
var count int64
|
||||||
|
e.Orm.Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).First(&data, c.GetId())
|
||||||
|
c.Generate(&data)
|
||||||
|
|
||||||
|
e.Orm.Model(&models.LineSymbolPrice{}).Where("symbol = ? and id !=?", c.Symbol, c.GetId()).Count(&count)
|
||||||
|
if count > 0 {
|
||||||
|
return errors.New("交易对已存在,请不要重复添加")
|
||||||
|
}
|
||||||
|
|
||||||
|
db := e.Orm.Save(&data)
|
||||||
|
if err = db.Error; err != nil {
|
||||||
|
e.Log.Errorf("LineSymbolPriceService Save error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
e.cacheList()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove 删除LineSymbolPrice
|
||||||
|
func (e *LineSymbolPrice) Remove(d *dto.LineSymbolPriceDeleteReq, p *actions.DataPermission) error {
|
||||||
|
var data models.LineSymbolPrice
|
||||||
|
|
||||||
|
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 RemoveLineSymbolPrice error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权删除该数据")
|
||||||
|
}
|
||||||
|
e.cacheList()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LineSymbolPrice) InitCache() {
|
||||||
|
e.cacheList()
|
||||||
|
}
|
||||||
67
app/jobs/account_job.go
Normal file
67
app/jobs/account_job.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
binancedto "go-admin/models/binancedto"
|
||||||
|
"go-admin/services/binanceservice"
|
||||||
|
|
||||||
|
DbModels "go-admin/app/admin/models"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BinanceSpotAccountJob struct{}
|
||||||
|
|
||||||
|
type BinanceFuturesAccountJob struct{}
|
||||||
|
|
||||||
|
// 币安账户划转
|
||||||
|
func (t BinanceSpotAccountJob) Exec(arg interface{}) error {
|
||||||
|
db := getDefaultDb()
|
||||||
|
req := binancedto.BinanceTransfer{
|
||||||
|
Type: "MAIN_UMFUTURE",
|
||||||
|
Asset: "USDT",
|
||||||
|
Amount: decimal.NewFromFloat(0.1),
|
||||||
|
FromSymbol: "USDT",
|
||||||
|
ToSymbol: "USDT",
|
||||||
|
}
|
||||||
|
var apis []DbModels.LineApiUser
|
||||||
|
|
||||||
|
if err := db.Model(&DbModels.LineApiUser{}).Where("open_status = 1").Find(&apis).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, apiUserInfo := range apis {
|
||||||
|
err := binanceservice.TradeAmount(db, &req, apiUserInfo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("现货划转合约失败, err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 币安账户划转
|
||||||
|
func (t BinanceFuturesAccountJob) Exec(arg interface{}) error {
|
||||||
|
db := getDefaultDb()
|
||||||
|
req := binancedto.BinanceTransfer{
|
||||||
|
Type: "UMFUTURE_MAIN",
|
||||||
|
Asset: "USDT",
|
||||||
|
Amount: decimal.NewFromFloat(0.1),
|
||||||
|
FromSymbol: "USDT",
|
||||||
|
ToSymbol: "USDT",
|
||||||
|
}
|
||||||
|
var apis []DbModels.LineApiUser
|
||||||
|
if err := db.Model(&DbModels.LineApiUser{}).Where("open_status = 1").Find(&apis).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, apiUserInfo := range apis {
|
||||||
|
err := binanceservice.TradeAmount(db, &req, apiUserInfo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("合约划转现货失败, err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
34
app/jobs/account_job_test.go
Normal file
34
app/jobs/account_job_test.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/helper"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccountJob(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
sdk.Runtime.SetDb("default", db)
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "2")
|
||||||
|
|
||||||
|
accountJob := BinanceSpotAccountJob{}
|
||||||
|
accountJob.Exec(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFutureAccountJob(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
sdk.Runtime.SetDb("default", db)
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "2")
|
||||||
|
|
||||||
|
accountJob := BinanceFuturesAccountJob{}
|
||||||
|
accountJob.Exec(nil)
|
||||||
|
}
|
||||||
@ -38,6 +38,9 @@ func InitJob() {
|
|||||||
"MemberExpirationJob": MemberExpirationJob{}, //会员到期处理
|
"MemberExpirationJob": MemberExpirationJob{}, //会员到期处理
|
||||||
"MemberRenwalOrderExpirationJob": MemberRenwalOrderExpirationJob{}, //会员续费订单过期处理
|
"MemberRenwalOrderExpirationJob": MemberRenwalOrderExpirationJob{}, //会员续费订单过期处理
|
||||||
"TrxQueryJobs": TrxQueryJobs{}, //订单支付监听
|
"TrxQueryJobs": TrxQueryJobs{}, //订单支付监听
|
||||||
|
"StrategyJob": StrategyJob{}, //下单策略触发
|
||||||
|
"BinanceSpotAccountJob": BinanceSpotAccountJob{}, //币安现货划转
|
||||||
|
"BinanceFuturesAccountJob": BinanceFuturesAccountJob{}, //币安合约划转
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package jobs
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
models2 "go-admin/app/jobs/models"
|
models2 "go-admin/app/jobs/models"
|
||||||
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/go-admin-team/go-admin-core/logger"
|
log "github.com/go-admin-team/go-admin-core/logger"
|
||||||
@ -43,7 +44,10 @@ type ExecJob struct {
|
|||||||
func (e *ExecJob) Run() {
|
func (e *ExecJob) Run() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
log.Errorf("脚本任务失败:%v", err)
|
// 获取调用栈信息
|
||||||
|
buf := make([]byte, 1<<16) // 64KB 缓冲区
|
||||||
|
n := runtime.Stack(buf, false)
|
||||||
|
log.Errorf("脚本任务失败: %v\n%s", err, buf[:n])
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import (
|
|||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
"go-admin/pkg/utility/snowflakehelper"
|
"go-admin/pkg/utility/snowflakehelper"
|
||||||
"go-admin/services/binanceservice"
|
"go-admin/services/binanceservice"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
"go-admin/services/fileservice"
|
"go-admin/services/fileservice"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -241,7 +242,7 @@ 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)
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 0)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||||
@ -359,7 +360,7 @@ 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)
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||||
|
|||||||
12
app/jobs/order_job.go
Normal file
12
app/jobs/order_job.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
//波段交易策略任务
|
||||||
|
type StrategyOrderJob struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t StrategyOrderJob) Exec(arg interface{}) error {
|
||||||
|
// strategyOrderService:=
|
||||||
|
//todo 策略订单任务
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
25
app/jobs/strategy_job.go
Normal file
25
app/jobs/strategy_job.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/services/binanceservice"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StrategyJob struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 策略下单任务
|
||||||
|
func (j StrategyJob) Exec(arg interface{}) error {
|
||||||
|
strategyService := binanceservice.BinanceStrategyOrderService{}
|
||||||
|
db := getDefaultDb()
|
||||||
|
strategyService.Orm = db
|
||||||
|
strategyService.Log = logger.NewHelper(sdk.Runtime.GetLogger()).WithFields(map[string]interface{}{})
|
||||||
|
|
||||||
|
//触发币安策略下单
|
||||||
|
strategyService.TriggerStrategyOrder(global.EXCHANGE_BINANCE)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
22
app/jobs/strategy_job_test.go
Normal file
22
app/jobs/strategy_job_test.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/helper"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStrategyJob(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
sdk.Runtime.SetDb("default", db)
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "2")
|
||||||
|
|
||||||
|
job := StrategyJob{}
|
||||||
|
|
||||||
|
job.Exec([]string{})
|
||||||
|
}
|
||||||
@ -25,6 +25,11 @@ const (
|
|||||||
PreSpotOrderList = "_PreSpotOrderList_:%s" // 待触发的现货订单集合{交易所类型 exchange_type}
|
PreSpotOrderList = "_PreSpotOrderList_:%s" // 待触发的现货订单集合{交易所类型 exchange_type}
|
||||||
PreFutOrderList = "_PreFutOrderList_:%s" // 待触发的订单集合 {交易所类型 exchange_type}
|
PreFutOrderList = "_PreFutOrderList_:%s" // 待触发的订单集合 {交易所类型 exchange_type}
|
||||||
|
|
||||||
|
//策略现货订单集合 {交易所类型 exchange_type}
|
||||||
|
StrategySpotOrderList = "strategy_spot_order_list:%s"
|
||||||
|
//策略合约订单集合 {交易所类型 exchange_type}
|
||||||
|
StrategyFutOrderList = "strategy_fut_order_list:%s"
|
||||||
|
|
||||||
API_USER = "api_user:%v" // api用户
|
API_USER = "api_user:%v" // api用户
|
||||||
SystemSetting = "system_setting" //系统设置
|
SystemSetting = "system_setting" //系统设置
|
||||||
ApiGroup = "api_group:%v" //api用户组 {id}
|
ApiGroup = "api_group:%v" //api用户组 {id}
|
||||||
@ -41,6 +46,16 @@ const (
|
|||||||
SpotTrigger = "spot_trigger_lock:%v_%s" //现货触发 {apiuserid|symbol}
|
SpotTrigger = "spot_trigger_lock:%v_%s" //现货触发 {apiuserid|symbol}
|
||||||
FutTrigger = "fut_trigger_lock:%v_%s" //合约触发 {apiuserid|symbol}
|
FutTrigger = "fut_trigger_lock:%v_%s" //合约触发 {apiuserid|symbol}
|
||||||
|
|
||||||
|
//波段现货触发{apiuserid|ordersn}
|
||||||
|
StrategySpotTriggerLock = "strategy_spot_trigger_l:%v_%s"
|
||||||
|
//波段合约触发{apiuserid|ordersn}
|
||||||
|
StrategyFutTriggerLock = "strategy_fut_trigger_l:%v_%s"
|
||||||
|
|
||||||
|
//减仓波段合约触发 {apiuserid|symbol}
|
||||||
|
ReduceStrategyFutTriggerLock = "reduce_strategy_fut_trigger_l:%v_%s"
|
||||||
|
//减仓波段现货触发 {apiuserid|symbol}
|
||||||
|
ReduceStrategySpotTriggerLock = "reduce_strategy_spot_trigger_l:%v_%s"
|
||||||
|
|
||||||
SpotCallBack = "spot_callback:%s" //现货回调 {ordersn}
|
SpotCallBack = "spot_callback:%s" //现货回调 {ordersn}
|
||||||
FutCallBack = "fut_callback:%s" //合约回调 {ordersn}
|
FutCallBack = "fut_callback:%s" //合约回调 {ordersn}
|
||||||
|
|
||||||
@ -61,6 +76,11 @@ const (
|
|||||||
SpotPosition = "spot_position:%s:%v:%s_%s"
|
SpotPosition = "spot_position:%s:%v:%s_%s"
|
||||||
//合约持仓 {exchangeType,apiuserid,symbol,side}
|
//合约持仓 {exchangeType,apiuserid,symbol,side}
|
||||||
FuturePosition = "future_position:%s:%v:%s_%s"
|
FuturePosition = "future_position:%s:%v:%s_%s"
|
||||||
|
|
||||||
|
//现货减仓单减仓策略 {exchangeType}
|
||||||
|
SpotOrderReduceStrategyList = "spot_reduce_strategy_list:%s"
|
||||||
|
//合约减仓单减仓策略 {exchangeType}
|
||||||
|
FutOrderReduceStrategyList = "fut_reduce_strategy_list:%s"
|
||||||
//需要清理键值---------END-----------------
|
//需要清理键值---------END-----------------
|
||||||
|
|
||||||
//定时取消限价并下市价锁
|
//定时取消限价并下市价锁
|
||||||
@ -74,6 +94,19 @@ const (
|
|||||||
AveRequestToken = "ave_request_token" // AVE请求token
|
AveRequestToken = "ave_request_token" // AVE请求token
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//现货最后成交价 sort set key:={exchangeType,symbol} content:={utc:price}
|
||||||
|
SpotTickerLastPrice = "spot_ticker_last_price:%s:%s"
|
||||||
|
//合约最后成交价 sort set {exchangeType,symbol} content:={utc:price}
|
||||||
|
FutureTickerLastPrice = "fut_ticker_last_price:%s:%s"
|
||||||
|
|
||||||
|
//允许缓存交易对价格的交易对 list
|
||||||
|
CacheSymbolLastPrice = "cache_symbol_price"
|
||||||
|
|
||||||
|
//减仓策略缓存 {id}
|
||||||
|
ReduceStrategy = "reduce_stragy:%d"
|
||||||
|
)
|
||||||
|
|
||||||
// 用户下单
|
// 用户下单
|
||||||
const (
|
const (
|
||||||
MemberShipPre = "member_ship_pre:%v" //用户开通会员预下单 单价缓存{payable_amount}
|
MemberShipPre = "member_ship_pre:%v" //用户开通会员预下单 单价缓存{payable_amount}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -572,6 +573,33 @@ func (r *RedisHelper) HKeys(key string) ([]string, error) {
|
|||||||
return fields, nil
|
return fields, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RedisHelper) HExists(key, field, value string) (bool, error) {
|
||||||
|
exists, err := r.client.HExists(r.ctx, key, field).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("check existence failed: %v", err)
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
storedValue, err := r.client.HGet(r.ctx, key, field).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("get value failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果值是 JSON,比较前反序列化
|
||||||
|
var storedObj, inputObj interface{}
|
||||||
|
if err := sonic.UnmarshalString(storedValue, &storedObj); err != nil {
|
||||||
|
return false, fmt.Errorf("unmarshal stored value failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := sonic.UnmarshalString(value, &inputObj); err != nil {
|
||||||
|
return false, fmt.Errorf("unmarshal input value failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 比较两个对象(需要根据实际类型调整)
|
||||||
|
return fmt.Sprintf("%v", storedObj) == fmt.Sprintf("%v", inputObj), nil
|
||||||
|
}
|
||||||
|
|
||||||
// DelSet 从集合中删除元素
|
// DelSet 从集合中删除元素
|
||||||
func (r *RedisHelper) DelSet(key string, value string) error {
|
func (r *RedisHelper) DelSet(key string, value string) error {
|
||||||
_, err := r.client.SRem(r.ctx, key, value).Result()
|
_, err := r.client.SRem(r.ctx, key, value).Result()
|
||||||
@ -609,7 +637,7 @@ func (e *RedisHelper) SignelAdd(key string, score float64, member string) error
|
|||||||
_, err := e.client.ZRemRangeByScore(e.ctx, key, scoreStr, scoreStr).Result()
|
_, err := e.client.ZRemRangeByScore(e.ctx, key, scoreStr, scoreStr).Result()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("删除score失败", err.Error())
|
fmt.Printf("删除score失败,err:%s", err.Error())
|
||||||
}
|
}
|
||||||
_, err = e.client.ZAdd(e.ctx, key, &redis.Z{
|
_, err = e.client.ZAdd(e.ctx, key, &redis.Z{
|
||||||
Score: score,
|
Score: score,
|
||||||
@ -642,6 +670,46 @@ func (e *RedisHelper) DelSortSet(key, member string) error {
|
|||||||
return e.client.ZRem(e.ctx, key, member).Err()
|
return e.client.ZRem(e.ctx, key, member).Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveBeforeScore 移除 Sorted Set 中分数小于等于指定值的数据
|
||||||
|
// key: Sorted Set 的键
|
||||||
|
// score: 分数上限,所有小于等于此分数的元素将被移除
|
||||||
|
// 返回值: 移除的元素数量和可能的错误
|
||||||
|
func (e *RedisHelper) RemoveBeforeScore(key string, score float64) (int64, error) {
|
||||||
|
if key == "" {
|
||||||
|
return 0, errors.New("key 不能为空")
|
||||||
|
}
|
||||||
|
if math.IsNaN(score) || math.IsInf(score, 0) {
|
||||||
|
return 0, errors.New("score 必须是有效数字")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 ZRemRangeByScore 移除数据
|
||||||
|
count, err := e.client.ZRemRangeByScore(e.ctx, key, "-inf", strconv.FormatFloat(score, 'f', -1, 64)).Result()
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("移除 Sorted Set 数据失败, key: %s, score: %f, err: %v", key, score, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNextAfterScore 获取指定分数及之后的第一条数据(包含指定分数)
|
||||||
|
func (e *RedisHelper) GetNextAfterScore(key string, score float64) (string, error) {
|
||||||
|
// 使用 ZRangeByScore 获取大于等于 score 的第一条数据
|
||||||
|
zs, err := e.client.ZRangeByScoreWithScores(e.ctx, key, &redis.ZRangeBy{
|
||||||
|
Min: fmt.Sprintf("%f", score), // 包含指定分数
|
||||||
|
Max: "+inf", // 上限为正无穷
|
||||||
|
Offset: 0, // 从第 0 条开始
|
||||||
|
Count: 1, // 只取 1 条
|
||||||
|
}).Result()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("获取数据失败: %v", err)
|
||||||
|
}
|
||||||
|
if len(zs) == 0 {
|
||||||
|
return "", nil // 没有符合条件的元素
|
||||||
|
}
|
||||||
|
return zs[0].Member.(string), nil
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
获取sort set 所有数据
|
获取sort set 所有数据
|
||||||
*/
|
*/
|
||||||
@ -656,6 +724,22 @@ func (e *RedisHelper) GetRevRangeScoresSortSet(key string) ([]redis.Z, error) {
|
|||||||
return e.client.ZRevRangeWithScores(e.ctx, key, 0, -1).Result()
|
return e.client.ZRevRangeWithScores(e.ctx, key, 0, -1).Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取最后一条数据
|
||||||
|
func (e *RedisHelper) GetLastSortSet(key string) ([]redis.Z, error) {
|
||||||
|
// 获取最后一个元素及其分数
|
||||||
|
results, err := e.client.ZRevRangeWithScores(e.ctx, key, 0, 0).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get last member: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有数据,返回空
|
||||||
|
if len(results) == 0 {
|
||||||
|
return []redis.Z{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 获取指定区间数据
|
// 获取指定区间数据
|
||||||
func (e *RedisHelper) GetSortSetMembers(key string, start, stop int64) ([]string, error) {
|
func (e *RedisHelper) GetSortSetMembers(key string, start, stop int64) ([]string, error) {
|
||||||
return e.client.ZRange(e.ctx, key, start, stop).Result()
|
return e.client.ZRange(e.ctx, key, start, stop).Result()
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package helper
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -60,6 +61,8 @@ func InitLockRedisConn(host, password, dbIndex string) {
|
|||||||
log.Error("Failed to connect to Redis", zap.Error(err))
|
log.Error("Failed to connect to Redis", zap.Error(err))
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("redis lock初始化完毕")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +109,9 @@ func (rl *RedisLock) AcquireWait(ctx context.Context) (bool, error) {
|
|||||||
baseInterval = time.Second
|
baseInterval = time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if baseInterval <= 0 {
|
||||||
|
baseInterval = time.Millisecond * 100 // 至少 100ms
|
||||||
|
}
|
||||||
// 随机退避
|
// 随机退避
|
||||||
retryInterval := time.Duration(rand.Int63n(int64(baseInterval))) // 随机退避
|
retryInterval := time.Duration(rand.Int63n(int64(baseInterval))) // 随机退避
|
||||||
if retryInterval < time.Millisecond*100 {
|
if retryInterval < time.Millisecond*100 {
|
||||||
@ -129,6 +135,13 @@ func (rl *RedisLock) AcquireWait(ctx context.Context) (bool, error) {
|
|||||||
return false, ErrFailed
|
return false, ErrFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func safeRandomDuration(max time.Duration) time.Duration {
|
||||||
|
if max <= 0 {
|
||||||
|
return 100 * time.Millisecond // fallback default
|
||||||
|
}
|
||||||
|
return time.Duration(rand.Int63n(int64(max)))
|
||||||
|
}
|
||||||
|
|
||||||
// Release 释放锁
|
// Release 释放锁
|
||||||
func (rl *RedisLock) Release() (bool, error) {
|
func (rl *RedisLock) Release() (bool, error) {
|
||||||
return rl.releaseCtx(context.Background())
|
return rl.releaseCtx(context.Background())
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
"go-admin/services/futureservice"
|
"go-admin/services/futureservice"
|
||||||
"go-admin/services/scriptservice"
|
"go-admin/services/scriptservice"
|
||||||
"os"
|
"os"
|
||||||
|
"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"
|
||||||
@ -23,17 +24,27 @@ import (
|
|||||||
|
|
||||||
// 业务初始化
|
// 业务初始化
|
||||||
func BusinessInit(db *gorm.DB) {
|
func BusinessInit(db *gorm.DB) {
|
||||||
|
|
||||||
httputils.InitProxy(config.ExtConfig.ProxyUrl)
|
httputils.InitProxy(config.ExtConfig.ProxyUrl)
|
||||||
|
|
||||||
if err := loadApiUser(db); err != nil { //加载api用户
|
if err := loadApiUser(db); err != nil { //加载api用户
|
||||||
|
fmt.Printf("加载api用户失败 err:%v", err)
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
//初始化参数配置
|
//初始化参数配置
|
||||||
cacheservice.InitConfigCache(db)
|
cacheservice.InitConfigCache(db)
|
||||||
|
//初始化可缓存价格交易对
|
||||||
|
symbolPriceService := service.LineSymbolPrice{}
|
||||||
|
symbolPriceService.Orm = db
|
||||||
|
symbolPriceService.Log = logger.NewHelper(sdk.Runtime.GetLogger()).WithFields(map[string]interface{}{})
|
||||||
|
symbolPriceService.InitCache()
|
||||||
|
|
||||||
|
//清理交易对缓存价格
|
||||||
|
clearSymbolPrice()
|
||||||
|
|
||||||
//初始化订单配置
|
//初始化订单配置
|
||||||
binanceservice.ResetSystemSetting(db)
|
cacheservice.ResetSystemSetting(db)
|
||||||
lineApiUser := service.LineApiUser{}
|
lineApiUser := service.LineApiUser{}
|
||||||
lineApiUser.Orm = db
|
lineApiUser.Orm = db
|
||||||
if err := lineApiUser.InitCache(); err != nil {
|
if err := lineApiUser.InitCache(); err != nil {
|
||||||
@ -140,3 +151,24 @@ func loadApiUser(db *gorm.DB) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清理交易对价格缓存
|
||||||
|
func clearSymbolPrice() error {
|
||||||
|
spotAll, _ := helper.DefaultRedis.ScanKeys("spot_ticker_last_price:*")
|
||||||
|
futAllKey, _ := helper.DefaultRedis.ScanKeys("fut_ticker_last_price:*")
|
||||||
|
beforeTimeUtc := time.Now().UnixMilli()
|
||||||
|
|
||||||
|
for _, item := range spotAll {
|
||||||
|
if _, err := helper.DefaultRedis.RemoveBeforeScore(item, float64(beforeTimeUtc)); err != nil {
|
||||||
|
logger.Error("现货 清理交易对价格缓存失败:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range futAllKey {
|
||||||
|
if _, err := helper.DefaultRedis.RemoveBeforeScore(item, float64(beforeTimeUtc)); err != nil {
|
||||||
|
logger.Error("合约 清理交易对价格缓存失败:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
BIN
exchange-single
BIN
exchange-single
Binary file not shown.
11
models/binancedto/account.go
Normal file
11
models/binancedto/account.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package binancedto
|
||||||
|
|
||||||
|
import "github.com/shopspring/decimal"
|
||||||
|
|
||||||
|
type BinanceTransfer struct {
|
||||||
|
Type string `json:"type" content:"枚举 MAIN_UMFUTURE-现货到u合约"`
|
||||||
|
Asset string `json:"asset" content:"币种"`
|
||||||
|
Amount decimal.Decimal `json:"amount" content:"数量"`
|
||||||
|
FromSymbol string `json:"fromSymbol" content:"转出币种"`
|
||||||
|
ToSymbol string `json:"toSymbol" content:"转入币种"`
|
||||||
|
}
|
||||||
@ -640,3 +640,43 @@ func GetSpotUProperty(apiUserInfo DbModels.LineApiUser, data *dto.LineUserProper
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 万象划转
|
||||||
|
func TradeAmount(db *gorm.DB, req *binancedto.BinanceTransfer, apiUserInfo DbModels.LineApiUser) error {
|
||||||
|
url := "/sapi/v1/asset/transfer"
|
||||||
|
|
||||||
|
client := GetClient(&apiUserInfo)
|
||||||
|
|
||||||
|
params := map[string]string{
|
||||||
|
"type": req.Type,
|
||||||
|
"asset": req.Asset,
|
||||||
|
"amount": req.Amount.String(),
|
||||||
|
"fromSymbol": req.FromSymbol,
|
||||||
|
"toSymbol": req.ToSymbol,
|
||||||
|
"recvWindow": "10000",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, code, err := client.SendSpotAuth(url, "POST", params)
|
||||||
|
if err != nil || code != 200 {
|
||||||
|
log.Error("万向划转失败 参数:", params)
|
||||||
|
log.Error("万向划转失败 code:", code)
|
||||||
|
log.Error("万向划转失败 err:", err)
|
||||||
|
dataMap := make(map[string]interface{})
|
||||||
|
if err.Error() != "" {
|
||||||
|
if err := sonic.Unmarshal([]byte(err.Error()), &dataMap); err != nil {
|
||||||
|
return fmt.Errorf("api_id:%d 万向划转失败:%+v", apiUserInfo.Id, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
code, ok := dataMap["code"]
|
||||||
|
if ok {
|
||||||
|
return fmt.Errorf("api_id:%d 万向划转失败:%s", apiUserInfo.Id, ErrorMaps[code.(float64)])
|
||||||
|
}
|
||||||
|
if strings.Contains(err.Error(), "Unknown order sent.") {
|
||||||
|
return fmt.Errorf("api_id:%d 万向划转失败:%+v", apiUserInfo.Id, ErrorMaps[-2011])
|
||||||
|
}
|
||||||
|
return fmt.Errorf("api_id:%d 万向划转失败:%+v", apiUserInfo.Id, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
package binanceservice
|
package binanceservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
DbModels "go-admin/app/admin/models"
|
DbModels "go-admin/app/admin/models"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/const/rediskey"
|
"go-admin/common/const/rediskey"
|
||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/helper"
|
"go-admin/common/helper"
|
||||||
"go-admin/models"
|
|
||||||
"go-admin/models/positiondto"
|
"go-admin/models/positiondto"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
"go-admin/services/positionservice"
|
"go-admin/services/positionservice"
|
||||||
@ -27,32 +25,6 @@ type AddPosition struct {
|
|||||||
Db *gorm.DB
|
Db *gorm.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取缓存交易对
|
|
||||||
// symbolType 0-现货 1-合约
|
|
||||||
func GetTradeSet(symbol string, symbolType int) (models.TradeSet, error) {
|
|
||||||
result := models.TradeSet{}
|
|
||||||
val := ""
|
|
||||||
|
|
||||||
switch symbolType {
|
|
||||||
case 0:
|
|
||||||
key := fmt.Sprintf(global.TICKER_SPOT, global.EXCHANGE_BINANCE, symbol)
|
|
||||||
val, _ = helper.DefaultRedis.GetString(key)
|
|
||||||
case 1:
|
|
||||||
key := fmt.Sprintf(global.TICKER_FUTURES, global.EXCHANGE_BINANCE, symbol)
|
|
||||||
val, _ = helper.DefaultRedis.GetString(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if val != "" {
|
|
||||||
if err := sonic.Unmarshal([]byte(val), &result); err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return result, errors.New("未找到交易对信息")
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetRisk(futApi *FutRestApi, apiInfo *DbModels.LineApiUser, symbol string) []PositionRisk {
|
func GetRisk(futApi *FutRestApi, apiInfo *DbModels.LineApiUser, symbol string) []PositionRisk {
|
||||||
for x := 0; x < 5; x++ {
|
for x := 0; x < 5; x++ {
|
||||||
risks, _ := futApi.GetPositionV3(apiInfo, symbol)
|
risks, _ := futApi.GetPositionV3(apiInfo, symbol)
|
||||||
@ -279,11 +251,15 @@ func (e *AddPosition) CalculateAmount(req dto.ManuallyCover, totalNum, lastPrice
|
|||||||
// mainOrderId 主单id
|
// mainOrderId 主单id
|
||||||
// symbolType 1现货 2合约
|
// symbolType 1现货 2合约
|
||||||
func MainClosePositionClearCache(mainId int, symbolType int) {
|
func MainClosePositionClearCache(mainId int, symbolType int) {
|
||||||
|
strategyDto := dto.StrategyOrderRedisList{}
|
||||||
|
|
||||||
if symbolType == 1 {
|
if symbolType == 1 {
|
||||||
keySpotStop := fmt.Sprintf(rediskey.SpotStopLossList, global.EXCHANGE_BINANCE)
|
keySpotStop := fmt.Sprintf(rediskey.SpotStopLossList, global.EXCHANGE_BINANCE)
|
||||||
keySpotAddposition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE)
|
keySpotAddposition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE)
|
||||||
spotStopArray, _ := helper.DefaultRedis.GetAllList(keySpotStop)
|
spotStopArray, _ := helper.DefaultRedis.GetAllList(keySpotStop)
|
||||||
spotAddpositionArray, _ := helper.DefaultRedis.GetAllList(keySpotAddposition)
|
spotAddpositionArray, _ := helper.DefaultRedis.GetAllList(keySpotAddposition)
|
||||||
|
spotStrategyKey := fmt.Sprintf(rediskey.StrategySpotOrderList, global.EXCHANGE_BINANCE)
|
||||||
|
spotStrategyList, _ := helper.DefaultRedis.GetAllList(spotStrategyKey)
|
||||||
var position AddPositionList
|
var position AddPositionList
|
||||||
var stop dto.StopLossRedisList
|
var stop dto.StopLossRedisList
|
||||||
|
|
||||||
@ -307,11 +283,23 @@ func MainClosePositionClearCache(mainId int, symbolType int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, item := range spotStrategyList {
|
||||||
|
sonic.Unmarshal([]byte(item), &strategyDto)
|
||||||
|
|
||||||
|
if strategyDto.Id == mainId {
|
||||||
|
if _, err := helper.DefaultRedis.LRem(spotStrategyKey, item); err != nil {
|
||||||
|
logger.Errorf("id:%d 移除缓存失败,err:%v", mainId, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
keyFutStop := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE)
|
keyFutStop := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE)
|
||||||
keyFutAddposition := fmt.Sprintf(rediskey.FuturesStopLossList, global.EXCHANGE_BINANCE)
|
keyFutAddposition := fmt.Sprintf(rediskey.FuturesStopLossList, global.EXCHANGE_BINANCE)
|
||||||
futAddpositionArray, _ := helper.DefaultRedis.GetAllList(keyFutStop)
|
futAddpositionArray, _ := helper.DefaultRedis.GetAllList(keyFutStop)
|
||||||
futStopArray, _ := helper.DefaultRedis.GetAllList(keyFutAddposition)
|
futStopArray, _ := helper.DefaultRedis.GetAllList(keyFutAddposition)
|
||||||
|
|
||||||
|
futStrategyKey := fmt.Sprintf(rediskey.StrategyFutOrderList, global.EXCHANGE_BINANCE)
|
||||||
|
futStrategyList, _ := helper.DefaultRedis.GetAllList(futStrategyKey)
|
||||||
var position AddPositionList
|
var position AddPositionList
|
||||||
var stop dto.StopLossRedisList
|
var stop dto.StopLossRedisList
|
||||||
|
|
||||||
@ -334,6 +322,16 @@ func MainClosePositionClearCache(mainId int, symbolType int) {
|
|||||||
helper.DefaultRedis.LRem(keyFutStop, item)
|
helper.DefaultRedis.LRem(keyFutStop, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, item := range futStrategyList {
|
||||||
|
sonic.Unmarshal([]byte(item), &strategyDto)
|
||||||
|
|
||||||
|
if strategyDto.Id == mainId {
|
||||||
|
if _, err := helper.DefaultRedis.LRem(futStrategyKey, item); err != nil {
|
||||||
|
logger.Errorf("id:%d 移除缓存失败,err:%v", mainId, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
64
services/binanceservice/futures_judge_service_test.go
Normal file
64
services/binanceservice/futures_judge_service_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package binanceservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
"go-admin/models"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFutureJudge(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", "", "2")
|
||||||
|
// tradeSet := models.TradeSet{
|
||||||
|
// Coin: "ADA",
|
||||||
|
// Currency: "USDT",
|
||||||
|
// LastPrice: "0.516",
|
||||||
|
// }
|
||||||
|
|
||||||
|
key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
|
||||||
|
item := `{"id":10,"apiId":49,"mainId":7,"pid":7,"symbol":"ADAUSDT","price":"0.6244","side":"BUY","num":"12","orderSn":"398690240274890752"}`
|
||||||
|
reduceOrder := ReduceListItem{}
|
||||||
|
futApi := FutRestApi{}
|
||||||
|
setting, err := cacheservice.GetSystemSetting(db)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("获取系统设置失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
||||||
|
logger.Error("反序列化失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// JudgeFuturesReduce(tradeSet)
|
||||||
|
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试减仓后减仓触发
|
||||||
|
func TestFutureReduceReduce(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
sdk.Runtime.SetDb("default", db)
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "2")
|
||||||
|
tradeSet := models.TradeSet{
|
||||||
|
Coin: "ADA",
|
||||||
|
Currency: "USDT",
|
||||||
|
LastPrice: "0.5817",
|
||||||
|
PriceDigit: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
// JudgeFuturesReduce(tradeSet)
|
||||||
|
JudgeFuturesReduce(tradeSet)
|
||||||
|
}
|
||||||
@ -555,50 +555,6 @@ func (e FutRestApi) OrderPlace(orm *gorm.DB, params FutOrderPlace) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClosePositionB 平仓B对应的交易对
|
|
||||||
// bApiUserInfo B 账户api-user信息
|
|
||||||
// symbol 需要平仓的交易对
|
|
||||||
// closeType 平仓模式 ALL = 全平 reduceOnly = 只减仓
|
|
||||||
// func (e FutRestApi) ClosePositionB(orm *gorm.DB, bApiUserInfo *DbModels.LineApiUser, symbol string, closeType string) error {
|
|
||||||
// if bApiUserInfo == nil {
|
|
||||||
// return errors.New("缺失平仓账户信息")
|
|
||||||
// }
|
|
||||||
// if symbol == "" {
|
|
||||||
// return errors.New("缺失平仓交易对信息")
|
|
||||||
// }
|
|
||||||
// risks, err := e.GetPositionV3(bApiUserInfo, symbol)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for _, risk := range risks {
|
|
||||||
// if risk.Symbol == strings.ToUpper(symbol) {
|
|
||||||
// //持仓数量
|
|
||||||
// positionAmt, _ := decimal.NewFromString(risk.PositionAmt)
|
|
||||||
// side := "BUY"
|
|
||||||
// if positionAmt.GreaterThan(decimal.Zero) {
|
|
||||||
// side = "SELL"
|
|
||||||
// }
|
|
||||||
// var closeAmt decimal.Decimal
|
|
||||||
// if strings.ToUpper(closeType) == "ALL" { //全部平仓
|
|
||||||
// closeAmt = positionAmt
|
|
||||||
// } else {
|
|
||||||
// //如果是只减仓的话 数量=仓位数量*比例
|
|
||||||
// closeAmt = positionAmt.Mul(decimal.NewFromFloat(reduceOnlyRate))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err = e.ClosePosition(symbol, closeAmt, side, *bApiUserInfo, "MARKET", "", decimal.Zero)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// orm.Model(&DbModels.LinePreOrder{}).Where("api_id = ? AND symbol = ?", bApiUserInfo.Id, symbol).Updates(map[string]interface{}{
|
|
||||||
// "status": "6",
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 获取合约 持仓价格、数量
|
// 获取合约 持仓价格、数量
|
||||||
// symbol:交易对
|
// symbol:交易对
|
||||||
// side:方向
|
// side:方向
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import (
|
|||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/helper"
|
"go-admin/common/helper"
|
||||||
"go-admin/models"
|
"go-admin/models"
|
||||||
|
"go-admin/pkg/utility"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -151,21 +153,92 @@ func JudgeFuturesReduce(trade models.TradeSet) {
|
|||||||
key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
|
key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
|
||||||
reduceVal, _ := helper.DefaultRedis.GetAllList(key)
|
reduceVal, _ := helper.DefaultRedis.GetAllList(key)
|
||||||
|
|
||||||
if len(reduceVal) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
db := GetDBConnection()
|
db := GetDBConnection()
|
||||||
futApi := FutRestApi{}
|
futApi := FutRestApi{}
|
||||||
setting, err := GetSystemSetting(db)
|
setting, err := cacheservice.GetSystemSetting(db)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("获取系统设置失败")
|
log.Error("获取系统设置失败")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduceOrder := ReduceListItem{}
|
||||||
|
tradePrice, _ := decimal.NewFromString(trade.LastPrice)
|
||||||
|
//减仓单减仓策略
|
||||||
|
reduceReduceListKey := fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||||
|
orderReduceVal, _ := helper.DefaultRedis.HGetAllFields(reduceReduceListKey)
|
||||||
|
reduceOrderStrategy := dto.LineOrderReduceStrategyResp{}
|
||||||
|
|
||||||
|
for _, item := range orderReduceVal {
|
||||||
|
sonic.Unmarshal([]byte(item), &reduceOrderStrategy)
|
||||||
|
|
||||||
|
for index, item2 := range reduceOrderStrategy.Items {
|
||||||
|
if reduceOrderStrategy.Symbol == trade.Coin+trade.Currency && !item2.Actived {
|
||||||
|
//买入
|
||||||
|
if item2.TriggerPrice.Cmp(decimal.Zero) > 0 &&
|
||||||
|
tradePrice.Cmp(decimal.Zero) > 0 &&
|
||||||
|
((strings.ToUpper(reduceOrderStrategy.Side) == "SELL" && item2.TriggerPrice.Cmp(tradePrice) >= 0) ||
|
||||||
|
(strings.ToUpper(reduceOrderStrategy.Side) == "BUY" && item2.TriggerPrice.Cmp(tradePrice) <= 0)) {
|
||||||
|
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.ReduceStrategyFutTriggerLock, reduceOrder.ApiId, reduceOrder.Symbol), 50, 15, 100*time.Millisecond)
|
||||||
|
|
||||||
|
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||||
|
log.Error("获取锁失败", err)
|
||||||
|
return
|
||||||
|
} else if ok {
|
||||||
|
defer lock.Release()
|
||||||
|
hasrecord, _ := helper.DefaultRedis.HExists(reduceReduceListKey, utility.IntToString(reduceOrderStrategy.OrderId), item)
|
||||||
|
|
||||||
|
if !hasrecord {
|
||||||
|
log.Debug("减仓缓存中不存在", item)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.PriceDigit)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("%d 生成订单失败", reduceOrderStrategy.OrderId)
|
||||||
|
}
|
||||||
|
|
||||||
|
reduceOrder.ApiId = order.ApiId
|
||||||
|
reduceOrder.Id = order.Id
|
||||||
|
reduceOrder.Pid = order.Pid
|
||||||
|
reduceOrder.MainId = order.MainId
|
||||||
|
reduceOrder.Symbol = order.Symbol
|
||||||
|
reduceOrder.Side = reduceOrderStrategy.Side
|
||||||
|
reduceOrder.OrderSn = order.OrderSn
|
||||||
|
reduceOrder.Price = item2.Price
|
||||||
|
reduceOrder.Num = item2.Num
|
||||||
|
//下单成功修改策略节点状态
|
||||||
|
if FuturesReduceTrigger(db, reduceOrder, futApi, setting, reduceReduceListKey, item, true, reduceOrderStrategy.OrderId) {
|
||||||
|
reduceOrderStrategy.Items[index].Actived = true
|
||||||
|
allActive := true
|
||||||
|
orderId := utility.IntToString(reduceOrderStrategy.OrderId)
|
||||||
|
|
||||||
|
for _, item3 := range reduceOrderStrategy.Items {
|
||||||
|
if !item3.Actived {
|
||||||
|
allActive = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if allActive {
|
||||||
|
if err := helper.DefaultRedis.HDelField(reduceReduceListKey, orderId); err != nil {
|
||||||
|
log.Errorf("删除redis reduceReduceListKey失败 %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
str, _ := sonic.MarshalString(reduceOrderStrategy)
|
||||||
|
if err := helper.DefaultRedis.HSetField(reduceReduceListKey, orderId, str); err != nil {
|
||||||
|
log.Errorf("更新redis reduceReduceListKey失败 %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, item := range reduceVal {
|
for _, item := range reduceVal {
|
||||||
reduceOrder := ReduceListItem{}
|
|
||||||
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
||||||
log.Error("反序列化失败")
|
log.Error("反序列化失败")
|
||||||
continue
|
continue
|
||||||
@ -173,59 +246,68 @@ func JudgeFuturesReduce(trade models.TradeSet) {
|
|||||||
|
|
||||||
if reduceOrder.Symbol == trade.Coin+trade.Currency {
|
if reduceOrder.Symbol == trade.Coin+trade.Currency {
|
||||||
orderPrice := reduceOrder.Price
|
orderPrice := reduceOrder.Price
|
||||||
tradePrice, _ := decimal.NewFromString(trade.LastPrice)
|
|
||||||
//买入
|
//买入
|
||||||
if orderPrice.Cmp(decimal.Zero) > 0 &&
|
if orderPrice.Cmp(decimal.Zero) > 0 &&
|
||||||
tradePrice.Cmp(decimal.Zero) > 0 &&
|
tradePrice.Cmp(decimal.Zero) > 0 &&
|
||||||
((strings.ToUpper(reduceOrder.Side) == "SELL" && orderPrice.Cmp(tradePrice) >= 0) ||
|
((strings.ToUpper(reduceOrder.Side) == "SELL" && orderPrice.Cmp(tradePrice) >= 0) ||
|
||||||
(strings.ToUpper(reduceOrder.Side) == "BUY" && orderPrice.Cmp(tradePrice) <= 0)) {
|
(strings.ToUpper(reduceOrder.Side) == "BUY" && orderPrice.Cmp(tradePrice) <= 0)) {
|
||||||
|
|
||||||
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item)
|
FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触发合约减仓
|
// 触发合约减仓
|
||||||
func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string) {
|
// isStrategy 是否是策略减仓
|
||||||
tradeSet, _ := GetTradeSet(reduceOrder.Symbol, 1)
|
// reduceId 父减仓单id
|
||||||
|
func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool, reduceId int) bool {
|
||||||
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 1)
|
||||||
|
result := true
|
||||||
|
|
||||||
if tradeSet.LastPrice == "" {
|
if tradeSet.LastPrice == "" {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutTrigger, reduceOrder.ApiId, reduceOrder.Symbol), 20, 5, 100*time.Millisecond)
|
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutTrigger, reduceOrder.ApiId, reduceOrder.Symbol), 20, 5, 100*time.Millisecond)
|
||||||
|
|
||||||
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||||
log.Error("获取锁失败", err)
|
log.Error("获取锁失败", err)
|
||||||
return
|
return false
|
||||||
} else if ok {
|
} else if ok {
|
||||||
defer lock.Release()
|
defer lock.Release()
|
||||||
takeOrders := make([]DbModels.LinePreOrder, 0)
|
takeOrders := make([]DbModels.LinePreOrder, 0)
|
||||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type =1 AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
|
//只取消减仓单 止盈止损减仓成功后取消
|
||||||
|
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type IN 4 AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
|
||||||
log.Error("查询止盈单失败")
|
log.Error("查询止盈单失败")
|
||||||
return
|
// return false
|
||||||
}
|
}
|
||||||
|
|
||||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)
|
var hasrecord bool
|
||||||
|
|
||||||
|
if isStrategy {
|
||||||
|
hasrecord, _ = helper.DefaultRedis.HExists(key, utility.IntToString(reduceId), item)
|
||||||
|
} else {
|
||||||
|
hasrecord, _ = helper.DefaultRedis.IsElementInList(key, item)
|
||||||
|
}
|
||||||
|
|
||||||
if !hasrecord {
|
if !hasrecord {
|
||||||
log.Debug("减仓缓存中不存在", item)
|
log.Debug("减仓缓存中不存在", item)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
apiInfo, _ := GetApiInfo(reduceOrder.ApiId)
|
apiInfo, _ := GetApiInfo(reduceOrder.ApiId)
|
||||||
|
|
||||||
if apiInfo.Id == 0 {
|
if apiInfo.Id == 0 {
|
||||||
log.Error("现货减仓 查询api用户不存在")
|
log.Error("现货减仓 查询api用户不存在")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
for _, takeOrder := range takeOrders {
|
for _, takeOrder := range takeOrders {
|
||||||
err := CancelFutOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn)
|
err := CancelFutOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("合约止盈撤单失败", err)
|
log.Error("撤单失败", err)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,18 +321,8 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes
|
|||||||
positionSide = "LONG"
|
positionSide = "LONG"
|
||||||
}
|
}
|
||||||
|
|
||||||
// params := FutOrderPlace{
|
|
||||||
// ApiId: reduceOrder.ApiId,
|
|
||||||
// Side: reduceOrder.Side,
|
|
||||||
// OrderType: "STOP",
|
|
||||||
// Symbol: reduceOrder.Symbol,
|
|
||||||
// Price: price,
|
|
||||||
// StopPrice: price,
|
|
||||||
// Quantity: num,
|
|
||||||
// NewClientOrderId: reduceOrder.OrderSn,
|
|
||||||
// }
|
|
||||||
|
|
||||||
if err := futApi.ClosePositionLoop(reduceOrder.Symbol, reduceOrder.OrderSn, num, reduceOrder.Side, positionSide, apiInfo, "LIMIT", "0", price, 3); err != nil {
|
if err := futApi.ClosePositionLoop(reduceOrder.Symbol, reduceOrder.OrderSn, num, reduceOrder.Side, positionSide, apiInfo, "LIMIT", "0", price, 3); err != nil {
|
||||||
|
result = false
|
||||||
log.Errorf("合约减仓挂单失败 id:%s err:%v", reduceOrder.Id, err)
|
log.Errorf("合约减仓挂单失败 id:%s err:%v", reduceOrder.Id, err)
|
||||||
|
|
||||||
if err2 := db.Model(&DbModels.LinePreOrder{}).
|
if err2 := db.Model(&DbModels.LinePreOrder{}).
|
||||||
@ -267,14 +339,24 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes
|
|||||||
Where("id = ? AND status =0", reduceOrder.Id).Updates(map[string]interface{}{"status": 1}).Error; err != nil {
|
Where("id = ? AND status =0", reduceOrder.Id).Updates(map[string]interface{}{"status": 1}).Error; err != nil {
|
||||||
log.Errorf("合约减仓更新状态失败 id:%s err:%v", reduceOrder.Id, err)
|
log.Errorf("合约减仓更新状态失败 id:%s err:%v", reduceOrder.Id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//处理减仓单减仓策略
|
||||||
|
if err := CacheOrderStrategyAndReCreate(db, reduceOrder, 2, tradeSet, setting); err != nil {
|
||||||
|
log.Errorf("合约减仓策略处理失败 id:%s err:%v", reduceOrder.Id, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
|
if !isStrategy {
|
||||||
log.Errorf("合约减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
|
if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
|
||||||
|
log.Errorf("合约减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Error("获取锁失败")
|
log.Error("获取锁失败")
|
||||||
|
result = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断合约加仓
|
// 判断合约加仓
|
||||||
@ -322,8 +404,8 @@ func FutAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, futApi
|
|||||||
} else if ok {
|
} else if ok {
|
||||||
defer lock.Release()
|
defer lock.Release()
|
||||||
|
|
||||||
setting, _ := GetSystemSetting(db)
|
setting, _ := cacheservice.GetSystemSetting(db)
|
||||||
tradeSet, _ := GetTradeSet(v.Symbol, 1)
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, v.Symbol, 1)
|
||||||
|
|
||||||
if tradeSet.LastPrice == "" {
|
if tradeSet.LastPrice == "" {
|
||||||
log.Errorf("合约加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn)
|
log.Errorf("合约加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn)
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
models2 "go-admin/models"
|
models2 "go-admin/models"
|
||||||
"go-admin/models/positiondto"
|
"go-admin/models/positiondto"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -126,17 +127,26 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeSet, err := GetTradeSet(preOrder.Symbol, 1)
|
tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, preOrder.Symbol, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("handleReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn)
|
logger.Errorf("handleReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//修改减仓单减仓策略状态
|
||||||
|
ReduceCallBack(db, preOrder)
|
||||||
orderExt := models.LinePreOrderExt{}
|
orderExt := models.LinePreOrderExt{}
|
||||||
db.Model(&orderExt).Where("order_id =?", preOrder.Id).First(&orderExt)
|
//减仓策略单获取主减仓单的拓展信息
|
||||||
|
if preOrder.ReduceOrderId > 0 {
|
||||||
|
db.Model(&orderExt).Where("order_id =?", preOrder.ReduceOrderId).First(&orderExt)
|
||||||
|
} else {
|
||||||
|
db.Model(&orderExt).Where("order_id =?", preOrder.Id).First(&orderExt)
|
||||||
|
}
|
||||||
// rate := utility.StringAsFloat(orderExt.AddPositionVal)
|
// rate := utility.StringAsFloat(orderExt.AddPositionVal)
|
||||||
|
|
||||||
|
//取消委托中的止盈止损
|
||||||
|
cancelTakeProfitByReduce(db, apiUserInfo, preOrder.Symbol, preOrder.MainId, preOrder.SymbolType)
|
||||||
// 100%减仓 终止流程
|
// 100%减仓 终止流程
|
||||||
if orderExt.AddPositionVal.Cmp(decimal.NewFromInt(100)) >= 0 {
|
if orderExt.AddPositionVal.Cmp(decimal.NewFromInt(100)) >= 0 {
|
||||||
//缓存
|
//缓存
|
||||||
@ -160,9 +170,9 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
positionData := savePosition(db, preOrder)
|
positionData := savePosition(db, preOrder)
|
||||||
|
|
||||||
//市价单就跳出 市价减仓不设止盈止损
|
//市价单就跳出 市价减仓不设止盈止损
|
||||||
if preOrder.MainOrderType == "MARKET" {
|
// if preOrder.MainOrderType == "MARKET" {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
//亏损大于0 重新计算比例
|
//亏损大于0 重新计算比例
|
||||||
FutTakeProfit(db, preOrder, apiUserInfo, tradeSet, positionData, orderExt, decimal.Zero, decimal.Zero)
|
FutTakeProfit(db, preOrder, apiUserInfo, tradeSet, positionData, orderExt, decimal.Zero, decimal.Zero)
|
||||||
@ -171,6 +181,36 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 减仓成功后取消止盈止损
|
||||||
|
func cancelTakeProfitByReduce(db *gorm.DB, apiUserInfo DbModels.LineApiUser, symbol string, mainId int, symbolType int) {
|
||||||
|
orders, err := GetSymbolTakeAndStop(db, mainId, symbolType)
|
||||||
|
futApi := FutRestApi{}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("mainId:%d 获取委托中的止盈止损失败:%v", mainId, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
orderSns := make([]string, 0)
|
||||||
|
|
||||||
|
for _, v := range orders {
|
||||||
|
if v.OrderType != 1 && v.OrderType != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
orderSns = append(orderSns, v.OrderSn)
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := utility.SplitSlice(orderSns, 10)
|
||||||
|
|
||||||
|
for _, v := range arr {
|
||||||
|
err := futApi.CancelBatchFutOrder(apiUserInfo, symbol, v)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("mainId:%d 取消止盈止损失败:%v", mainId, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 减仓处理止盈止损
|
// 减仓处理止盈止损
|
||||||
func FutTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder, apiUserInfo DbModels.LineApiUser, tradeSet models2.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 {
|
positionData positiondto.PositionDto, orderExt DbModels.LinePreOrderExt, manualTakeRatio, manualStopRatio decimal.Decimal) bool {
|
||||||
@ -245,7 +285,7 @@ func nextFuturesReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal,
|
|||||||
nextOrder := DbModels.LinePreOrder{}
|
nextOrder := DbModels.LinePreOrder{}
|
||||||
nextExt := DbModels.LinePreOrderExt{}
|
nextExt := DbModels.LinePreOrderExt{}
|
||||||
|
|
||||||
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0 AND reduce_order_id=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
||||||
logger.Errorf("获取下一个单失败 err:%v", err)
|
logger.Errorf("获取下一个单失败 err:%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -432,6 +472,8 @@ func removeFutLossAndAddPosition(mainId int, orderSn string) {
|
|||||||
stoploss := dto.StopLossRedisList{}
|
stoploss := dto.StopLossRedisList{}
|
||||||
addPosition := AddPositionList{}
|
addPosition := AddPositionList{}
|
||||||
reduce := ReduceListItem{}
|
reduce := ReduceListItem{}
|
||||||
|
//移除减仓后减仓策略
|
||||||
|
RemoveReduceReduceCacheByMainId(mainId, 2)
|
||||||
|
|
||||||
//止损缓存
|
//止损缓存
|
||||||
for _, v := range stoplossVal {
|
for _, v := range stoplossVal {
|
||||||
@ -473,7 +515,7 @@ func removeFutLossAndAddPosition(mainId int, orderSn string) {
|
|||||||
// 处理主单成交,处理止盈、止损、减仓订单
|
// 处理主单成交,处理止盈、止损、减仓订单
|
||||||
func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrderId int, first bool) {
|
func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrderId int, first bool) {
|
||||||
// 获取交易对配置和API信息
|
// 获取交易对配置和API信息
|
||||||
tradeSet, err := GetTradeSet(preOrder.Symbol, 1)
|
tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, preOrder.Symbol, 1)
|
||||||
mainId := preOrder.Id
|
mainId := preOrder.Id
|
||||||
if err != nil || tradeSet.Coin == "" {
|
if err != nil || tradeSet.Coin == "" {
|
||||||
logger.Errorf("获取交易对配置失败, 回调订单号:%s, 错误信息: %v", preOrder.OrderSn, err)
|
logger.Errorf("获取交易对配置失败, 回调订单号:%s, 错误信息: %v", preOrder.OrderSn, err)
|
||||||
@ -595,7 +637,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
processFutStopLossOrder(db, order, price, num)
|
processFutStopLossOrder(db, order, utility.StrToDecimal(order.Price), num)
|
||||||
// case 4: // 减仓
|
// case 4: // 减仓
|
||||||
// processFutReduceOrder(order, price, num)
|
// processFutReduceOrder(order, price, num)
|
||||||
}
|
}
|
||||||
@ -697,9 +739,13 @@ func updateOrderQuantity(db *gorm.DB, order models.LinePreOrder, preOrder *model
|
|||||||
// order.Num = num.String()
|
// order.Num = num.String()
|
||||||
// } else
|
// } else
|
||||||
|
|
||||||
if first && (order.OrderCategory == 1 || order.OrderCategory == 3) && order.OrderType == 1 && ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 {
|
//止盈止损重算数量
|
||||||
|
if first && (order.OrderCategory == 1 || order.OrderCategory == 3) && ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 {
|
||||||
// 计算止盈数量
|
// 计算止盈数量
|
||||||
num = num.Mul(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
if order.OrderType == 1 {
|
||||||
|
num = num.Mul(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
}
|
||||||
|
|
||||||
order.Num = num.String()
|
order.Num = num.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,7 +788,7 @@ func processFutReduceOrder(order DbModels.LinePreOrder, price, num decimal.Decim
|
|||||||
// 处理止盈订单
|
// 处理止盈订单
|
||||||
func processFutTakeProfitOrder(db *gorm.DB, futApi FutRestApi, order models.LinePreOrder, num decimal.Decimal) {
|
func processFutTakeProfitOrder(db *gorm.DB, futApi FutRestApi, order models.LinePreOrder, num decimal.Decimal) {
|
||||||
price, _ := decimal.NewFromString(order.Price)
|
price, _ := decimal.NewFromString(order.Price)
|
||||||
tradeSet, _ := GetTradeSet(order.Symbol, 1)
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1)
|
||||||
|
|
||||||
params := FutOrderPlace{
|
params := FutOrderPlace{
|
||||||
ApiId: order.ApiId,
|
ApiId: order.ApiId,
|
||||||
@ -779,7 +825,7 @@ func processFutTakeProfitOrder(db *gorm.DB, futApi FutRestApi, order models.Line
|
|||||||
// 处理止损订单
|
// 处理止损订单
|
||||||
// order 止损单
|
// order 止损单
|
||||||
func processFutStopLossOrder(db *gorm.DB, order models.LinePreOrder, price, num decimal.Decimal) error {
|
func processFutStopLossOrder(db *gorm.DB, order models.LinePreOrder, price, num decimal.Decimal) error {
|
||||||
tradeSet, _ := GetTradeSet(order.Symbol, 1)
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1)
|
||||||
|
|
||||||
params := FutOrderPlace{
|
params := FutOrderPlace{
|
||||||
ApiId: order.ApiId,
|
ApiId: order.ApiId,
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
package binanceservice
|
package binanceservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
DbModels "go-admin/app/admin/models"
|
DbModels "go-admin/app/admin/models"
|
||||||
|
"go-admin/pkg/utility"
|
||||||
|
"go-admin/pkg/utility/snowflakehelper"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -129,7 +134,7 @@ func GetTotalLossAmount(db *gorm.DB, mainId int) (decimal.Decimal, error) {
|
|||||||
return totalLossAmountU, nil
|
return totalLossAmountU, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取交易对的 委托中的止盈止损
|
// 获取交易对的 委托中的止盈止损、减仓单
|
||||||
// mainId 主单id
|
// mainId 主单id
|
||||||
// symbolType 交易对类型
|
// symbolType 交易对类型
|
||||||
func GetSymbolTakeAndStop(db *gorm.DB, mainId int, symbolType int) ([]models.LinePreOrder, error) {
|
func GetSymbolTakeAndStop(db *gorm.DB, mainId int, symbolType int) ([]models.LinePreOrder, error) {
|
||||||
@ -170,3 +175,69 @@ func GetChildTpOrder(db *gorm.DB, pid int) (int, error) {
|
|||||||
|
|
||||||
return int(count), nil
|
return int(count), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建减仓后减仓单
|
||||||
|
func CreateReduceReduceOrder(db *gorm.DB, pid int, price, num decimal.Decimal, priceDigit int) (models.LinePreOrder, error) {
|
||||||
|
var preOrder models.LinePreOrder
|
||||||
|
var result models.LinePreOrder
|
||||||
|
var ext models.LinePreOrderExt
|
||||||
|
|
||||||
|
if err := db.Model(&models.LinePreOrder{}).Preload("Childs").Where("id =? ", pid).First(&preOrder).Error; err != nil {
|
||||||
|
return preOrder, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Model(&models.LinePreOrderExt{}).Where("order_id =? ", pid).Find(&ext).Error; err != nil {
|
||||||
|
return preOrder, err
|
||||||
|
}
|
||||||
|
|
||||||
|
copier.Copy(&result, &preOrder)
|
||||||
|
|
||||||
|
result.Id = 0
|
||||||
|
result.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||||
|
result.Status = 0
|
||||||
|
result.CreatedAt = time.Now()
|
||||||
|
result.TriggerTime = nil
|
||||||
|
result.UpdatedAt = time.Now()
|
||||||
|
result.BuyPrice = decimal.Zero.String()
|
||||||
|
result.Price = price.String()
|
||||||
|
result.Num = num.String()
|
||||||
|
result.ReduceOrderId = preOrder.Id
|
||||||
|
|
||||||
|
for index := range result.Childs {
|
||||||
|
result.Childs[index].Id = 0
|
||||||
|
result.Childs[index].OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||||
|
result.Childs[index].Status = 0
|
||||||
|
result.Childs[index].CreatedAt = time.Now()
|
||||||
|
result.Childs[index].TriggerTime = nil
|
||||||
|
result.Childs[index].UpdatedAt = time.Now()
|
||||||
|
result.Childs[index].BuyPrice = decimal.Zero.String()
|
||||||
|
var pricePercent decimal.Decimal
|
||||||
|
|
||||||
|
if result.Childs[index].OrderType == 1 && ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
// 减仓单卖出
|
||||||
|
if preOrder.Site == "SELL" {
|
||||||
|
pricePercent = decimal.NewFromInt(100).Add(ext.TakeProfitRatio).Div(decimal.NewFromInt(100))
|
||||||
|
} else {
|
||||||
|
pricePercent = decimal.NewFromInt(100).Sub(ext.TakeProfitRatio).Div(decimal.NewFromInt(100))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if result.Childs[index].OrderType == 2 && ext.StopLossRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
if preOrder.Site == "SELL" {
|
||||||
|
pricePercent = decimal.NewFromInt(100).Sub(ext.StopLossRatio).Div(decimal.NewFromInt(100))
|
||||||
|
} else {
|
||||||
|
pricePercent = decimal.NewFromInt(100).Add(ext.StopLossRatio).Div(decimal.NewFromInt(100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//重新计算止盈止损价
|
||||||
|
if pricePercent.Cmp(decimal.Zero) > 0 {
|
||||||
|
result.Childs[index].Price = price.Mul(pricePercent).Truncate(int32(priceDigit)).String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Create(&result).Error; err != nil {
|
||||||
|
return result, fmt.Errorf("复制减仓单失败:pid:%d err:%v", pid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|||||||
178
services/binanceservice/reduce_order_strategy_service.go
Normal file
178
services/binanceservice/reduce_order_strategy_service.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package binanceservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
models2 "go-admin/models"
|
||||||
|
"go-admin/pkg/utility"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 缓存减仓节点和重新生成
|
||||||
|
// reduceOrder:原始减仓单
|
||||||
|
// reduceOrderStrategy:减仓策略
|
||||||
|
func CacheOrderStrategyAndReCreate(db *gorm.DB, reduceOrder ReduceListItem, symbolType int, tradeSet models2.TradeSet, setting models.LineSystemSetting) error {
|
||||||
|
reduceOrderStrategy := models.LineOrderReduceStrategy{}
|
||||||
|
var key string
|
||||||
|
|
||||||
|
if symbolType == 1 {
|
||||||
|
key = fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||||
|
} else {
|
||||||
|
key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Model(&reduceOrderStrategy).Where("order_id =?", reduceOrder.Id).Find(&reduceOrderStrategy).Error; err != nil {
|
||||||
|
logger.Errorf("获取减仓策略失败,err:%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if reduceOrderStrategy.Id > 0 {
|
||||||
|
items := make([]models.LineReduceStrategyItem, 0)
|
||||||
|
strategyCache := dto.LineOrderReduceStrategyResp{
|
||||||
|
OrderId: reduceOrder.Id,
|
||||||
|
Symbol: reduceOrder.Symbol,
|
||||||
|
MainId: reduceOrder.MainId,
|
||||||
|
Side: reduceOrder.Side,
|
||||||
|
}
|
||||||
|
|
||||||
|
sonic.Unmarshal([]byte(reduceOrderStrategy.ItemContent), &items)
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
var rate decimal.Decimal
|
||||||
|
var triggerRate decimal.Decimal
|
||||||
|
|
||||||
|
if reduceOrder.Side == "SELL" {
|
||||||
|
rate = (decimal.NewFromInt(100).Sub(item.LossPercent)).Div(decimal.NewFromInt(100))
|
||||||
|
|
||||||
|
if setting.ReduceEarlyTriggerPercent.Cmp(decimal.Zero) > 0 {
|
||||||
|
triggerRate = rate.Add(setting.ReduceEarlyTriggerPercent.Div(decimal.NewFromInt(100)))
|
||||||
|
} else {
|
||||||
|
triggerRate = rate
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rate = (decimal.NewFromInt(100).Add(item.LossPercent)).Div(decimal.NewFromInt(100))
|
||||||
|
|
||||||
|
if setting.ReduceEarlyTriggerPercent.Cmp(decimal.Zero) > 0 {
|
||||||
|
triggerRate = rate.Sub(setting.ReduceEarlyTriggerPercent.Div(decimal.NewFromInt(100)))
|
||||||
|
} else {
|
||||||
|
triggerRate = rate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
price := reduceOrder.Price.Mul(rate).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
triggerPrice := reduceOrder.Price.Mul(triggerRate).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
num := reduceOrder.Num
|
||||||
|
|
||||||
|
//百分比大于0就重新计算 否则就是主减仓单数量
|
||||||
|
if item.QuantityPercent.Cmp(decimal.Zero) > 0 {
|
||||||
|
num = reduceOrder.Num.Mul(item.QuantityPercent.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
}
|
||||||
|
|
||||||
|
strategyCache.Items = append(strategyCache.Items, dto.LineOrderReduceStrategyRespItem{
|
||||||
|
LossPercent: item.LossPercent,
|
||||||
|
OrderType: item.OrderType,
|
||||||
|
Price: price,
|
||||||
|
TriggerPrice: triggerPrice,
|
||||||
|
Num: num,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
str, _ := sonic.MarshalString(strategyCache)
|
||||||
|
|
||||||
|
if str != "" {
|
||||||
|
if err := helper.DefaultRedis.HSetField(key, utility.IntToString(reduceOrder.Id), str); err != nil {
|
||||||
|
logger.Errorf("减仓单缓存减仓策略,err:%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据订单id获取订单减仓策略
|
||||||
|
func GetReduceStrategyById(db *gorm.DB, orderId int) (models.LineOrderReduceStrategy, error) {
|
||||||
|
result := models.LineOrderReduceStrategy{}
|
||||||
|
|
||||||
|
if err := db.Model(result).Where("order_id =?", orderId).Select("id", "order_id").First(&result).Error; err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 减仓单成功回调
|
||||||
|
func ReduceCallBack(db *gorm.DB, preOrder *models.LinePreOrder) error {
|
||||||
|
reduceOrderId := preOrder.Id
|
||||||
|
var key string
|
||||||
|
if preOrder.ReduceOrderId > 0 {
|
||||||
|
reduceOrderId = preOrder.ReduceOrderId
|
||||||
|
}
|
||||||
|
|
||||||
|
switch preOrder.SymbolType {
|
||||||
|
case 1:
|
||||||
|
key = fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||||
|
case 2:
|
||||||
|
key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("交易对类型错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
arrays, _ := helper.DefaultRedis.HGetAllFields(key)
|
||||||
|
cache := dto.LineOrderReduceStrategyResp{}
|
||||||
|
|
||||||
|
for _, v := range arrays {
|
||||||
|
sonic.Unmarshal([]byte(v), &cache)
|
||||||
|
|
||||||
|
if cache.OrderId == reduceOrderId {
|
||||||
|
if err := helper.DefaultRedis.HDelField(key, utility.IntToString(cache.OrderId)); err != nil {
|
||||||
|
logger.Errorf("移除减仓单减仓策略失败redis err:%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orderReduceStrategy, _ := GetReduceStrategyById(db, reduceOrderId)
|
||||||
|
if orderReduceStrategy.Id > 0 {
|
||||||
|
if err := db.Model(&orderReduceStrategy).Update("actived", 1).Error; err != nil {
|
||||||
|
logger.Errorf("更新减仓单减仓策略状态失败 order_id:%d err:%v", orderReduceStrategy.OrderId, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除减仓后减仓策略
|
||||||
|
// mainId 主单id
|
||||||
|
// symbolType 交易对类型
|
||||||
|
func RemoveReduceReduceCacheByMainId(mainId int, symbolType int) error {
|
||||||
|
var key string
|
||||||
|
switch symbolType {
|
||||||
|
case 1:
|
||||||
|
key = fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||||
|
case 2:
|
||||||
|
key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("交易对类型错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
arrays, _ := helper.DefaultRedis.HGetAllFields(key)
|
||||||
|
cache := dto.LineOrderReduceStrategyResp{}
|
||||||
|
|
||||||
|
for _, v := range arrays {
|
||||||
|
sonic.Unmarshal([]byte(v), &cache)
|
||||||
|
|
||||||
|
if cache.MainId == mainId {
|
||||||
|
if err := helper.DefaultRedis.HDelField(key, utility.IntToString(cache.OrderId)); err != nil {
|
||||||
|
logger.Errorf("移除减仓单减仓策略失败redis err:%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
64
services/binanceservice/spot_judge_service_test.go
Normal file
64
services/binanceservice/spot_judge_service_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package binanceservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
"go-admin/models"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSpotJudge(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", "", "2")
|
||||||
|
// tradeSet := models.TradeSet{
|
||||||
|
// Coin: "ADA",
|
||||||
|
// Currency: "USDT",
|
||||||
|
// LastPrice: "0.516",
|
||||||
|
// }
|
||||||
|
|
||||||
|
key := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE)
|
||||||
|
item := `{"id":66,"apiId":49,"mainId":63,"pid":63,"symbol":"ADAUSDT","price":"0.5912","side":"SELL","num":"12.6","orderSn":"397919643961917440"}`
|
||||||
|
reduceOrder := ReduceListItem{}
|
||||||
|
spotApi := SpotRestApi{}
|
||||||
|
setting, err := cacheservice.GetSystemSetting(db)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("获取系统设置失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
||||||
|
logger.Error("反序列化失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// JudgeFuturesReduce(tradeSet)
|
||||||
|
SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, false, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试减仓后减仓触发
|
||||||
|
func TestSpotReduceReduce(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
sdk.Runtime.SetDb("default", db)
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "2")
|
||||||
|
tradeSet := models.TradeSet{
|
||||||
|
Coin: "ADA",
|
||||||
|
Currency: "USDT",
|
||||||
|
LastPrice: "0.5793",
|
||||||
|
PriceDigit: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
// JudgeFuturesReduce(tradeSet)
|
||||||
|
JudgeSpotReduce(tradeSet)
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@ import (
|
|||||||
"go-admin/common/helper"
|
"go-admin/common/helper"
|
||||||
"go-admin/models"
|
"go-admin/models"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -141,14 +142,14 @@ func JudgeSpotStopLoss(trade models.TradeSet) {
|
|||||||
|
|
||||||
db := GetDBConnection()
|
db := GetDBConnection()
|
||||||
spotApi := SpotRestApi{}
|
spotApi := SpotRestApi{}
|
||||||
setting, err := GetSystemSetting(db)
|
setting, err := cacheservice.GetSystemSetting(db)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("获取系统设置失败")
|
log.Error("获取系统设置失败")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeSet, err := GetTradeSet(trade.Coin+trade.Currency, 0)
|
tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, trade.Coin+trade.Currency, 0)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("获取交易设置失败")
|
log.Error("获取交易设置失败")
|
||||||
@ -256,23 +257,94 @@ func SpotStopLossTrigger(db *gorm.DB, stopOrder dto.StopLossRedisList, spotApi S
|
|||||||
// 判断是否触发现货减仓
|
// 判断是否触发现货减仓
|
||||||
func JudgeSpotReduce(trade models.TradeSet) {
|
func JudgeSpotReduce(trade models.TradeSet) {
|
||||||
key := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE)
|
key := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE)
|
||||||
reduceVal, _ := helper.DefaultRedis.GetAllList(key)
|
|
||||||
|
|
||||||
if len(reduceVal) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
db := GetDBConnection()
|
db := GetDBConnection()
|
||||||
spotApi := SpotRestApi{}
|
spotApi := SpotRestApi{}
|
||||||
setting, err := GetSystemSetting(db)
|
setting, err := cacheservice.GetSystemSetting(db)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("获取系统设置失败")
|
log.Error("获取系统设置失败")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduceOrder := ReduceListItem{}
|
||||||
|
tradePrice, _ := decimal.NewFromString(trade.LastPrice)
|
||||||
|
//减仓单减仓策略
|
||||||
|
reduceReduceListKey := fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
||||||
|
orderReduceVal, _ := helper.DefaultRedis.HGetAllFields(reduceReduceListKey)
|
||||||
|
reduceOrderStrategy := dto.LineOrderReduceStrategyResp{}
|
||||||
|
|
||||||
|
for _, item := range orderReduceVal {
|
||||||
|
sonic.Unmarshal([]byte(item), &reduceOrderStrategy)
|
||||||
|
|
||||||
|
for index, item2 := range reduceOrderStrategy.Items {
|
||||||
|
if reduceOrderStrategy.Symbol == trade.Coin+trade.Currency {
|
||||||
|
//买入
|
||||||
|
if strings.ToUpper(reduceOrderStrategy.Side) == "SELL" &&
|
||||||
|
item2.TriggerPrice.Cmp(tradePrice) >= 0 &&
|
||||||
|
item2.TriggerPrice.Cmp(decimal.Zero) > 0 &&
|
||||||
|
tradePrice.Cmp(decimal.Zero) > 0 {
|
||||||
|
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.ReduceStrategySpotTriggerLock, reduceOrder.ApiId, reduceOrder.Symbol), 50, 15, 100*time.Millisecond)
|
||||||
|
|
||||||
|
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||||
|
log.Error("获取锁失败", err)
|
||||||
|
return
|
||||||
|
} else if ok {
|
||||||
|
defer lock.Release()
|
||||||
|
hasrecord, _ := helper.DefaultRedis.HExists(reduceReduceListKey, utility.IntTostring(reduceOrderStrategy.OrderId), item)
|
||||||
|
|
||||||
|
if !hasrecord {
|
||||||
|
log.Debug("减仓缓存中不存在", item)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.PriceDigit)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("%d 生成订单失败", reduceOrderStrategy.OrderId)
|
||||||
|
}
|
||||||
|
|
||||||
|
reduceOrder.ApiId = order.ApiId
|
||||||
|
reduceOrder.Id = order.Id
|
||||||
|
reduceOrder.Pid = order.Pid
|
||||||
|
reduceOrder.MainId = order.MainId
|
||||||
|
reduceOrder.Symbol = order.Symbol
|
||||||
|
reduceOrder.Side = reduceOrderStrategy.Side
|
||||||
|
reduceOrder.OrderSn = order.OrderSn
|
||||||
|
reduceOrder.Price = item2.Price
|
||||||
|
reduceOrder.Num = item2.Num
|
||||||
|
if SpotReduceTrigger(db, reduceOrder, spotApi, setting, reduceReduceListKey, item, true, reduceOrderStrategy.OrderId) {
|
||||||
|
reduceOrderStrategy.Items[index].Actived = true
|
||||||
|
allActive := true
|
||||||
|
orderId := utility.IntToString(reduceOrderStrategy.OrderId)
|
||||||
|
|
||||||
|
for _, item3 := range reduceOrderStrategy.Items {
|
||||||
|
if !item3.Actived {
|
||||||
|
allActive = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if allActive {
|
||||||
|
if err := helper.DefaultRedis.HDelField(reduceReduceListKey, orderId); err != nil {
|
||||||
|
log.Errorf("删除redis reduceReduceListKey失败 %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
str, _ := sonic.MarshalString(reduceOrderStrategy)
|
||||||
|
if err := helper.DefaultRedis.HSetField(reduceReduceListKey, orderId, str); err != nil {
|
||||||
|
log.Errorf("更新redis reduceReduceListKey失败 %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//减仓单
|
||||||
|
reduceVal, _ := helper.DefaultRedis.GetAllList(key)
|
||||||
|
|
||||||
for _, item := range reduceVal {
|
for _, item := range reduceVal {
|
||||||
reduceOrder := ReduceListItem{}
|
|
||||||
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
|
||||||
log.Error("反序列化失败")
|
log.Error("反序列化失败")
|
||||||
continue
|
continue
|
||||||
@ -280,59 +352,67 @@ func JudgeSpotReduce(trade models.TradeSet) {
|
|||||||
|
|
||||||
if reduceOrder.Symbol == trade.Coin+trade.Currency {
|
if reduceOrder.Symbol == trade.Coin+trade.Currency {
|
||||||
orderPrice := reduceOrder.Price
|
orderPrice := reduceOrder.Price
|
||||||
tradePrice, _ := decimal.NewFromString(trade.LastPrice)
|
|
||||||
//买入
|
//买入
|
||||||
if strings.ToUpper(reduceOrder.Side) == "SELL" &&
|
if strings.ToUpper(reduceOrder.Side) == "SELL" &&
|
||||||
orderPrice.Cmp(tradePrice) >= 0 &&
|
orderPrice.Cmp(tradePrice) >= 0 &&
|
||||||
orderPrice.Cmp(decimal.Zero) > 0 &&
|
orderPrice.Cmp(decimal.Zero) > 0 &&
|
||||||
tradePrice.Cmp(decimal.Zero) > 0 {
|
tradePrice.Cmp(decimal.Zero) > 0 {
|
||||||
|
|
||||||
SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item)
|
SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, false, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触发现货减仓
|
// 触发现货减仓
|
||||||
func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string) {
|
// isStrategy 是否是策略减仓单
|
||||||
tradeSet, err := GetTradeSet(reduceOrder.Symbol, 0)
|
// reduceId 策略主减仓单id
|
||||||
|
func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool, reduceId int) bool {
|
||||||
|
tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 0)
|
||||||
|
result := true
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("获取交易设置失败")
|
log.Error("获取交易设置失败")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, reduceOrder.ApiId, reduceOrder.Symbol), 20, 5, 100*time.Millisecond)
|
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, reduceOrder.ApiId, reduceOrder.Symbol), 20, 5, 100*time.Millisecond)
|
||||||
|
|
||||||
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||||
log.Error("获取锁失败", err)
|
log.Error("获取锁失败", err)
|
||||||
return
|
return false
|
||||||
} else if ok {
|
} else if ok {
|
||||||
defer lock.Release()
|
defer lock.Release()
|
||||||
takeOrders := make([]DbModels.LinePreOrder, 0)
|
takeOrders := make([]DbModels.LinePreOrder, 0)
|
||||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type =1 AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
|
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type IN (1,2,4) AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
|
||||||
log.Error("查询止盈单失败")
|
log.Error("查询止盈单失败")
|
||||||
return
|
return false
|
||||||
|
}
|
||||||
|
var hasrecord bool
|
||||||
|
|
||||||
|
if isStrategy {
|
||||||
|
hasrecord, _ = helper.DefaultRedis.HExists(key, utility.IntToString(reduceId), item)
|
||||||
|
} else {
|
||||||
|
hasrecord, _ = helper.DefaultRedis.IsElementInList(key, item)
|
||||||
}
|
}
|
||||||
hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)
|
|
||||||
|
|
||||||
if !hasrecord {
|
if !hasrecord {
|
||||||
log.Debug("减仓缓存中不存在", item)
|
log.Debug("减仓缓存中不存在", item)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
apiInfo, _ := GetApiInfo(reduceOrder.ApiId)
|
apiInfo, _ := GetApiInfo(reduceOrder.ApiId)
|
||||||
|
|
||||||
if apiInfo.Id == 0 {
|
if apiInfo.Id == 0 {
|
||||||
log.Error("现货减仓 查询api用户不存在")
|
log.Error("现货减仓 查询api用户不存在")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, takeOrder := range takeOrders {
|
for _, takeOrder := range takeOrders {
|
||||||
err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn)
|
err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("现货止盈撤单失败", err)
|
log.Error("现货撤单失败", err)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
|
price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
|
||||||
@ -349,6 +429,7 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
|
if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
|
||||||
|
result = false
|
||||||
log.Errorf("现货减仓挂单失败 id:%s err:%v", reduceOrder.Id, err)
|
log.Errorf("现货减仓挂单失败 id:%s err:%v", reduceOrder.Id, err)
|
||||||
|
|
||||||
if err2 := db.Model(&DbModels.LinePreOrder{}).
|
if err2 := db.Model(&DbModels.LinePreOrder{}).
|
||||||
@ -366,14 +447,23 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest
|
|||||||
Updates(map[string]interface{}{"status": 1}).Error; err != nil {
|
Updates(map[string]interface{}{"status": 1}).Error; err != nil {
|
||||||
log.Errorf("修改现货减仓状态失败 id:%s err:%v", reduceOrder.Id, err)
|
log.Errorf("修改现货减仓状态失败 id:%s err:%v", reduceOrder.Id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//处理减仓单减仓策略
|
||||||
|
if err := CacheOrderStrategyAndReCreate(db, reduceOrder, 1, tradeSet, setting); err != nil {
|
||||||
|
log.Errorf("现货减仓 处理减仓策略失败 id:%v err:%v", reduceOrder.Id, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
|
if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
|
||||||
|
result = false
|
||||||
log.Errorf("现货减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
|
log.Errorf("现货减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Error("获取锁失败")
|
log.Error("获取锁失败")
|
||||||
|
result = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断现货加仓
|
// 判断现货加仓
|
||||||
@ -414,8 +504,8 @@ func SpotAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, spotAp
|
|||||||
} else if ok {
|
} else if ok {
|
||||||
defer lock.Release()
|
defer lock.Release()
|
||||||
|
|
||||||
setting, _ := GetSystemSetting(db)
|
setting, _ := cacheservice.GetSystemSetting(db)
|
||||||
tradeSet, _ := GetTradeSet(v.Symbol, 0)
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, v.Symbol, 0)
|
||||||
|
|
||||||
if tradeSet.LastPrice == "" {
|
if tradeSet.LastPrice == "" {
|
||||||
log.Errorf("现货加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn)
|
log.Errorf("现货加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn)
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
models2 "go-admin/models"
|
models2 "go-admin/models"
|
||||||
"go-admin/models/positiondto"
|
"go-admin/models/positiondto"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
"go-admin/services/positionservice"
|
"go-admin/services/positionservice"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -165,20 +166,29 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeSet, err := GetTradeSet(preOrder.Symbol, 0)
|
tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, preOrder.Symbol, 0)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("handleMainReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn)
|
logger.Errorf("handleMainReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//修改减仓单减仓策略状态
|
||||||
|
ReduceCallBack(db, preOrder)
|
||||||
|
|
||||||
orderExt := models.LinePreOrderExt{}
|
orderExt := models.LinePreOrderExt{}
|
||||||
positionData := savePosition(db, preOrder)
|
positionData := savePosition(db, preOrder)
|
||||||
|
|
||||||
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)
|
|
||||||
|
//策略减仓单 获取主减仓单拓展信息
|
||||||
|
if preOrder.ReduceOrderId > 0 {
|
||||||
|
db.Model(&orderExt).Where("order_id =?", preOrder.ReduceOrderId).Find(&orderExt)
|
||||||
|
} else {
|
||||||
|
db.Model(&orderExt).Where("order_id =?", preOrder.Id).Find(&orderExt)
|
||||||
|
}
|
||||||
|
|
||||||
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotReduceCallback, preOrder.ApiId, preOrder.Symbol), 120, 20, 100*time.Millisecond)
|
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotReduceCallback, preOrder.ApiId, preOrder.Symbol), 120, 20, 100*time.Millisecond)
|
||||||
|
|
||||||
@ -278,7 +288,7 @@ func nextSpotReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tr
|
|||||||
nextExt := DbModels.LinePreOrderExt{}
|
nextExt := DbModels.LinePreOrderExt{}
|
||||||
// var percentag decimal.Decimal
|
// var percentag decimal.Decimal
|
||||||
|
|
||||||
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0 AND reduce_order_id =0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
||||||
logger.Errorf("获取下一个单失败 err:%v", err)
|
logger.Errorf("获取下一个单失败 err:%v", err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -546,6 +556,9 @@ func removeSpotLossAndAddPosition(mainId int, orderSn string) {
|
|||||||
addPosition := AddPositionList{}
|
addPosition := AddPositionList{}
|
||||||
reduce := ReduceListItem{}
|
reduce := ReduceListItem{}
|
||||||
|
|
||||||
|
//移除减仓后减仓策略
|
||||||
|
RemoveReduceReduceCacheByMainId(mainId, 1)
|
||||||
|
|
||||||
//止损缓存
|
//止损缓存
|
||||||
for _, v := range stoplossVal {
|
for _, v := range stoplossVal {
|
||||||
sonic.Unmarshal([]byte(v), &stoploss)
|
sonic.Unmarshal([]byte(v), &stoploss)
|
||||||
@ -731,7 +744,7 @@ func updateOrderStatus(db *gorm.DB, preOrder *models.LinePreOrder, status int, r
|
|||||||
// fist 首次止盈止损
|
// fist 首次止盈止损
|
||||||
func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder, positionData *positiondto.PositionDto, extOrderId int, fist bool) {
|
func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder, positionData *positiondto.PositionDto, extOrderId int, fist bool) {
|
||||||
orders := []models.LinePreOrder{}
|
orders := []models.LinePreOrder{}
|
||||||
tradeSet, _ := GetTradeSet(preOrder.Symbol, 0)
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, preOrder.Symbol, 0)
|
||||||
mainId := preOrder.Id
|
mainId := preOrder.Id
|
||||||
|
|
||||||
if preOrder.MainId > 0 {
|
if preOrder.MainId > 0 {
|
||||||
@ -869,7 +882,7 @@ func processSpotReduceOrder(preOrder DbModels.LinePreOrder) {
|
|||||||
|
|
||||||
// 处理止盈订单
|
// 处理止盈订单
|
||||||
func processTakeProfitOrder(db *gorm.DB, spotApi SpotRestApi, order models.LinePreOrder) {
|
func processTakeProfitOrder(db *gorm.DB, spotApi SpotRestApi, order models.LinePreOrder) {
|
||||||
tradeSet, _ := GetTradeSet(order.Symbol, 0)
|
tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 0)
|
||||||
|
|
||||||
if tradeSet.Coin == "" {
|
if tradeSet.Coin == "" {
|
||||||
logger.Error("获取交易对失败")
|
logger.Error("获取交易对失败")
|
||||||
@ -941,44 +954,6 @@ func processStopLossOrder(order models.LinePreOrder) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSystemSetting(db *gorm.DB) (models.LineSystemSetting, error) {
|
|
||||||
key := fmt.Sprintf(rediskey.SystemSetting)
|
|
||||||
val, _ := helper.DefaultRedis.GetString(key)
|
|
||||||
setting := models.LineSystemSetting{}
|
|
||||||
|
|
||||||
if val != "" {
|
|
||||||
sonic.UnmarshalString(val, &setting)
|
|
||||||
}
|
|
||||||
|
|
||||||
if setting.Id > 0 {
|
|
||||||
return setting, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
setting, err = ResetSystemSetting(db)
|
|
||||||
if err != nil {
|
|
||||||
return setting, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return setting, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResetSystemSetting(db *gorm.DB) (DbModels.LineSystemSetting, error) {
|
|
||||||
setting := DbModels.LineSystemSetting{}
|
|
||||||
if err := db.Model(&setting).First(&setting).Error; err != nil {
|
|
||||||
return setting, err
|
|
||||||
}
|
|
||||||
|
|
||||||
settVal, _ := sonic.MarshalString(&setting)
|
|
||||||
|
|
||||||
if settVal != "" {
|
|
||||||
if err := helper.DefaultRedis.SetString(rediskey.SystemSetting, settVal); err != nil {
|
|
||||||
logger.Error("redis添加系统设置失败", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DbModels.LineSystemSetting{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 循环取消订单
|
// 循环取消订单
|
||||||
func CancelOpenOrderByOrderSnLoop(apiInfo DbModels.LineApiUser, symbol string, orderSn string) error {
|
func CancelOpenOrderByOrderSnLoop(apiInfo DbModels.LineApiUser, symbol string, orderSn string) error {
|
||||||
spotApi := SpotRestApi{}
|
spotApi := SpotRestApi{}
|
||||||
|
|||||||
510
services/binanceservice/strategy_order_service.go
Normal file
510
services/binanceservice/strategy_order_service.go
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
package binanceservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
models2 "go-admin/models"
|
||||||
|
"go-admin/pkg/utility"
|
||||||
|
"go-admin/services/cacheservice"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BinanceStrategyOrderService struct {
|
||||||
|
service.Service
|
||||||
|
Debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否触发波段订单
|
||||||
|
func (e *BinanceStrategyOrderService) TriggerStrategyOrder(exchangeType string) {
|
||||||
|
//现货
|
||||||
|
orderStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategySpotOrderList, exchangeType))
|
||||||
|
if len(orderStrs) > 0 {
|
||||||
|
e.DoJudge(orderStrs, 1, exchangeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
//合约
|
||||||
|
futOrdedrStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType))
|
||||||
|
|
||||||
|
if len(futOrdedrStrs) > 0 {
|
||||||
|
e.DoJudge(futOrdedrStrs, 2, exchangeType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否符合条件
|
||||||
|
func (e *BinanceStrategyOrderService) DoJudge(orderStrs []string, symbolType int, exchangeType string) {
|
||||||
|
db := GetDBConnection()
|
||||||
|
// setting, _ := cacheservice.GetSystemSetting(db)
|
||||||
|
|
||||||
|
for _, orderStr := range orderStrs {
|
||||||
|
var lockKey string
|
||||||
|
orderItem := dto.StrategyOrderRedisList{}
|
||||||
|
err := sonic.Unmarshal([]byte(orderStr), &orderItem)
|
||||||
|
|
||||||
|
if err != nil || orderItem.Symbol == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if symbolType == 1 {
|
||||||
|
lockKey = rediskey.StrategySpotTriggerLock
|
||||||
|
} else {
|
||||||
|
lockKey = rediskey.StrategyFutTriggerLock
|
||||||
|
}
|
||||||
|
|
||||||
|
lock := helper.NewRedisLock(fmt.Sprintf(lockKey, orderItem.ApiId, orderItem.OrderSn), 60, 20, 300*time.Millisecond)
|
||||||
|
|
||||||
|
if ok, err := lock.AcquireWait(context.Background()); err != nil {
|
||||||
|
e.Log.Debug("获取锁失败", err)
|
||||||
|
return
|
||||||
|
} else if ok {
|
||||||
|
defer lock.Release()
|
||||||
|
|
||||||
|
//判断是否符合条件
|
||||||
|
success, err := e.JudgeStrategy(orderItem, symbolType, exchangeType)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("order_id:%d err:%v", orderItem.Id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Debug || success {
|
||||||
|
e.TriggerOrder(db, orderStr, orderItem, symbolType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否符合触发条件
|
||||||
|
func (e *BinanceStrategyOrderService) JudgeStrategy(order dto.StrategyOrderRedisList, symbolType int, exchangeType string) (bool, error) {
|
||||||
|
var symbolKey string
|
||||||
|
result := false
|
||||||
|
nowUtc := time.Now().UnixMilli()
|
||||||
|
|
||||||
|
switch symbolType {
|
||||||
|
case 1:
|
||||||
|
symbolKey = fmt.Sprintf(rediskey.SpotTickerLastPrice, exchangeType, order.Symbol)
|
||||||
|
case 2:
|
||||||
|
symbolKey = fmt.Sprintf(rediskey.FutureTickerLastPrice, exchangeType, order.Symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastUtc := nowUtc - (int64(order.TimeSlotStart) * 60 * 1000)
|
||||||
|
beforePrice, _ := helper.DefaultRedis.GetNextAfterScore(symbolKey, float64(lastUtc))
|
||||||
|
lastPrices, _ := helper.DefaultRedis.GetLastSortSet(symbolKey)
|
||||||
|
|
||||||
|
if beforePrice == "" || len(lastPrices) == 0 {
|
||||||
|
return result, errors.New("获取交易对起止价格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
score := lastPrices[0].Score
|
||||||
|
var startPrice decimal.Decimal
|
||||||
|
var lastPrice decimal.Decimal
|
||||||
|
startPriceArgs := strings.Split(beforePrice, ":")
|
||||||
|
endPricecArgs := strings.Split(lastPrices[0].Member.(string), ":")
|
||||||
|
|
||||||
|
if len(startPriceArgs) == 0 || len(endPricecArgs) == 0 {
|
||||||
|
return result, errors.New("获取交易对起止价格失败")
|
||||||
|
}
|
||||||
|
startPrice = utility.StrToDecimal(startPriceArgs[len(startPriceArgs)-1])
|
||||||
|
lastPrice = utility.StrToDecimal(endPricecArgs[len(endPricecArgs)-1])
|
||||||
|
|
||||||
|
//时间差超过10s
|
||||||
|
if (nowUtc-int64(score))/1000 > 10 {
|
||||||
|
return result, fmt.Errorf("时间差超过 %ss", "10")
|
||||||
|
}
|
||||||
|
|
||||||
|
if startPrice.Cmp(decimal.Zero) == 0 || lastPrice.Cmp(decimal.Zero) == 0 {
|
||||||
|
return result, errors.New("获取交易对起止价格有一个为0")
|
||||||
|
}
|
||||||
|
|
||||||
|
percentag := lastPrice.Div(startPrice).Sub(decimal.NewFromInt(1)).Truncate(6)
|
||||||
|
logger.Infof("百分比:%s", percentag.Mul(decimal.NewFromInt(100)).String())
|
||||||
|
//价格没有变动
|
||||||
|
if percentag.Cmp(decimal.Zero) == 0 {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//满足条件
|
||||||
|
switch {
|
||||||
|
//涨价格大于0.5% 跌价格小于-0.5%
|
||||||
|
case order.CompareType == 1 && order.Direction == 1 && percentag.Cmp(decimal.Zero) > 0,
|
||||||
|
order.CompareType == 1 && order.Direction == 2 && percentag.Cmp(decimal.Zero) < 0:
|
||||||
|
result = percentag.Abs().Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) > 0
|
||||||
|
|
||||||
|
case order.CompareType == 2 && order.Direction == 1 && percentag.Cmp(decimal.Zero) > 0,
|
||||||
|
order.CompareType == 2 && order.Direction == 2 && percentag.Cmp(decimal.Zero) < 0:
|
||||||
|
result = percentag.Abs().Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) >= 0
|
||||||
|
|
||||||
|
case order.CompareType == 5 && order.Direction == 1 && percentag.Cmp(decimal.Zero) > 0,
|
||||||
|
order.CompareType == 5 && order.Direction == 2 && percentag.Cmp(decimal.Zero) < 0:
|
||||||
|
result = percentag.Abs().Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发委托单
|
||||||
|
func (e *BinanceStrategyOrderService) TriggerOrder(db *gorm.DB, cacheVal string, order dto.StrategyOrderRedisList, symbolType int) error {
|
||||||
|
orders := make([]models.LinePreOrder, 0)
|
||||||
|
if err := e.Orm.Model(&models.LinePreOrder{}).Where("main_id =? or id =?", order.Id, order.Id).Find(&orders).Error; err != nil {
|
||||||
|
e.Log.Errorf("order_id:%d 获取委托单失败:%s", order.Id, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
setting, _ := cacheservice.GetSystemSetting(e.Orm)
|
||||||
|
|
||||||
|
if setting.Id == 0 {
|
||||||
|
return errors.New("获取系统设置失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
var tradeSet models2.TradeSet
|
||||||
|
|
||||||
|
switch symbolType {
|
||||||
|
case 1:
|
||||||
|
tradeSet, _ = cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 0)
|
||||||
|
case 2:
|
||||||
|
tradeSet, _ = cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1)
|
||||||
|
default:
|
||||||
|
return errors.New("获取交易对行情失败,交易对类型错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tradeSet.Coin == "" {
|
||||||
|
return errors.New("获取交易对行情失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPrice := utility.StrToDecimal(tradeSet.LastPrice)
|
||||||
|
|
||||||
|
if lastPrice.Cmp(decimal.Zero) <= 0 {
|
||||||
|
return errors.New("最新成交价小于等于0")
|
||||||
|
}
|
||||||
|
|
||||||
|
mainOrder := models.LinePreOrder{}
|
||||||
|
|
||||||
|
for _, v := range orders {
|
||||||
|
if v.MainId == 0 {
|
||||||
|
mainOrder = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mainOrder.Id == 0 {
|
||||||
|
return errors.New("获取主单失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
GetOrderByPid(&mainOrder, orders, mainOrder.Id)
|
||||||
|
|
||||||
|
e.RecalculateOrder(tradeSet, &mainOrder, setting)
|
||||||
|
|
||||||
|
//事务保存
|
||||||
|
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if err1 := tx.Save(&mainOrder).Error; err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range mainOrder.Childs {
|
||||||
|
if err1 := tx.Save(&v).Error; err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v2 := range v.Childs {
|
||||||
|
if err1 := tx.Save(&v2).Error; err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("order_id:%d 波段触发保存委托单失败:%s", mainOrder.Id, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.StrategyOrderPlace(db, cacheVal, mainOrder, tradeSet)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 策略触发订单
|
||||||
|
// cacheVal:缓存值
|
||||||
|
// mainOrder:主订单
|
||||||
|
// tradeSet:交易对行情
|
||||||
|
func (e *BinanceStrategyOrderService) StrategyOrderPlace(db *gorm.DB, cacheVal string, mainOrder models.LinePreOrder, tradeSet models2.TradeSet) {
|
||||||
|
price := utility.StringToDecimal(mainOrder.Price).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
num := utility.StringToDecimal(mainOrder.Num).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
futApi := FutRestApi{}
|
||||||
|
var key string
|
||||||
|
|
||||||
|
switch mainOrder.SymbolType {
|
||||||
|
case 1:
|
||||||
|
key = fmt.Sprintf(rediskey.StrategySpotOrderList, global.EXCHANGE_BINANCE)
|
||||||
|
case 2:
|
||||||
|
key = fmt.Sprintf(rediskey.StrategyFutOrderList, global.EXCHANGE_BINANCE)
|
||||||
|
default:
|
||||||
|
logger.Errorf("id:%d 交易对类型不存在:%d", mainOrder.Id, mainOrder.SymbolType)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params := FutOrderPlace{
|
||||||
|
ApiId: mainOrder.ApiId,
|
||||||
|
Symbol: mainOrder.Symbol,
|
||||||
|
Side: mainOrder.Site,
|
||||||
|
OrderType: mainOrder.MainOrderType,
|
||||||
|
SideType: mainOrder.MainOrderType,
|
||||||
|
Price: price,
|
||||||
|
Quantity: num,
|
||||||
|
NewClientOrderId: mainOrder.OrderSn,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := futApi.OrderPlaceLoop(db, params, 3); err != nil {
|
||||||
|
logger.Error("下单失败", mainOrder.Symbol, " err:", err)
|
||||||
|
if _, err := helper.DefaultRedis.LRem(key, cacheVal); err != nil {
|
||||||
|
logger.Error("删除redis 预下单失败:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := db.Model(&models.LinePreOrder{}).Where("id =? and status='0'", mainOrder.Id).Updates(map[string]interface{}{"status": "2", "desc": err.Error()}).Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("更新预下单状态失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
if _, err := helper.DefaultRedis.LRem(key, cacheVal); err != nil {
|
||||||
|
logger.Error("删除redis 预下单失败:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Model(&models.LinePreOrder{}).Where("id =? ", mainOrder.Id).Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil {
|
||||||
|
logger.Error("更新预下单状态失败 ordersn:", mainOrder.OrderSn, " status:1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Model(&models.LinePreOrder{}).Where("id =? AND status ='0'", mainOrder.Id).Updates(map[string]interface{}{"status": "1"}).Error; err != nil {
|
||||||
|
logger.Error("更新预下单状态失败 ordersn:", mainOrder.OrderSn, " status:1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新计算订单单价、数量
|
||||||
|
// tradeSet 交易对行情
|
||||||
|
// mainOrder 主订单
|
||||||
|
// setting 系统设置
|
||||||
|
func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet, mainOrder *models.LinePreOrder, setting models.LineSystemSetting) error {
|
||||||
|
exts := make([]models.LinePreOrderExt, 0)
|
||||||
|
if err := e.Orm.Model(models.LinePreOrderExt{}).Where("main_order_id =?", mainOrder.Id).Find(&exts).Error; err != nil {
|
||||||
|
return errors.New("获取拓展信息失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
var newPrice decimal.Decimal
|
||||||
|
lastPrice := utility.StrToDecimal(tradeSet.LastPrice)
|
||||||
|
rate := utility.StrToDecimal(mainOrder.Rate)
|
||||||
|
newPrice = lastPrice.Mul(decimal.NewFromInt(1).Add(rate.Div(decimal.NewFromInt(100)).Truncate(4))).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
buyPrice := utility.StrToDecimal(mainOrder.BuyPrice)
|
||||||
|
totalNum := buyPrice.Div(newPrice).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
|
||||||
|
mainOrder.SignPrice = lastPrice.String()
|
||||||
|
mainOrder.Price = newPrice.String()
|
||||||
|
mainOrder.Num = totalNum.String()
|
||||||
|
remainQuantity := totalNum
|
||||||
|
var totalLossAmount decimal.Decimal
|
||||||
|
prePrice := lastPrice
|
||||||
|
|
||||||
|
for index := range mainOrder.Childs {
|
||||||
|
var ext models.LinePreOrderExt
|
||||||
|
extOrderId := mainOrder.Childs[index].Id
|
||||||
|
takeStopArray := []int{1, 2}
|
||||||
|
|
||||||
|
//止盈止损 ext拓展id为 pid
|
||||||
|
if utility.ContainsInt(takeStopArray, mainOrder.Childs[index].OrderType) {
|
||||||
|
extOrderId = mainOrder.Childs[index].Pid
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range exts {
|
||||||
|
if v.OrderId == extOrderId {
|
||||||
|
ext = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ext.Id <= 0 {
|
||||||
|
logger.Errorf("子订单ext不存在 id:%d", mainOrder.Childs[index].Id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//主单止盈、止损
|
||||||
|
if mainOrder.Childs[index].Pid == mainOrder.Childs[index].MainId && (mainOrder.Childs[index].OrderType == 1 || mainOrder.Childs[index].OrderType == 2) {
|
||||||
|
var percent decimal.Decimal
|
||||||
|
|
||||||
|
switch {
|
||||||
|
// 加价
|
||||||
|
case mainOrder.Childs[index].OrderType == 1 && mainOrder.Site == "BUY", mainOrder.Childs[index].OrderType == 2 && mainOrder.Site == "SELL":
|
||||||
|
percent = decimal.NewFromInt(100).Add(ext.TakeProfitRatio)
|
||||||
|
//减价
|
||||||
|
case mainOrder.Childs[index].OrderType == 2 && mainOrder.Site == "BUY", mainOrder.Childs[index].OrderType == 1 && mainOrder.Site == "SELL":
|
||||||
|
percent = decimal.NewFromInt(100).Sub(ext.StopLossRatio)
|
||||||
|
}
|
||||||
|
|
||||||
|
childPrice := lastPrice.Mul(percent.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
mainOrder.Childs[index].Price = childPrice.String()
|
||||||
|
mainOrder.Childs[index].Num = totalNum.String()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
lastNum := remainQuantity
|
||||||
|
|
||||||
|
//过期时间
|
||||||
|
if ext.ExpirateHour <= 0 {
|
||||||
|
mainOrder.Childs[index].ExpireTime = time.Now().AddDate(10, 0, 0)
|
||||||
|
} else {
|
||||||
|
mainOrder.Childs[index].ExpireTime = time.Now().Add(time.Hour * time.Duration(ext.ExpirateHour))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
//加仓单
|
||||||
|
case mainOrder.Childs[index].OrderType == 1 && mainOrder.Childs[index].OrderCategory == 3:
|
||||||
|
var percentage decimal.Decimal
|
||||||
|
|
||||||
|
if mainOrder.Site == "BUY" {
|
||||||
|
percentage = decimal.NewFromInt(1).Sub(ext.PriceRatio.Div(decimal.NewFromInt(100)))
|
||||||
|
} else {
|
||||||
|
percentage = decimal.NewFromInt(1).Add(ext.PriceRatio.Div(decimal.NewFromInt(100)))
|
||||||
|
}
|
||||||
|
|
||||||
|
dataPrice := utility.StrToDecimal(mainOrder.Price).Mul(percentage).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
mainOrder.Childs[index].Price = dataPrice.String()
|
||||||
|
|
||||||
|
priceDiff := dataPrice.Sub(prePrice).Abs()
|
||||||
|
totalLossAmount = totalLossAmount.Add(lastNum.Mul(priceDiff))
|
||||||
|
|
||||||
|
if ext.AddPositionType == 1 {
|
||||||
|
buyPrice := utility.StrToDecimal(mainOrder.BuyPrice).Mul(utility.SafeDiv(ext.AddPositionVal, decimal.NewFromInt(100))).Truncate(2)
|
||||||
|
mainOrder.Childs[index].Num = utility.SafeDiv(buyPrice, dataPrice).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
mainOrder.Childs[index].Num = utility.SafeDiv(ext.AddPositionVal.Truncate(2), dataPrice).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
//加库存
|
||||||
|
lastNum = lastNum.Add(utility.StrToDecimal(mainOrder.Childs[index].Num))
|
||||||
|
// 计算子订单
|
||||||
|
if len(mainOrder.Childs[index].Childs) > 0 {
|
||||||
|
calculateChildOrder(&mainOrder.Childs[index].Childs, &tradeSet, ext, lastNum, dataPrice, totalLossAmount, false)
|
||||||
|
}
|
||||||
|
//覆盖最近的订单价
|
||||||
|
prePrice = dataPrice
|
||||||
|
//减仓单
|
||||||
|
case mainOrder.Childs[index].OrderType == 4:
|
||||||
|
percentage := decimal.NewFromInt(1)
|
||||||
|
|
||||||
|
if mainOrder.Site == "BUY" && ext.PriceRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
percentage = decimal.NewFromInt(1).Sub(ext.PriceRatio.Div(decimal.NewFromInt(100)))
|
||||||
|
} else if ext.PriceRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
percentage = decimal.NewFromInt(1).Add(ext.PriceRatio.Div(decimal.NewFromInt(100)))
|
||||||
|
}
|
||||||
|
|
||||||
|
dataPrice := utility.StrToDecimal(mainOrder.Price).Mul(percentage).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
mainOrder.Childs[index].Price = dataPrice.String()
|
||||||
|
priceDiff := dataPrice.Sub(prePrice).Abs()
|
||||||
|
totalLossAmount = totalLossAmount.Add(lastNum.Mul(priceDiff))
|
||||||
|
|
||||||
|
//百分比减仓
|
||||||
|
if ext.AddPositionType == 1 {
|
||||||
|
mainOrder.Childs[index].Num = lastNum.Mul(ext.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logger.Error("减仓不能是固定数值")
|
||||||
|
}
|
||||||
|
|
||||||
|
//减库存
|
||||||
|
lastNum = lastNum.Sub(utility.StrToDecimal(mainOrder.Childs[index].Num))
|
||||||
|
// 计算子订单
|
||||||
|
if len(mainOrder.Childs[index].Childs) > 0 {
|
||||||
|
calculateChildOrder(&mainOrder.Childs[index].Childs, &tradeSet, ext, lastNum, dataPrice, totalLossAmount, false)
|
||||||
|
}
|
||||||
|
//覆盖最近的订单价
|
||||||
|
prePrice = dataPrice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算子订单信息
|
||||||
|
// isTpTp 是否是止盈后止损止盈
|
||||||
|
// totalLossAmount 累计亏损金额
|
||||||
|
func calculateChildOrder(orders *[]models.LinePreOrder, tradeSet *models2.TradeSet, ext models.LinePreOrderExt, lastNum decimal.Decimal, price decimal.Decimal, totalLossAmount decimal.Decimal, isTpTp bool) error {
|
||||||
|
for index := range *orders {
|
||||||
|
orderQuantity := lastNum.Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
percentage := decimal.NewFromInt(1)
|
||||||
|
var addPercentage decimal.Decimal
|
||||||
|
|
||||||
|
switch {
|
||||||
|
//止盈
|
||||||
|
case !isTpTp && (*orders)[index].OrderType == 1:
|
||||||
|
addPercentage = ext.TakeProfitRatio
|
||||||
|
if ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 {
|
||||||
|
orderQuantity = lastNum.Mul(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
}
|
||||||
|
//止损
|
||||||
|
case !isTpTp && (*orders)[index].OrderType == 2:
|
||||||
|
addPercentage = ext.StopLossRatio
|
||||||
|
//止盈后止盈
|
||||||
|
case isTpTp && (*orders)[index].OrderType == 1:
|
||||||
|
addPercentage = ext.TpTpPriceRatio
|
||||||
|
//止盈后止损
|
||||||
|
case isTpTp && (*orders)[index].OrderType == 2:
|
||||||
|
addPercentage = ext.TpSlPriceRatio
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
//做多止盈、做空止损
|
||||||
|
case (*orders)[index].OrderType == 1 && (*orders)[index].Site == "SELL", (*orders)[index].OrderType == 2 && (*orders)[index].Site == "BUY":
|
||||||
|
percentage = decimal.NewFromInt(100).Add(addPercentage)
|
||||||
|
|
||||||
|
//做多止损、做空止盈
|
||||||
|
case (*orders)[index].OrderType == 2 && (*orders)[index].Site == "SELL", (*orders)[index].OrderType == 1 && (*orders)[index].Site == "BUY":
|
||||||
|
percentage = decimal.NewFromInt(100).Sub(addPercentage)
|
||||||
|
}
|
||||||
|
|
||||||
|
//止盈亏损回本百分比
|
||||||
|
if (*orders)[index].OrderType == 1 && totalLossAmount.Cmp(decimal.Zero) > 0 {
|
||||||
|
lossPercent := totalLossAmount.Div(lastNum).Mul(decimal.NewFromInt(100)).Truncate(2)
|
||||||
|
percentage = percentage.Add(lossPercent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if percentage.Cmp(decimal.Zero) > 0 {
|
||||||
|
percentage = percentage.Div(decimal.NewFromInt(100))
|
||||||
|
}
|
||||||
|
|
||||||
|
orderPrice := price.Mul(percentage).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
(*orders)[index].Price = orderPrice.String()
|
||||||
|
(*orders)[index].Num = orderQuantity.String()
|
||||||
|
lastOrderQuantity := lastNum.Sub(orderQuantity).Truncate(int32(tradeSet.AmountDigit))
|
||||||
|
|
||||||
|
//止盈后止盈、止盈后止损
|
||||||
|
if len((*orders)[index].Childs) > 0 && lastOrderQuantity.Cmp(decimal.Zero) > 0 {
|
||||||
|
calculateChildOrder(&(*orders)[index].Childs, tradeSet, ext, lastOrderQuantity, orderPrice, decimal.Zero, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归订单树
|
||||||
|
func GetOrderByPid(order *models.LinePreOrder, orders []models.LinePreOrder, pid int) {
|
||||||
|
for _, v := range orders {
|
||||||
|
if v.Pid == pid {
|
||||||
|
GetOrderByPid(&v, orders, v.Id)
|
||||||
|
|
||||||
|
order.Childs = append(order.Childs, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
services/binanceservice/strategy_order_service_test.go
Normal file
26
services/binanceservice/strategy_order_service_test.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package binanceservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/helper"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 测试策略 触发单
|
||||||
|
func TestTriggerOrder(t *testing.T) {
|
||||||
|
service := BinanceStrategyOrderService{}
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
helper.InitDefaultRedis("127.0.0.1:6379", "", 2)
|
||||||
|
helper.InitLockRedisConn("127.0.0.1:6379", "", "2")
|
||||||
|
sdk.Runtime.SetDb("default", db)
|
||||||
|
|
||||||
|
service.Orm = db
|
||||||
|
service.Debug = true
|
||||||
|
|
||||||
|
service.TriggerStrategyOrder(global.EXCHANGE_BINANCE)
|
||||||
|
}
|
||||||
@ -1,10 +1,13 @@
|
|||||||
package cacheservice
|
package cacheservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/common/const/rediskey"
|
"go-admin/common/const/rediskey"
|
||||||
|
"go-admin/common/global"
|
||||||
"go-admin/common/helper"
|
"go-admin/common/helper"
|
||||||
|
models2 "go-admin/models"
|
||||||
|
|
||||||
"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"
|
||||||
@ -59,3 +62,71 @@ func GetConfigCacheByKey(db *gorm.DB, key string) models.SysConfig {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取缓存交易对
|
||||||
|
// symbolType 0-现货 1-合约
|
||||||
|
func GetTradeSet(exchangeType string, symbol string, symbolType int) (models2.TradeSet, error) {
|
||||||
|
// 定义返回结果和val变量
|
||||||
|
result := models2.TradeSet{}
|
||||||
|
val := ""
|
||||||
|
|
||||||
|
// 根据交易对类型选择不同的key
|
||||||
|
switch symbolType {
|
||||||
|
case 0:
|
||||||
|
key := fmt.Sprintf(global.TICKER_SPOT, exchangeType, symbol)
|
||||||
|
val, _ = helper.DefaultRedis.GetString(key)
|
||||||
|
case 1:
|
||||||
|
key := fmt.Sprintf(global.TICKER_FUTURES, exchangeType, symbol)
|
||||||
|
val, _ = helper.DefaultRedis.GetString(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果val不为空,则解析val为TradeSet结构体
|
||||||
|
if val != "" {
|
||||||
|
if err := sonic.Unmarshal([]byte(val), &result); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果val为空,则返回错误信息
|
||||||
|
return result, errors.New("未找到交易对信息")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回结果
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSystemSetting(db *gorm.DB) (models.LineSystemSetting, error) {
|
||||||
|
key := fmt.Sprintf(rediskey.SystemSetting)
|
||||||
|
val, _ := helper.DefaultRedis.GetString(key)
|
||||||
|
setting := models.LineSystemSetting{}
|
||||||
|
|
||||||
|
if val != "" {
|
||||||
|
sonic.UnmarshalString(val, &setting)
|
||||||
|
}
|
||||||
|
|
||||||
|
if setting.Id > 0 {
|
||||||
|
return setting, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
setting, err = ResetSystemSetting(db)
|
||||||
|
if err != nil {
|
||||||
|
return setting, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return setting, nil
|
||||||
|
}
|
||||||
|
func ResetSystemSetting(db *gorm.DB) (models.LineSystemSetting, error) {
|
||||||
|
setting := models.LineSystemSetting{}
|
||||||
|
if err := db.Model(&setting).First(&setting).Error; err != nil {
|
||||||
|
return setting, err
|
||||||
|
}
|
||||||
|
|
||||||
|
settVal, _ := sonic.MarshalString(&setting)
|
||||||
|
|
||||||
|
if settVal != "" {
|
||||||
|
if err := helper.DefaultRedis.SetString(rediskey.SystemSetting, settVal); err != nil {
|
||||||
|
logger.Error("redis添加系统设置失败", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return models.LineSystemSetting{}, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go-admin/common/const/rediskey"
|
||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/helper"
|
"go-admin/common/helper"
|
||||||
"go-admin/config"
|
"go-admin/config"
|
||||||
@ -15,6 +16,7 @@ import (
|
|||||||
"go-admin/models"
|
"go-admin/models"
|
||||||
|
|
||||||
log "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/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -133,7 +135,19 @@ func handleTickerAllMessage(msg []byte) {
|
|||||||
// log.Debug(symbol, "ticker@all ws处理失败", err)
|
// log.Debug(symbol, "ticker@all ws处理失败", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tradeSet.LastPrice = utility.StringFloat64Cut(data["c"].(string), int32(tradeSet.PriceDigit))
|
var utcTime int64
|
||||||
|
var lastPrice decimal.Decimal
|
||||||
|
lastPriceKey := fmt.Sprintf(rediskey.FutureTickerLastPrice, global.EXCHANGE_BINANCE, symbol)
|
||||||
|
|
||||||
|
if e, ok := data["E"]; ok {
|
||||||
|
utcTime = utility.ToInt64(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e, ok := data["c"]; ok {
|
||||||
|
lastPrice = utility.StrToDecimal(e.(string)).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
}
|
||||||
|
|
||||||
|
tradeSet.LastPrice = lastPrice.String()
|
||||||
tradeSet.OpenPrice = utility.StrToFloatCut(data["o"].(string), int32(tradeSet.PriceDigit))
|
tradeSet.OpenPrice = utility.StrToFloatCut(data["o"].(string), int32(tradeSet.PriceDigit))
|
||||||
tradeSet.HighPrice = utility.StringFloat64Cut(data["h"].(string), int32(tradeSet.PriceDigit))
|
tradeSet.HighPrice = utility.StringFloat64Cut(data["h"].(string), int32(tradeSet.PriceDigit))
|
||||||
tradeSet.LowPrice = utility.StringFloat64Cut(data["l"].(string), int32(tradeSet.PriceDigit))
|
tradeSet.LowPrice = utility.StringFloat64Cut(data["l"].(string), int32(tradeSet.PriceDigit))
|
||||||
@ -147,6 +161,21 @@ func handleTickerAllMessage(msg []byte) {
|
|||||||
log.Error(symbol, "ticker@all ws处理失败", err)
|
log.Error(symbol, "ticker@all ws处理失败", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val, _ := helper.DefaultRedis.GetAllList(rediskey.CacheSymbolLastPrice)
|
||||||
|
|
||||||
|
if utility.ContainsStr(val, symbol) {
|
||||||
|
//行情存储时间
|
||||||
|
lastUtc := utcTime - 1000*60*60
|
||||||
|
content := fmt.Sprintf("%d:%s", utcTime, lastPrice.String())
|
||||||
|
if _, err := helper.DefaultRedis.RemoveBeforeScore(lastPriceKey, float64(lastUtc)); err != nil {
|
||||||
|
log.Errorf("移除 合约交易对:%s %d之前的最新成交价失败,err:%v", symbol, lastUtc, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := helper.DefaultRedis.AddSortSet(lastPriceKey, float64(utcTime), content); err != nil {
|
||||||
|
log.Errorf("添加 合约交易对:%s %d之前的最新成交价失败,err:%v", symbol, lastUtc, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(trades) > 0 {
|
if len(trades) > 0 {
|
||||||
|
|||||||
@ -204,6 +204,7 @@ func handleTickerMessage(msg []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
key := fmt.Sprintf(global.TICKER_SPOT, global.EXCHANGE_BINANCE, symbolName)
|
key := fmt.Sprintf(global.TICKER_SPOT, global.EXCHANGE_BINANCE, symbolName)
|
||||||
|
lastPriceKey := fmt.Sprintf(rediskey.SpotTickerLastPrice, global.EXCHANGE_BINANCE, symbolName)
|
||||||
tcVal, _ := helper.DefaultRedis.GetString(key)
|
tcVal, _ := helper.DefaultRedis.GetString(key)
|
||||||
tradeSet := models.TradeSet{}
|
tradeSet := models.TradeSet{}
|
||||||
if err := sonic.UnmarshalString(tcVal, &tradeSet); err != nil {
|
if err := sonic.UnmarshalString(tcVal, &tradeSet); err != nil {
|
||||||
@ -212,7 +213,19 @@ func handleTickerMessage(msg []byte) {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tradeSet.LastPrice = utility.StringFloat64Cut(dataMap["c"].(string), int32(tradeSet.PriceDigit))
|
|
||||||
|
var utcTime int64
|
||||||
|
var lastPrice decimal.Decimal
|
||||||
|
|
||||||
|
if e, ok := dataMap["E"]; ok {
|
||||||
|
utcTime = utility.ToInt64(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e, ok := dataMap["c"]; ok {
|
||||||
|
lastPrice = utility.StrToDecimal(e.(string)).Truncate(int32(tradeSet.PriceDigit))
|
||||||
|
}
|
||||||
|
|
||||||
|
tradeSet.LastPrice = lastPrice.String()
|
||||||
tradeSet.OpenPrice = utility.StrToFloatCut(dataMap["o"].(string), int32(tradeSet.PriceDigit))
|
tradeSet.OpenPrice = utility.StrToFloatCut(dataMap["o"].(string), int32(tradeSet.PriceDigit))
|
||||||
tradeSet.HighPrice = utility.StringFloat64Cut(dataMap["h"].(string), int32(tradeSet.PriceDigit))
|
tradeSet.HighPrice = utility.StringFloat64Cut(dataMap["h"].(string), int32(tradeSet.PriceDigit))
|
||||||
tradeSet.LowPrice = utility.StringFloat64Cut(dataMap["l"].(string), int32(tradeSet.PriceDigit))
|
tradeSet.LowPrice = utility.StringFloat64Cut(dataMap["l"].(string), int32(tradeSet.PriceDigit))
|
||||||
@ -236,6 +249,22 @@ func handleTickerMessage(msg []byte) {
|
|||||||
log.Error("redis保存交易对失败", tradeSet.Coin, tradeSet.Currency)
|
log.Error("redis保存交易对失败", tradeSet.Coin, tradeSet.Currency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val, _ := helper.DefaultRedis.GetAllList(rediskey.CacheSymbolLastPrice)
|
||||||
|
|
||||||
|
if utility.ContainsStr(val, symbolName) {
|
||||||
|
//行情存储时间
|
||||||
|
lastUtc := utcTime - 1000*60*60
|
||||||
|
content := fmt.Sprintf("%d:%s", utcTime, lastPrice.String())
|
||||||
|
|
||||||
|
if _, err := helper.DefaultRedis.RemoveBeforeScore(lastPriceKey, float64(lastUtc)); err != nil {
|
||||||
|
log.Errorf("移除 现货交易对:%s %d之前的最新成交价失败,err:%v", symbolName, lastUtc, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := helper.DefaultRedis.AddSortSet(lastPriceKey, float64(utcTime), content); err != nil {
|
||||||
|
log.Errorf("添加 现货交易对:%s %d之前的最新成交价失败,err:%v", symbolName, lastUtc, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断触发现货下单
|
//判断触发现货下单
|
||||||
|
|||||||
Reference in New Issue
Block a user