1、减仓策略
2、减仓后减仓节点(60%)
This commit is contained in:
		
							
								
								
									
										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(), "删除成功") | ||||
| } | ||||
							
								
								
									
										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 | ||||
| } | ||||
| @ -11,7 +11,6 @@ type LinePreOrder struct { | ||||
| 	models.Model | ||||
| 	ExchangeType         string          `json:"exchangeType" gorm:"type:varchar(20);comment:交易所类型 (字典 exchange_type)"` | ||||
| 	StrategyTemplateType int             `json:"strategyTemplateType" gorm:"type:tinyint;comment:策略类型 0-无 1-波段涨跌幅"` | ||||
| 	StrategyTemplateId   int             `json:"strategyTemplateId" gorm:"type:bigint;comment:策略模板id"` | ||||
| 	Pid                  int             `json:"pid" gorm:"type:int unsigned;omitempty;comment:pid"` | ||||
| 	MainId               int             `json:"mainId" gorm:"type:int;comment:主单id"` | ||||
| 	ApiId                int             `json:"apiId" gorm:"type:varchar(255);omitempty;comment:api用户"` | ||||
| @ -43,6 +42,8 @@ type LinePreOrder struct { | ||||
| 	AddPositionStatus    int             `json:"add_position_status" gorm:"->"` | ||||
| 	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 线上预埋单\ | ||||
| 	models.ModelTime | ||||
| 	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 | ||||
| } | ||||
							
								
								
									
										31
									
								
								app/admin/models/line_reduce_strategy_item.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								app/admin/models/line_reduce_strategy_item.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| 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:亏损百分比"` | ||||
| 	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 { | ||||
| 	models.Model | ||||
|  | ||||
| 	Time                int64           `json:"time" gorm:"type:int;comment:导入:挂单时长达到时间后失效"` | ||||
| 	BatchTime           int64           `json:"batchTime" gorm:"type:int;comment:批量:挂单时长达到时间后失效"` | ||||
| 	ProfitRate          string          `json:"profitRate" gorm:"type:decimal(10,2);comment:平仓盈利比例"` | ||||
| 	CoverOrderTypeBRate string          `json:"coverOrderTypeBRate" gorm:"type:decimal(10,2);comment:b账户限价补单的买入百分比"` | ||||
| 	StopLossPremium     decimal.Decimal `json:"stopLossPremium" 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:限价减仓溢价百分比"` | ||||
| 	Time                      int64           `json:"time" gorm:"type:int;comment:导入:挂单时长达到时间后失效"` | ||||
| 	BatchTime                 int64           `json:"batchTime" gorm:"type:int;comment:批量:挂单时长达到时间后失效"` | ||||
| 	ProfitRate                string          `json:"profitRate" gorm:"type:decimal(10,2);comment:平仓盈利比例"` | ||||
| 	CoverOrderTypeBRate       string          `json:"coverOrderTypeBRate" gorm:"type:decimal(10,2);comment:b账户限价补单的买入百分比"` | ||||
| 	StopLossPremium           decimal.Decimal `json:"stopLossPremium" 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:限价减仓溢价百分比"` | ||||
| 	ReduceEarlyTriggerPercent decimal.Decimal `json:"reduceEarlyTriggerPercent" gorm:"type:decimal(10,2);comment:减仓提前触发百分比"` | ||||
| 	models.ModelTime | ||||
| 	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) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										19
									
								
								app/admin/service/dto/line_order_reduce_strategy.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/admin/service/dto/line_order_reduce_strategy.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| package dto | ||||
|  | ||||
| import "github.com/shopspring/decimal" | ||||
|  | ||||
| type LineOrderReduceStrategyResp struct { | ||||
| 	OrderId int                               `json:"orderId"` | ||||
| 	Symbol  string                            `json:"symbol"` | ||||
| 	Side    string                            `json:"side" comment:"BUY SELL"` | ||||
| 	Items   []LineOrderReduceStrategyRespItem `json:"items"` | ||||
| } | ||||
|  | ||||
| // 减仓节点 | ||||
| type LineOrderReduceStrategyRespItem struct { | ||||
| 	Price        decimal.Decimal `json:"p" 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:"是否触发 "` | ||||
| } | ||||
| @ -188,6 +188,7 @@ type LineAddPreOrderReq struct { | ||||
| 	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"`                  //订单类型 | ||||
| 	Symbol                  string          `json:"symbol"`                      //交易对 | ||||
| 	ApiUserId               string          `json:"api_id" `                     //下单用户 | ||||
| @ -201,6 +202,7 @@ type LineAddPreOrderReq struct { | ||||
| 	ProfitNumRatio          decimal.Decimal `json:"profit_num_ratio"`            //止盈数量百分比 | ||||
| 	ProfitTpTpPriceRatio    decimal.Decimal `json:"profit_tp_tp_price_ratio"`    //止盈后止盈价百分比 | ||||
| 	ProfitTpSlPriceRatio    decimal.Decimal `json:"profit_tp_sl_price_ratio"`    //止盈后止损价百分比 | ||||
| 	StopLoss                decimal.Decimal `json:"stop_loss"`                   //止损价 | ||||
| 	PriceType               string          `json:"price_type"`                  //价格类型 | ||||
| 	SaveTemplate            string          `json:"save_template"`               //是否保存模板 | ||||
| 	TemplateName            string          `json:"template_name"`               //模板名字 | ||||
| @ -324,7 +326,9 @@ func (req LineAddPreOrderReq) Valid() error { | ||||
| 			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("止盈价格不正确") | ||||
| 		} | ||||
|  | ||||
| @ -474,7 +478,9 @@ func (req LineBatchAddPreOrderReq) CheckParams() error { | ||||
| 			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("止盈价格不正确") | ||||
| 		} | ||||
|  | ||||
| @ -569,6 +575,17 @@ type PreOrderRedisList struct { | ||||
| 	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 { | ||||
| 	Id            int             `json:"id"` | ||||
| 	PId           int             `json:"pid"`    //父级id | ||||
|  | ||||
							
								
								
									
										157
									
								
								app/admin/service/dto/line_reduce_strategy.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								app/admin/service/dto/line_reduce_strategy.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,157 @@ | ||||
| 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].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 | ||||
|  | ||||
| 		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 | ||||
|  | ||||
| 		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 | ||||
| } | ||||
							
								
								
									
										125
									
								
								app/admin/service/dto/line_reduce_strategy_item.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								app/admin/service/dto/line_reduce_strategy_item.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | ||||
| 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:"止损百分比"` | ||||
| 	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") | ||||
| 	} | ||||
|  | ||||
| 	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 || s.TimeSlotEnd > 59 { | ||||
| 		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 || s.TimeSlotEnd > 59 { | ||||
| 		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:"基础货币"` | ||||
| 	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:"交易对类型"` | ||||
| 	// StrategyTemplateId int    `form:"strategyTemplateId" search:"-" comment:"策略id"` | ||||
| 	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 | ||||
| } | ||||
| @ -11,6 +11,7 @@ import ( | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/pkg/utility/snowflakehelper" | ||||
| 	"go-admin/services/binanceservice" | ||||
| 	"go-admin/services/cacheservice" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| @ -403,6 +404,15 @@ func (e *LinePreOrder) AddPreOrderCheck(req *dto.LineAddPreOrderReq, p *actions. | ||||
| 		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) | ||||
|  | ||||
| 	if len(activeApiIds) == 0 { | ||||
| @ -438,6 +448,17 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 		saveTemplateParams.CreateBy = req.CreateBy | ||||
| 		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" { | ||||
| 		return nil | ||||
| 	} | ||||
| @ -461,13 +482,13 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 		} | ||||
| 		var AddOrder models.LinePreOrder | ||||
| 		var profitOrder models.LinePreOrder | ||||
| 		var stopOrder models.LinePreOrder | ||||
| 		var reduceOrder models.LinePreOrder | ||||
|  | ||||
| 		//获取交易对 | ||||
| 		tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key) | ||||
| 		tickerPrice := utility.StrToDecimal(tradeSet.LastPrice) | ||||
| 		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 | ||||
| 		} | ||||
|  | ||||
| @ -540,7 +561,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 			AddOrder.Num = utility.SafeDiv(buyPrice, fromString).Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 		} | ||||
| 		if utility.StringToFloat64(AddOrder.Num) < tradeSet.MinQty { | ||||
| 			*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 小于最小下单数量", id, req.Symbol)) | ||||
| 			*errs = append(*errs, fmt.Errorf("api_id:%d 获取交易对:%s 小于最小下单数量", id, req.Symbol)) | ||||
| 			continue | ||||
| 		} | ||||
| 		AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) | ||||
| @ -551,7 +572,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 		AddOrder.GroupId = "0" | ||||
| 		AddOrder.Status = 0 | ||||
| 		copier.Copy(&profitOrder, &AddOrder) | ||||
| 		copier.Copy(&stopOrder, &AddOrder) | ||||
| 		copier.Copy(&reduceOrder, &AddOrder) | ||||
|  | ||||
| 		preOrderStatus := models.LinePreOrderStatus{} | ||||
| 		preOrderStatus.OrderSn = AddOrder.OrderSn | ||||
| @ -565,6 +586,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 			OrderType:          req.PriceType, | ||||
| 			TakeProfitRatio:    utility.StringToDecimal(req.Profit), | ||||
| 			TakeProfitNumRatio: req.ProfitNumRatio, | ||||
| 			StopLossRatio:      req.StopLoss, | ||||
| 			TpTpPriceRatio:     req.ProfitTpTpPriceRatio, | ||||
| 			TpSlPriceRatio:     req.ProfitTpSlPriceRatio, | ||||
| 		} | ||||
| @ -584,7 +606,6 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 		defultExt.TotalAfter = utility.StrToDecimal(AddOrder.Num).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		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)) | ||||
| 		defultExt2.TotalAfter = mainAmount.Mul(default2NumPercent).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		defultExt2.ReTakeRatio = utility.SafeDiv(req.ReducePriceRatio, default2NumPercent).Truncate(2) | ||||
| @ -614,7 +635,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 		mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU   //buyPrice.Mul(req.ReducePriceRatio.Div(decimal.NewFromInt(100)).Truncate(4)).Truncate(int32(tradeSet.PriceDigit)) | ||||
| 		req.ReduceReTakeProfitRatio = calculateResp.Ratio | ||||
| 		mainParam.LossBeginPercent = req.ReducePriceRatio | ||||
| 		defultExt.ReTakeRatio = calculateResp.Ratio | ||||
| 		// defultExt.ReTakeRatio = calculateResp.Ratio | ||||
|  | ||||
| 		for index, addPosition := range req.Ext { | ||||
| 			ext := models.LinePreOrderExt{ | ||||
| @ -651,11 +672,20 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 			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 { | ||||
| 			reduceOrderStrategys := make([]models.LineOrderReduceStrategy, 0) | ||||
| 			err := tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&AddOrder).Error | ||||
| 			if err != nil { | ||||
| 				*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", id, req.Symbol)) | ||||
| 				*errs = append(*errs, fmt.Errorf("api_id:%d 获取交易对:%s 生成订单失败", id, req.Symbol)) | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| @ -664,117 +694,72 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 			//加仓、减仓状态 | ||||
| 			tx.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus) | ||||
| 			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)) | ||||
|  | ||||
| 			//是否有止盈止损订单 | ||||
| 			if req.Profit != "" { | ||||
| 				if req.PricePattern == "mixture" { | ||||
| 					mixturePrice := utility.StrToDecimal(req.Profit) | ||||
| 			childOrders, err := makeFuturesTakeAndReduce(&AddOrder, defultExt, tradeSet) | ||||
|  | ||||
| 					if mixturePrice.Cmp(decimal.Zero) <= 0 { | ||||
| 						return fmt.Errorf("止盈价不能小于等于0") | ||||
| 					} | ||||
|  | ||||
| 					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 err != nil { | ||||
| 				logger.Errorf("构建主单止盈止损失败,err:%v", err) | ||||
| 			} | ||||
|  | ||||
| 			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.PricePattern == "mixture" { | ||||
| 					if req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 { | ||||
| 						return errors.New("检查价格不能小于等于0") | ||||
| 					} | ||||
|  | ||||
| 					stopOrder.Price = req.ReducePriceRatio.Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					stopOrder.Rate = "0" | ||||
| 					reduceOrder.Price = req.ReducePriceRatio.Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					reduceOrder.Rate = "0" | ||||
| 				} else { | ||||
| 					if strings.ToUpper(req.Site) == "BUY" { | ||||
| 						// 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 { | ||||
| 						// 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" { | ||||
| 					stopOrder.Site = "SELL" | ||||
| 					reduceOrder.Site = "SELL" | ||||
| 				} else { | ||||
| 					stopOrder.Site = "BUY" | ||||
| 					reduceOrder.Site = "BUY" | ||||
| 				} | ||||
| 				stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) | ||||
| 				stopOrder.Pid = AddOrder.Id | ||||
| 				stopOrder.MainId = AddOrder.Id | ||||
| 				stopOrder.OrderType = 4 | ||||
| 				stopOrder.Status = 0 | ||||
| 				stopOrder.BuyPrice = "0" | ||||
| 				reduceOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) | ||||
| 				reduceOrder.Pid = AddOrder.Id | ||||
| 				reduceOrder.MainId = AddOrder.Id | ||||
| 				reduceOrder.OrderType = 4 | ||||
| 				reduceOrder.Status = 0 | ||||
| 				reduceOrder.BuyPrice = "0" | ||||
| 				stopNum := utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4)) | ||||
| 				stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 				stopOrder.ExpireTime = time.Now().AddDate(10, 0, 0) | ||||
| 				reduceOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 				reduceOrder.ExpireTime = time.Now().AddDate(10, 0, 0) | ||||
|  | ||||
| 				tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&stopOrder) | ||||
| 				preOrderExts[1].OrderId = stopOrder.Id | ||||
| 				tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&reduceOrder) | ||||
| 				preOrderExts[1].OrderId = reduceOrder.Id | ||||
| 				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) | ||||
| 						return err | ||||
| 					} else if len(newOrders) > 0 { | ||||
| @ -784,9 +769,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 { | ||||
| 				preOrderExts[index].MainOrderId = AddOrder.Id | ||||
| 				if index < 2 { | ||||
| @ -825,7 +814,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, apiUserIds []int | ||||
| 				} | ||||
|  | ||||
| 				for index := range orders { | ||||
| 					//减仓单且 减仓比例大于0 小于100 就冲下止盈止损 | ||||
| 					//止盈后止盈止损 | ||||
| 					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) | ||||
|  | ||||
| @ -844,19 +833,113 @@ 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 | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
|  | ||||
| 			//保存下单缓存 | ||||
| 			return saveOrderCache(req, AddOrder, linestrategyTemplate) | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
| 		list.TimeSlotEnd = linestrategyTemplate.TimeSlotEnd | ||||
|  | ||||
| 		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 { | ||||
| 	data := models.LinePreOrder{} | ||||
| @ -1134,31 +1217,6 @@ func (e *LinePreOrder) CheckRepeatOrder(symbolType int, apiUserId, site, baseCoi | ||||
|  | ||||
| // AddBatchPreOrder 批量添加 | ||||
| func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p *actions.DataPermission, errs *[]error) error { | ||||
| 	// apiIds := []int{} | ||||
| 	// apiUserIds := strings.Split(batchReq.ApiUserId, ",") | ||||
| 	// apiUserService := LineApiUser{Service: e.Service} | ||||
|  | ||||
| 	// for _, v := range apiUserIds { | ||||
| 	// 	apiId, _ := strconv.Atoi(v) | ||||
| 	// 	apiIds = append(apiIds, apiId) | ||||
| 	// } | ||||
|  | ||||
| 	// activeIds, err := apiUserService.GetActiveApis(apiIds) | ||||
|  | ||||
| 	// if err != nil { | ||||
| 	// 	return err | ||||
| 	// } | ||||
|  | ||||
| 	// if len(activeIds) == 0 { | ||||
| 	// 	return errors.New("没有可用的api") | ||||
| 	// } | ||||
|  | ||||
| 	// for _, v := range apiIds { | ||||
| 	// 	if !utility.ContainsInt(activeIds, v) { | ||||
| 	// 		*errs = append(*errs, errors.New("api_id:"+strconv.Itoa(v)+"不可用")) | ||||
| 	// 	} | ||||
| 	// } | ||||
|  | ||||
| 	if batchReq.SaveTemplate == "2" || batchReq.SaveTemplate == "1" { //2 = 只保存模板 1= 保存模板并下单 | ||||
| 		var templateLog dto.LineBatchAddPreOrderReq | ||||
| 		copier.Copy(&templateLog, batchReq) | ||||
| @ -1551,6 +1609,8 @@ func (e *LinePreOrder) ClearAll() error { | ||||
| 		"_PreFutOrderList_", | ||||
| 		"spot_reduce_list", | ||||
| 		"futures_reduce_list", | ||||
| 		"spot_reduce_strategy_list", | ||||
| 		"fut_reduce_strategy_list", | ||||
| 	} | ||||
| 	err = helper.DefaultRedis.DeleteKeysByPrefix(prefixs...) | ||||
| 	if err != nil { | ||||
| @ -1558,9 +1618,10 @@ func (e *LinePreOrder) ClearAll() error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order")        //订单表 | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_status") //订单拓展状态 | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_ext")    //订单拓展配置 | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order")             //订单表 | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_status")      //订单拓展状态 | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_ext")         //订单拓展配置 | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_order_reduce_strategy") //订单减仓策略配置 | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| @ -2042,9 +2103,9 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error { | ||||
| 	var tickerPrice decimal.Decimal | ||||
|  | ||||
| 	if req.SymbolType == 1 { | ||||
| 		tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 0) | ||||
| 		tradeSet, _ = cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, req.Symbol, 0) | ||||
| 	} else { | ||||
| 		tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 1) | ||||
| 		tradeSet, _ = cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, req.Symbol, 1) | ||||
| 	} | ||||
|  | ||||
| 	if tradeSet.LastPrice == "" { | ||||
| @ -2161,164 +2222,3 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio | ||||
|  | ||||
| 	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() | ||||
| } | ||||
| @ -15,6 +15,7 @@ import ( | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/pkg/utility/snowflakehelper" | ||||
| 	"go-admin/services/binanceservice" | ||||
| 	"go-admin/services/cacheservice" | ||||
| 	"go-admin/services/fileservice" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| @ -241,7 +242,7 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li | ||||
| 	} else { | ||||
| 		var remainingQuantity decimal.Decimal | ||||
| 		spotOrder, err := spotApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4) | ||||
| 		tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0) | ||||
| 		tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 0) | ||||
|  | ||||
| 		if err == nil { | ||||
| 			origQty := utility.StrToDecimal(spotOrder.OrigQty) | ||||
| @ -359,7 +360,7 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin | ||||
| 	} else { | ||||
| 		var remainingQuantity decimal.Decimal | ||||
| 		spotOrder, err := futApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4) | ||||
| 		tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 1) | ||||
| 		tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1) | ||||
|  | ||||
| 		if err == nil { | ||||
| 			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,6 +25,11 @@ const ( | ||||
| 	PreSpotOrderList   = "_PreSpotOrderList_:%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用户 | ||||
| 	SystemSetting = "system_setting" //系统设置 | ||||
| 	ApiGroup      = "api_group:%v"   //api用户组 {id} | ||||
| @ -41,6 +46,11 @@ const ( | ||||
| 	SpotTrigger            = "spot_trigger_lock:%v_%s"        //现货触发 {apiuserid|symbol} | ||||
| 	FutTrigger             = "fut_trigger_lock:%v_%s"         //合约触发 {apiuserid|symbol} | ||||
|  | ||||
| 	//波段现货触发{apiuserid|symbol} | ||||
| 	StrategySpotTriggerLock = "strategy_spot_trigger_l:%v_%s" | ||||
| 	//波段合约触发{apiuserid|symbol} | ||||
| 	StrategyFutTriggerLock = "strategy_fut_trigger_l:%v_%s" | ||||
|  | ||||
| 	SpotCallBack = "spot_callback:%s" //现货回调 {ordersn} | ||||
| 	FutCallBack  = "fut_callback:%s"  //合约回调 {ordersn} | ||||
|  | ||||
| @ -61,6 +71,11 @@ const ( | ||||
| 	SpotPosition = "spot_position:%s:%v:%s_%s" | ||||
| 	//合约持仓 {exchangeType,apiuserid,symbol,side} | ||||
| 	FuturePosition = "future_position:%s:%v:%s_%s" | ||||
|  | ||||
| 	//现货减仓单减仓策略 {exchangeType} | ||||
| 	SpotOrderReduceStrategyList = "spot_reduce_strategy_list:%s" | ||||
| 	//合约减仓单减仓策略 {exchangeType} | ||||
| 	FutOrderReduceStrategyList = "fut_reduce_strategy_list:%s" | ||||
| 	//需要清理键值---------END----------------- | ||||
|  | ||||
| 	//定时取消限价并下市价锁 | ||||
| @ -79,6 +94,12 @@ const ( | ||||
| 	SpotTickerLastPrice = "spot_ticker_last_price:%s:%s" | ||||
| 	//合约最后成交价 sort set {exchangeType,symbol} | ||||
| 	FutureTickerLastPrice = "fut_ticker_last_price:%s:%s" | ||||
|  | ||||
| 	//允许缓存交易对价格的交易对 list | ||||
| 	CacheSymbolLastPrice = "cache_symbol_price" | ||||
|  | ||||
| 	//减仓策略缓存 {id} | ||||
| 	ReduceStrategy = "reduce_stragy:%d" | ||||
| ) | ||||
|  | ||||
| // 用户下单 | ||||
|  | ||||
| @ -697,6 +697,22 @@ func (e *RedisHelper) GetRevRangeScoresSortSet(key string) ([]redis.Z, error) { | ||||
| 	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) { | ||||
| 	return e.client.ZRange(e.ctx, key, start, stop).Result() | ||||
|  | ||||
| @ -31,9 +31,14 @@ func BusinessInit(db *gorm.DB) { | ||||
|  | ||||
| 	//初始化参数配置 | ||||
| 	cacheservice.InitConfigCache(db) | ||||
| 	//初始化可缓存价格交易对 | ||||
| 	symbolPriceService := service.LineSymbolPrice{} | ||||
| 	symbolPriceService.Orm = db | ||||
| 	symbolPriceService.Log = logger.NewHelper(sdk.Runtime.GetLogger()).WithFields(map[string]interface{}{}) | ||||
| 	symbolPriceService.InitCache() | ||||
|  | ||||
| 	//初始化订单配置 | ||||
| 	binanceservice.ResetSystemSetting(db) | ||||
| 	cacheservice.ResetSystemSetting(db) | ||||
| 	lineApiUser := service.LineApiUser{} | ||||
| 	lineApiUser.Orm = db | ||||
| 	if err := lineApiUser.InitCache(); err != nil { | ||||
|  | ||||
| @ -1,14 +1,12 @@ | ||||
| package binanceservice | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	DbModels "go-admin/app/admin/models" | ||||
| 	"go-admin/app/admin/service/dto" | ||||
| 	"go-admin/common/const/rediskey" | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	"go-admin/models" | ||||
| 	"go-admin/models/positiondto" | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/services/positionservice" | ||||
| @ -27,32 +25,6 @@ type AddPosition struct { | ||||
| 	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 { | ||||
| 	for x := 0; x < 5; x++ { | ||||
| 		risks, _ := futApi.GetPositionV3(apiInfo, symbol) | ||||
|  | ||||
| @ -10,6 +10,7 @@ import ( | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	"go-admin/models" | ||||
| 	"go-admin/services/cacheservice" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| @ -151,19 +152,37 @@ func JudgeFuturesReduce(trade models.TradeSet) { | ||||
| 	key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE) | ||||
| 	reduceVal, _ := helper.DefaultRedis.GetAllList(key) | ||||
|  | ||||
| 	if len(reduceVal) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	db := GetDBConnection() | ||||
| 	futApi := FutRestApi{} | ||||
| 	setting, err := GetSystemSetting(db) | ||||
| 	setting, err := cacheservice.GetSystemSetting(db) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Error("获取系统设置失败") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	tradePrice, _ := decimal.NewFromString(trade.LastPrice) | ||||
| 	//减仓单减仓策略 | ||||
| 	orderReduceVal, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)) | ||||
| 	reduceOrderStrategy := dto.LineOrderReduceStrategyResp{} | ||||
|  | ||||
| 	for _, item := range orderReduceVal { | ||||
| 		sonic.Unmarshal([]byte(item), &reduceOrderStrategy) | ||||
|  | ||||
| 		for _, item2 := range reduceOrderStrategy.Items { | ||||
| 			if reduceOrderStrategy.Symbol == trade.Coin+trade.Currency { | ||||
| 				//买入 | ||||
| 				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)) { | ||||
| 					//todo 生成订单并触发 | ||||
| 					// SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, item := range reduceVal { | ||||
| 		reduceOrder := ReduceListItem{} | ||||
| 		if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil { | ||||
| @ -173,7 +192,6 @@ func JudgeFuturesReduce(trade models.TradeSet) { | ||||
|  | ||||
| 		if reduceOrder.Symbol == trade.Coin+trade.Currency { | ||||
| 			orderPrice := reduceOrder.Price | ||||
| 			tradePrice, _ := decimal.NewFromString(trade.LastPrice) | ||||
| 			//买入 | ||||
| 			if orderPrice.Cmp(decimal.Zero) > 0 && | ||||
| 				tradePrice.Cmp(decimal.Zero) > 0 && | ||||
| @ -188,7 +206,7 @@ func JudgeFuturesReduce(trade models.TradeSet) { | ||||
|  | ||||
| // 触发合约减仓 | ||||
| func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string) { | ||||
| 	tradeSet, _ := GetTradeSet(reduceOrder.Symbol, 1) | ||||
| 	tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 1) | ||||
|  | ||||
| 	if tradeSet.LastPrice == "" { | ||||
| 		return | ||||
| @ -239,17 +257,6 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes | ||||
| 			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 { | ||||
| 			log.Errorf("合约减仓挂单失败 id:%s err:%v", reduceOrder.Id, err) | ||||
|  | ||||
| @ -267,6 +274,9 @@ 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 { | ||||
| 				log.Errorf("合约减仓更新状态失败 id:%s err:%v", reduceOrder.Id, err) | ||||
| 			} | ||||
|  | ||||
| 			//处理减仓单减仓策略 | ||||
| 			CacheOrderStrategyAndReCreate(db, reduceOrder, 2, tradeSet, setting) | ||||
| 		} | ||||
|  | ||||
| 		if _, err := helper.DefaultRedis.LRem(key, item); err != nil { | ||||
| @ -322,8 +332,8 @@ func FutAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, futApi | ||||
| 	} else if ok { | ||||
| 		defer lock.Release() | ||||
|  | ||||
| 		setting, _ := GetSystemSetting(db) | ||||
| 		tradeSet, _ := GetTradeSet(v.Symbol, 1) | ||||
| 		setting, _ := cacheservice.GetSystemSetting(db) | ||||
| 		tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, v.Symbol, 1) | ||||
|  | ||||
| 		if tradeSet.LastPrice == "" { | ||||
| 			log.Errorf("合约加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn) | ||||
|  | ||||
| @ -13,6 +13,7 @@ import ( | ||||
| 	models2 "go-admin/models" | ||||
| 	"go-admin/models/positiondto" | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/services/cacheservice" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| @ -126,13 +127,15 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	tradeSet, err := GetTradeSet(preOrder.Symbol, 1) | ||||
| 	tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, preOrder.Symbol, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		logger.Errorf("handleReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	//修改减仓单减仓策略状态 | ||||
| 	ReduceCallBack(db, preOrder) | ||||
| 	orderExt := models.LinePreOrderExt{} | ||||
| 	db.Model(&orderExt).Where("order_id =?", preOrder.Id).First(&orderExt) | ||||
| 	// rate := utility.StringAsFloat(orderExt.AddPositionVal) | ||||
| @ -473,7 +476,7 @@ func removeFutLossAndAddPosition(mainId int, orderSn string) { | ||||
| // 处理主单成交,处理止盈、止损、减仓订单 | ||||
| func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrderId int, first bool) { | ||||
| 	// 获取交易对配置和API信息 | ||||
| 	tradeSet, err := GetTradeSet(preOrder.Symbol, 1) | ||||
| 	tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, preOrder.Symbol, 1) | ||||
| 	mainId := preOrder.Id | ||||
| 	if err != nil || tradeSet.Coin == "" { | ||||
| 		logger.Errorf("获取交易对配置失败, 回调订单号:%s, 错误信息: %v", preOrder.OrderSn, err) | ||||
| @ -742,7 +745,7 @@ func processFutReduceOrder(order DbModels.LinePreOrder, price, num decimal.Decim | ||||
| // 处理止盈订单 | ||||
| func processFutTakeProfitOrder(db *gorm.DB, futApi FutRestApi, order models.LinePreOrder, num decimal.Decimal) { | ||||
| 	price, _ := decimal.NewFromString(order.Price) | ||||
| 	tradeSet, _ := GetTradeSet(order.Symbol, 1) | ||||
| 	tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1) | ||||
|  | ||||
| 	params := FutOrderPlace{ | ||||
| 		ApiId:            order.ApiId, | ||||
| @ -779,7 +782,7 @@ func processFutTakeProfitOrder(db *gorm.DB, futApi FutRestApi, order models.Line | ||||
| // 处理止损订单 | ||||
| // order 止损单 | ||||
| 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{ | ||||
| 		ApiId:            order.ApiId, | ||||
|  | ||||
							
								
								
									
										134
									
								
								services/binanceservice/reduce_order_strategy_service.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								services/binanceservice/reduce_order_strategy_service.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| 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" | ||||
|  | ||||
| 	"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.LineReduceStrategy{} | ||||
| 	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 { | ||||
| 		strategyCache := dto.LineOrderReduceStrategyResp{ | ||||
| 			OrderId: reduceOrder.Id, | ||||
| 		} | ||||
|  | ||||
| 		for _, item := range reduceOrderStrategy.Items { | ||||
| 			var rate decimal.Decimal | ||||
| 			var triggerRate decimal.Decimal | ||||
|  | ||||
| 			if reduceOrder.Side == "BUY" { | ||||
| 				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)) | ||||
|  | ||||
| 			strategyCache.Items = append(strategyCache.Items, dto.LineOrderReduceStrategyRespItem{ | ||||
| 				LossPercent:  item.LossPercent, | ||||
| 				OrderType:    item.OrderType, | ||||
| 				Price:        price, | ||||
| 				TriggerPrice: triggerPrice, | ||||
| 			}) | ||||
| 		} | ||||
|  | ||||
| 		str, _ := sonic.MarshalString(reduceOrderStrategy) | ||||
|  | ||||
| 		if str != "" { | ||||
| 			if err := helper.DefaultRedis.SetString(key, 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.GetAllList(key) | ||||
| 	cache := dto.LineOrderReduceStrategyResp{} | ||||
|  | ||||
| 	for _, v := range arrays { | ||||
| 		sonic.Unmarshal([]byte(v), &cache) | ||||
|  | ||||
| 		if cache.OrderId == reduceOrderId { | ||||
| 			if _, err := helper.DefaultRedis.LRem(key, v); 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 | ||||
| } | ||||
| @ -11,6 +11,7 @@ import ( | ||||
| 	"go-admin/common/helper" | ||||
| 	"go-admin/models" | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/services/cacheservice" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| @ -141,14 +142,14 @@ func JudgeSpotStopLoss(trade models.TradeSet) { | ||||
|  | ||||
| 	db := GetDBConnection() | ||||
| 	spotApi := SpotRestApi{} | ||||
| 	setting, err := GetSystemSetting(db) | ||||
| 	setting, err := cacheservice.GetSystemSetting(db) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Error("获取系统设置失败") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	tradeSet, err := GetTradeSet(trade.Coin+trade.Currency, 0) | ||||
| 	tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, trade.Coin+trade.Currency, 0) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Error("获取交易设置失败") | ||||
| @ -256,21 +257,40 @@ func SpotStopLossTrigger(db *gorm.DB, stopOrder dto.StopLossRedisList, spotApi S | ||||
| // 判断是否触发现货减仓 | ||||
| func JudgeSpotReduce(trade models.TradeSet) { | ||||
| 	key := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE) | ||||
| 	reduceVal, _ := helper.DefaultRedis.GetAllList(key) | ||||
|  | ||||
| 	if len(reduceVal) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	db := GetDBConnection() | ||||
| 	spotApi := SpotRestApi{} | ||||
| 	setting, err := GetSystemSetting(db) | ||||
| 	setting, err := cacheservice.GetSystemSetting(db) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Error("获取系统设置失败") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	tradePrice, _ := decimal.NewFromString(trade.LastPrice) | ||||
| 	//减仓单减仓策略 | ||||
| 	orderReduceVal, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)) | ||||
| 	reduceOrderStrategy := dto.LineOrderReduceStrategyResp{} | ||||
|  | ||||
| 	for _, item := range orderReduceVal { | ||||
| 		sonic.Unmarshal([]byte(item), &reduceOrderStrategy) | ||||
|  | ||||
| 		for _, 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 { | ||||
| 					//todo 生成订单并触发 | ||||
| 					// SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//减仓单 | ||||
| 	reduceVal, _ := helper.DefaultRedis.GetAllList(key) | ||||
|  | ||||
| 	for _, item := range reduceVal { | ||||
| 		reduceOrder := ReduceListItem{} | ||||
| 		if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil { | ||||
| @ -280,7 +300,6 @@ func JudgeSpotReduce(trade models.TradeSet) { | ||||
|  | ||||
| 		if reduceOrder.Symbol == trade.Coin+trade.Currency { | ||||
| 			orderPrice := reduceOrder.Price | ||||
| 			tradePrice, _ := decimal.NewFromString(trade.LastPrice) | ||||
| 			//买入 | ||||
| 			if strings.ToUpper(reduceOrder.Side) == "SELL" && | ||||
| 				orderPrice.Cmp(tradePrice) >= 0 && | ||||
| @ -295,7 +314,7 @@ func JudgeSpotReduce(trade models.TradeSet) { | ||||
|  | ||||
| // 触发现货减仓 | ||||
| func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string) { | ||||
| 	tradeSet, err := GetTradeSet(reduceOrder.Symbol, 0) | ||||
| 	tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 0) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Error("获取交易设置失败") | ||||
| @ -366,6 +385,9 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest | ||||
| 				Updates(map[string]interface{}{"status": 1}).Error; err != nil { | ||||
| 				log.Errorf("修改现货减仓状态失败 id:%s err:%v", reduceOrder.Id, err) | ||||
| 			} | ||||
|  | ||||
| 			//处理减仓单减仓策略 | ||||
| 			CacheOrderStrategyAndReCreate(db, reduceOrder, 1, tradeSet, setting) | ||||
| 		} | ||||
|  | ||||
| 		if _, err := helper.DefaultRedis.LRem(key, item); err != nil { | ||||
| @ -414,8 +436,8 @@ func SpotAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, spotAp | ||||
| 	} else if ok { | ||||
| 		defer lock.Release() | ||||
|  | ||||
| 		setting, _ := GetSystemSetting(db) | ||||
| 		tradeSet, _ := GetTradeSet(v.Symbol, 0) | ||||
| 		setting, _ := cacheservice.GetSystemSetting(db) | ||||
| 		tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, v.Symbol, 0) | ||||
|  | ||||
| 		if tradeSet.LastPrice == "" { | ||||
| 			log.Errorf("现货加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn) | ||||
|  | ||||
| @ -13,6 +13,7 @@ import ( | ||||
| 	models2 "go-admin/models" | ||||
| 	"go-admin/models/positiondto" | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/services/cacheservice" | ||||
| 	"go-admin/services/positionservice" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| @ -165,13 +166,16 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	tradeSet, err := GetTradeSet(preOrder.Symbol, 0) | ||||
| 	tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, preOrder.Symbol, 0) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		logger.Errorf("handleMainReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	//修改减仓单减仓策略状态 | ||||
| 	ReduceCallBack(db, preOrder) | ||||
|  | ||||
| 	orderExt := models.LinePreOrderExt{} | ||||
| 	positionData := savePosition(db, preOrder) | ||||
|  | ||||
| @ -731,7 +735,7 @@ func updateOrderStatus(db *gorm.DB, preOrder *models.LinePreOrder, status int, r | ||||
| // fist 首次止盈止损 | ||||
| func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder, positionData *positiondto.PositionDto, extOrderId int, fist bool) { | ||||
| 	orders := []models.LinePreOrder{} | ||||
| 	tradeSet, _ := GetTradeSet(preOrder.Symbol, 0) | ||||
| 	tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, preOrder.Symbol, 0) | ||||
| 	mainId := preOrder.Id | ||||
|  | ||||
| 	if preOrder.MainId > 0 { | ||||
| @ -869,7 +873,7 @@ func processSpotReduceOrder(preOrder DbModels.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 == "" { | ||||
| 		logger.Error("获取交易对失败") | ||||
| @ -941,44 +945,6 @@ func processStopLossOrder(order models.LinePreOrder) error { | ||||
| 	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 { | ||||
| 	spotApi := SpotRestApi{} | ||||
|  | ||||
							
								
								
									
										232
									
								
								services/binanceservice/strategy_order_service.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								services/binanceservice/strategy_order_service.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,232 @@ | ||||
| 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" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/sdk/service" | ||||
| 	"github.com/shopspring/decimal" | ||||
| ) | ||||
|  | ||||
| type BinanceStrategyOrderService struct { | ||||
| 	service.Service | ||||
| } | ||||
|  | ||||
| // 判断是否触发波段订单 | ||||
| func (e *BinanceStrategyOrderService) TriggerStrategyOrder(exchangeType string) { | ||||
| 	//现货 | ||||
| 	orderStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType)) | ||||
| 	e.DoJudge(orderStrs, 1, exchangeType) | ||||
|  | ||||
| 	//合约 | ||||
| 	futOrdedrStrs, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.StrategyFutOrderList, exchangeType)) | ||||
| 	e.DoJudge(futOrdedrStrs, 2, exchangeType) | ||||
| } | ||||
|  | ||||
| // 处理订单 | ||||
| func (e *BinanceStrategyOrderService) DoJudge(orderStrs []string, symbolType int, exchangeType string) { | ||||
| 	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.Symbol), 200, 50, 100*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, 1, exchangeType) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				e.Log.Errorf("order_id:%d err:%v", orderItem.Id, err) | ||||
| 			} | ||||
|  | ||||
| 			if success { | ||||
| 				e.TriggerOrder(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 | ||||
| 	startPrice := utility.StrToDecimal(beforePrice) | ||||
| 	lastPrice := utility.StrToDecimal(lastPrices[0].Member.(string)) | ||||
|  | ||||
| 	//时间差超过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) | ||||
|  | ||||
| 	//价格没有变动 | ||||
| 	if percentag.Cmp(decimal.Zero) == 0 { | ||||
| 		return result, nil | ||||
| 	} | ||||
|  | ||||
| 	//满足条件 | ||||
| 	switch order.CompareType { | ||||
| 	case 1: | ||||
| 		result = percentag.Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) > 0 | ||||
| 	case 2: | ||||
| 		result = percentag.Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) >= 0 | ||||
| 	case 5: | ||||
| 		result = percentag.Mul(decimal.NewFromInt(100)).Cmp(order.Percentag) == 0 | ||||
| 	default: | ||||
| 		return result, errors.New("没有对应的类型") | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| // 触发委托单 | ||||
| func (e *BinanceStrategyOrderService) TriggerOrder(order dto.StrategyOrderRedisList, symbolType int) error { | ||||
| 	orders := make([]models.LinePreOrder, 0) | ||||
| 	if err := e.Orm.Model(&models.LinePreOrder{}).Where("main_id =?", order.Id).Find(&orders).Error; err != nil { | ||||
| 		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("获取系统设置失败") | ||||
| 	} | ||||
|  | ||||
| 	tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, symbolType) | ||||
|  | ||||
| 	if tradeSet.Coin == "" { | ||||
| 		return errors.New("获取交易对行情失败") | ||||
| 	} | ||||
|  | ||||
| 	lastPrice := utility.StrToDecimal(tradeSet.LastPrice) | ||||
|  | ||||
| 	if lastPrice.Cmp(decimal.Zero) <= 0 { | ||||
| 		return errors.New("最新成交价小于等于0") | ||||
| 	} | ||||
|  | ||||
| 	var mainOrder models.LinePreOrder | ||||
|  | ||||
| 	for _, v := range orders { | ||||
| 		if v.MainId == 0 { | ||||
| 			mainOrder = v | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	GetOrderByPid(&mainOrder, orders, mainOrder.Id) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // 重新计算订单单价、数量 | ||||
| // 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_id =?", mainOrder.Id).Find(&exts).Error; err != nil { | ||||
| 		return errors.New("获取拓展信息失败") | ||||
| 	} | ||||
|  | ||||
| 	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() | ||||
|  | ||||
| 	for index := range mainOrder.Childs { | ||||
| 		//主单止盈 | ||||
| 		if mainOrder.Child[index].OrderType == 1 { | ||||
| 			var ext models.LinePreOrderExt | ||||
|  | ||||
| 			for _, v := range exts { | ||||
| 				if v.OrderId == mainOrder.Child[index].Id { | ||||
| 					ext = v | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if ext.Id > 0 { | ||||
| 				var percent decimal.Decimal | ||||
| 				//多 | ||||
| 				if mainOrder.Site == "BUY" { | ||||
| 					percent = decimal.NewFromInt(100).Add(ext.TakeProfitRatio) | ||||
| 				} else { | ||||
| 					percent = decimal.NewFromInt(100).Sub(ext.StopLossRatio) | ||||
| 				} | ||||
|  | ||||
| 				childPrice := lastPrice.Mul(percent.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.PriceDigit)) | ||||
| 				mainOrder.Child[index].Price = childPrice.String() | ||||
| 			} | ||||
| 		} else { | ||||
| 			//todo 重新计算 | ||||
| 		} | ||||
| 	} | ||||
| 	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) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -1,10 +1,13 @@ | ||||
| package cacheservice | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"go-admin/app/admin/models" | ||||
| 	"go-admin/common/const/rediskey" | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	models2 "go-admin/models" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| @ -59,3 +62,66 @@ func GetConfigCacheByKey(db *gorm.DB, key string) models.SysConfig { | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // 获取缓存交易对 | ||||
| // symbolType 0-现货 1-合约 | ||||
| func GetTradeSet(exchangeType string, symbol string, symbolType int) (models2.TradeSet, error) { | ||||
| 	result := models2.TradeSet{} | ||||
| 	val := "" | ||||
|  | ||||
| 	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) | ||||
| 	} | ||||
|  | ||||
| 	if val != "" { | ||||
| 		if err := sonic.Unmarshal([]byte(val), &result); err != nil { | ||||
| 			return result, err | ||||
| 		} | ||||
| 	} else { | ||||
| 		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 | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user