Browse Source

temp commit

hsun 10 months ago
parent
commit
1061835029

+ 13 - 5
controllers/data_manage/edb_info_calculate.go

@@ -2117,6 +2117,7 @@ func (this *ChartInfoController) CalculateComputeCorrelation() {
 // @Param   SysUserIds   query   int  true       "创建人"
 // @Param   Keyword   query   string  false       "关键词搜索"
 // @Param   Frequency   query   string  false       "频度"
+// @Param   EdbInfoType  query  int  false  "指标类型: 0-普通指标; 1-预测指标"
 // @Success 200 {object} data_manage.EdbInfoSearchResp
 // @router /edb_info/calculate/multi/choice [get]
 func (this *ChartInfoController) CalculateMultiChoice() {
@@ -2134,13 +2135,15 @@ func (this *ChartInfoController) CalculateMultiChoice() {
 	edbInfoIds := this.GetString("EdbInfoIds")
 	selectAll, _ := this.GetBool("SelectAll")
 	notFrequency := this.GetString("NotFrequency")
+	edbInfoType, _ := this.GetInt("EdbInfoType", 0)
 	var edbIdArr []int
 
 	if selectAll {
 		// 如果勾了列表全选,那么EdbCode传的就是排除的code
 
-		var condition string
-		var pars []interface{}
+		condition := ` AND edb_info_type = ? `
+		pars := make([]interface{}, 0)
+		pars = append(pars, edbInfoType)
 
 		if classifyIds != "" {
 			classifyIdsArr := strings.Split(classifyIds, ",")
@@ -2175,7 +2178,7 @@ func (this *ChartInfoController) CalculateMultiChoice() {
 				}
 			}
 		}
-		edbList, e := data_manage.GetEdbInfoFilter(condition, pars)
+		edbList, e := data_manage.GetEdbInfoListByCond(condition, pars)
 		if e != nil {
 			br.Msg = "获取指标列表失败"
 			br.ErrMsg = "获取指标列表失败,Err:" + e.Error()
@@ -2263,6 +2266,7 @@ func (this *ChartInfoController) CalculateMultiChoice() {
 				EdbInfoId:     info.EdbInfoId,
 				ClassifyId:    info.ClassifyId,
 				HaveOperaAuth: haveOperaAuth,
+				EdbInfoType:   info.EdbInfoType,
 			}
 			searchItemList = append(searchItemList, searchItem)
 		}
@@ -2283,6 +2287,7 @@ func (this *ChartInfoController) CalculateMultiChoice() {
 // @Param   SysUserIds   query   int  true       "创建人"
 // @Param   Keyword   query   string  false       "关键词搜索"
 // @Param   Frequency   query   string  false       "频度"
+// @Param   EdbInfoType  query  int  false  "指标类型: 0-普通指标; 1-预测指标"
 // @Success 200 {object} data_manage.EdbInfoSearchResp
 // @router /edb_info/calculate/multi/search [get]
 func (this *ChartInfoController) CalculateMultiSearch() {
@@ -2301,6 +2306,7 @@ func (this *ChartInfoController) CalculateMultiSearch() {
 	pageSize, _ := this.GetInt("PageSize")
 	currentIndex, _ := this.GetInt("CurrentIndex")
 	notFrequency := this.GetString("NotFrequency")
+	edbInfoType, _ := this.GetInt("EdbInfoType", 0)
 
 	var startSize int
 	if pageSize <= 0 {
@@ -2313,8 +2319,9 @@ func (this *ChartInfoController) CalculateMultiSearch() {
 
 	var edbIdArr []int
 
-	condition := ` AND edb_info_type = 0 `
-	var pars []interface{}
+	condition := ` AND edb_info_type = ? `
+	pars := make([]interface{}, 0)
+	pars = append(pars, edbInfoType)
 
 	if classifyIds != "" {
 		classifyIdsArr := strings.Split(classifyIds, ",")
@@ -2422,6 +2429,7 @@ func (this *ChartInfoController) CalculateMultiSearch() {
 				EndDate:         info.EndDate,
 				EndValue:        info.EndValue,
 				HaveOperaAuth:   haveOperaAuth,
+				EdbInfoType:     info.EdbInfoType,
 			}
 			searchItemList = append(searchItemList, searchItem)
 		}

+ 748 - 0
controllers/data_manage/factor_edb_series.go

@@ -0,0 +1,748 @@
+package data_manage
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/request"
+	"eta/eta_api/services/data"
+	correlationServ "eta/eta_api/services/data/correlation"
+	"eta/eta_api/utils"
+	"fmt"
+	"sort"
+	"strings"
+	"sync"
+	"time"
+)
+
+// FactorEdbSeriesController 因子指标系列
+type FactorEdbSeriesController struct {
+	controllers.BaseAuthController
+}
+
+// CalculateFuncList
+// @Title 计算方式列表
+// @Description 计算方式列表
+// @Param   EdbInfoType  query  int  false "指标计算类型: 0-普通指标; 1-预测指标"
+// @Success Ret=200 操作成功
+// @router /factor_edb_series/calculate_func/list [get]
+func (this *FactorEdbSeriesController) CalculateFuncList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	edbInfoType, _ := this.GetInt("EdbInfoType", 0)
+
+	funcOb := new(data_manage.FactorEdbSeriesCalculateFunc)
+	cond := fmt.Sprintf(` AND %s = ?`, funcOb.Cols().EdbInfoType)
+	pars := make([]interface{}, 0)
+	pars = append(pars, edbInfoType)
+	list, e := funcOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", funcOb.Cols().PrimaryId))
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprintf("获取计算方式列表失败, Err: %v", e)
+		return
+	}
+	resp := make([]*data_manage.FactorEdbSeriesCalculateFuncItem, 0)
+	for _, v := range list {
+		resp = append(resp, v.Format2Item())
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Add
+// @Title 新增
+// @Description 新增
+// @Param	request	body request.AddFactorEdbSeriesReq true "type json string"
+// @Success Ret=200 操作成功
+// @router /factor_edb_series/add [post]
+func (this *FactorEdbSeriesController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.AddFactorEdbSeriesReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常"
+		br.ErrMsg = fmt.Sprintf("参数解析异常, Err: %v", e)
+		return
+	}
+	req.SeriesName = strings.TrimSpace(req.SeriesName)
+	if req.SeriesName == "" {
+		br.Msg = "请输入指标系列名称"
+		return
+	}
+	if len(req.EdbInfoIds) <= 0 {
+		br.Msg = "请选择因子指标系列"
+		return
+	}
+	if len(req.EdbInfoIds) > 100 {
+		br.Msg = "添加指标总数量不得超过100"
+		return
+	}
+	calculateLen := len(req.Calculates)
+	if calculateLen > 5 {
+		br.Msg = "计算公式不可超过5个"
+		return
+	}
+	var calculatesJson string
+	if calculateLen > 0 {
+		b, e := json.Marshal(req.Calculates)
+		if e != nil {
+			br.Msg = "计算方式格式有误"
+			br.ErrMsg = "解析计算方式参数失败, Err: " + e.Error()
+			return
+		}
+		calculatesJson = string(b)
+		for _, v := range req.Calculates {
+			switch v.Source {
+			case utils.EdbBaseCalculateNszydpjjs, utils.EdbBaseCalculateHbz, utils.EdbBaseCalculateHcz, utils.EdbBaseCalculateCjjx:
+				if v.Formula == nil {
+					br.Msg = "请输入N值"
+					return
+				}
+				formulaInt, ok := v.Formula.(int)
+				if !ok {
+					br.Msg = "N值格式有误"
+					return
+				}
+				if formulaInt <= 0 {
+					br.Msg = "N值不可小于0, 重新输入"
+					return
+				}
+			case utils.EdbBaseCalculateExponentialSmoothing:
+				if v.Formula == nil {
+					br.Msg = "请填写alpha值"
+					return
+				}
+				alpha, ok := v.Formula.(float64)
+				if ok {
+					br.Msg = "alpha值格式有误"
+					return
+				}
+				if alpha <= 0 || alpha >= 1 {
+					br.Msg = "alpha值应在0-1之间, 请重新输入"
+					return
+				}
+			}
+		}
+	}
+	edbArr, e := data_manage.GetEdbInfoByIdList(req.EdbInfoIds)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取指标列表失败, Err: " + e.Error()
+		return
+	}
+	if len(edbArr) == 0 {
+		br.Msg = "因子指标系列有误"
+		br.ErrMsg = "因子指标系列长度为0"
+		return
+	}
+
+	// 新增指标系列
+	seriesItem := new(data_manage.FactorEdbSeries)
+	seriesItem.SeriesName = req.SeriesName
+	seriesItem.EdbInfoType = req.EdbInfoType
+	seriesItem.CreateTime = time.Now().Local()
+	seriesItem.ModifyTime = time.Now().Local()
+	if calculateLen > 0 {
+		seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
+		seriesItem.CalculateStep = calculatesJson
+	}
+	mappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
+	for _, v := range edbArr {
+		mappings = append(mappings, &data_manage.FactorEdbSeriesMapping{
+			EdbInfoId:  v.EdbInfoId,
+			EdbCode:    v.EdbCode,
+			CreateTime: time.Now().Local(),
+			ModifyTime: time.Now().Local(),
+		})
+	}
+	seriesId, e := seriesItem.CreateSeriesAndMapping(seriesItem, mappings)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "新增因子指标系列失败, Err: " + e.Error()
+		return
+	}
+
+	// 计算指标数据
+	var calculateResp data_manage.FactorEdbSeriesStepCalculateResp
+	if calculateLen > 0 {
+		calculateResp, e = data.FactorEdbStepCalculate(seriesId, edbArr, req.Calculates, this.Lang, false)
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "计算因子指标失败, Err: " + e.Error()
+			return
+		}
+
+		// 更新系列计算状态
+		cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
+		seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
+		seriesItem.ModifyTime = time.Now().Local()
+		if e = seriesItem.Update(cols); e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新因子指标系列计算状态失败, Err: " + e.Error()
+			return
+		}
+	} else {
+		for _, v := range edbArr {
+			calculateResp.Success = append(calculateResp.Success, data_manage.FactorEdbSeriesStepCalculateResult{
+				EdbInfoId: v.EdbInfoId,
+				EdbCode:   v.EdbCode,
+				Msg:       "保存成功",
+			})
+		}
+	}
+	calculateResp.SeriesId = seriesId
+
+	br.Data = calculateResp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	br.IsAddLog = true
+}
+
+// Edit
+// @Title 编辑
+// @Description 编辑
+// @Param	request	body request.EditFactorEdbSeriesReq true "type json string"
+// @Success Ret=200 操作成功
+// @router /factor_edb_series/edit [post]
+func (this *FactorEdbSeriesController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.EditFactorEdbSeriesReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常"
+		br.ErrMsg = fmt.Sprintf("参数解析异常, Err: %v", e)
+		return
+	}
+	if req.SeriesId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, SeriesId: %d", req.SeriesId)
+		return
+	}
+	req.SeriesName = strings.TrimSpace(req.SeriesName)
+	if req.SeriesName == "" {
+		br.Msg = "请输入指标系列名称"
+		return
+	}
+	if len(req.EdbInfoIds) <= 0 {
+		br.Msg = "请选择因子指标系列"
+		return
+	}
+	if len(req.EdbInfoIds) > 100 {
+		br.Msg = "添加指标总数量不得超过100"
+		return
+	}
+	calculateLen := len(req.Calculates)
+	if calculateLen > 5 {
+		br.Msg = "计算公式不可超过5个"
+		return
+	}
+	var calculatesJson string
+	if calculateLen > 0 {
+		b, e := json.Marshal(req.Calculates)
+		if e != nil {
+			br.Msg = "计算方式格式有误"
+			br.ErrMsg = "解析计算方式参数失败, Err: " + e.Error()
+			return
+		}
+		calculatesJson = string(b)
+		for _, v := range req.Calculates {
+			switch v.Source {
+			case utils.EdbBaseCalculateNszydpjjs, utils.EdbBaseCalculateHbz, utils.EdbBaseCalculateHcz, utils.EdbBaseCalculateCjjx:
+				if v.Formula == nil {
+					br.Msg = "请输入N值"
+					return
+				}
+				formulaInt, ok := v.Formula.(int)
+				if !ok {
+					br.Msg = "N值格式有误"
+					return
+				}
+				if formulaInt <= 0 {
+					br.Msg = "N值不可小于0, 重新输入"
+					return
+				}
+			case utils.EdbBaseCalculateExponentialSmoothing:
+				if v.Formula == nil {
+					br.Msg = "请填写alpha值"
+					return
+				}
+				alpha, ok := v.Formula.(float64)
+				if ok {
+					br.Msg = "alpha值格式有误"
+					return
+				}
+				if alpha <= 0 || alpha >= 1 {
+					br.Msg = "alpha值应在0-1之间, 请重新输入"
+					return
+				}
+			}
+		}
+	}
+	seriesOb := new(data_manage.FactorEdbSeries)
+	seriesItem, e := seriesOb.GetItemById(req.SeriesId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "该因子指标系列不存在"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
+		return
+	}
+
+	edbArr, e := data_manage.GetEdbInfoByIdList(req.EdbInfoIds)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取指标列表失败, Err: " + e.Error()
+		return
+	}
+	if len(edbArr) == 0 {
+		br.Msg = "因子指标系列有误"
+		br.ErrMsg = "因子指标系列长度为0"
+		return
+	}
+	var calculateResp data_manage.FactorEdbSeriesStepCalculateResp
+	calculateResp.SeriesId = seriesItem.FactorEdbSeriesId
+
+	// 如果不需要进行重新计算(比如只改了系列名称)那么只更新指标系列
+	seriesItem.SeriesName = req.SeriesName
+	seriesItem.EdbInfoType = req.EdbInfoType
+	seriesItem.ModifyTime = time.Now().Local()
+	updateCols := []string{seriesOb.Cols().SeriesName, seriesOb.Cols().EdbInfoType, seriesOb.Cols().ModifyTime}
+	if !req.Recalculate {
+		if e = seriesItem.Update(updateCols); e != nil {
+			br.Msg = "操作成功"
+			br.ErrMsg = "更新因子指标系列信息失败, Err: " + e.Error()
+			return
+		}
+		for _, v := range edbArr {
+			calculateResp.Success = append(calculateResp.Success, data_manage.FactorEdbSeriesStepCalculateResult{
+				EdbInfoId: v.EdbInfoId,
+				EdbCode:   v.EdbCode,
+				Msg:       "保存成功",
+			})
+		}
+		br.Data = calculateResp
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+
+	// 更新系列信息和指标关联
+	if calculateLen > 0 {
+		seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
+		seriesItem.CalculateStep = calculatesJson
+		updateCols = append(updateCols, seriesOb.Cols().CalculateState, seriesOb.Cols().CalculateStep)
+	}
+	mappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
+	for _, v := range edbArr {
+		mappings = append(mappings, &data_manage.FactorEdbSeriesMapping{
+			EdbInfoId:  v.EdbInfoId,
+			EdbCode:    v.EdbCode,
+			CreateTime: time.Now().Local(),
+			ModifyTime: time.Now().Local(),
+		})
+	}
+	if e = seriesItem.EditSeriesAndMapping(seriesItem, mappings, updateCols); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "编辑因子指标系列失败, Err: " + e.Error()
+		return
+	}
+
+	// 重新计算
+	calculateResp, e = data.FactorEdbStepCalculate(seriesItem.FactorEdbSeriesId, edbArr, req.Calculates, this.Lang, req.Recalculate)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "计算因子指标失败, Err: " + e.Error()
+		return
+	}
+
+	// 更新系列计算状态
+	cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
+	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
+	seriesItem.ModifyTime = time.Now().Local()
+	if e = seriesItem.Update(cols); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新因子指标系列计算状态失败, Err: " + e.Error()
+		return
+	}
+
+	br.Data = calculateResp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	br.IsAddLog = true
+}
+
+// Detail
+// @Title 详情
+// @Description 详情
+// @Param   SeriesId  query  int  false  "多因子指标系列ID"
+// @Success 200 {object} data_manage.FactorEdbSeriesDetail
+// @router /factor_edb_series/detail [get]
+func (this *FactorEdbSeriesController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	seriesId, _ := this.GetInt("SeriesId", 0)
+	if seriesId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, SeriesId: %d", seriesId)
+		return
+	}
+
+	seriesOb := new(data_manage.FactorEdbSeries)
+	series, e := seriesOb.GetItemById(seriesId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "该因子指标系列不存在"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
+		return
+	}
+
+	mappingOb := new(data_manage.FactorEdbSeriesMapping)
+	cond := fmt.Sprintf(" AND %s = ?", mappingOb.Cols().FactorEdbSeriesId)
+	pars := make([]interface{}, 0)
+	pars = append(pars, seriesId)
+	mappings, e := mappingOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", mappingOb.Cols().CreateTime))
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取因子指标系列关联失败, Err: " + e.Error()
+		return
+	}
+
+	resp := new(data_manage.FactorEdbSeriesDetail)
+	resp.FactorEdbSeriesItem = series.Format2Item()
+	for _, m := range mappings {
+		resp.EdbMappings = append(resp.EdbMappings, m.Format2Item())
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// CorrelationMatrix
+// @Title 因子指标系列-相关性矩阵
+// @Description 因子指标系列-相关性矩阵
+// @Param	request	body request.FactorEdbSeriesCorrelationMatrixReq true "type json string"
+// @Success 200 {object} data_manage.FactorEdbSeriesCorrelationMatrixItem
+// @router /factor_edb_series/correlation/matrix [post]
+func (this *FactorEdbSeriesController) CorrelationMatrix() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.FactorEdbSeriesCorrelationMatrixReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常"
+		br.ErrMsg = fmt.Sprintf("参数解析异常, Err: %v", e)
+		return
+	}
+	if req.BaseEdbInfoId <= 0 {
+		br.Msg = "请选择标的指标"
+		return
+	}
+	if len(req.SeriesIds) == 0 {
+		br.Msg = "请选择因子指标系列"
+		return
+	}
+	if req.Correlation.LeadValue <= 0 {
+		br.Msg = "分析周期不允许设置为负数或0"
+		return
+	}
+	if req.Correlation.LeadUnit == "" {
+		br.Msg = "请选择分析周期频度"
+		return
+	}
+	leadUnitDays, ok := utils.FrequencyDaysMap[req.Correlation.LeadUnit]
+	if !ok {
+		br.Msg = "错误的分析周期频度"
+		br.ErrMsg = fmt.Sprintf("分析周期频度有误: %s", req.Correlation.LeadUnit)
+		return
+	}
+
+	if req.Correlation.CalculateUnit == "" {
+		br.Msg = "请选择计算窗口频度"
+		return
+	}
+	calculateUnitDays, ok := utils.FrequencyDaysMap[req.Correlation.CalculateUnit]
+	if !ok {
+		br.Msg = "错误的计算窗口频度"
+		br.ErrMsg = fmt.Sprintf("计算窗口频度有误: %s", req.Correlation.CalculateUnit)
+		return
+	}
+	leadDays := 2 * req.Correlation.LeadValue * leadUnitDays
+	calculateDays := req.Correlation.CalculateValue * calculateUnitDays
+	if calculateDays < leadDays {
+		br.Msg = "计算窗口必须≥2*分析周期"
+		return
+	}
+
+	// 获取标的指标信息及数据
+	baseEdb, e := data_manage.GetEdbInfoById(req.BaseEdbInfoId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "标的指标不存在"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取标的指标信息失败, Err: " + e.Error()
+		return
+	}
+	dataListA := make([]*data_manage.EdbDataList, 0)
+	{
+		// 标的指标数据日期区间
+		startDate := time.Now().AddDate(0, 0, -calculateDays).Format(utils.FormatDate)
+		endDate := time.Now().Format(utils.FormatDate)
+		startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		startDate = startDateTime.AddDate(0, 0, 1).Format(utils.FormatDate) // 不包含第一天
+		switch baseEdb.EdbInfoType {
+		case 0:
+			dataListA, e = data_manage.GetEdbDataList(baseEdb.Source, baseEdb.SubSource, baseEdb.EdbInfoId, startDate, endDate)
+		case 1:
+			_, dataListA, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdb.EdbInfoId, startDate, endDate, false)
+		default:
+			br.Msg = "获取失败"
+			br.ErrMsg = fmt.Sprintf("标的指标类型异常: %d", baseEdb.EdbInfoType)
+			return
+		}
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取标的指标数据失败, Err:" + e.Error()
+			return
+		}
+	}
+
+	// 获取因子系列
+	seriesIdItem := make(map[int]*data_manage.FactorEdbSeries)
+	{
+		ob := new(data_manage.FactorEdbSeries)
+		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().PrimaryId, utils.GetOrmInReplace(len(req.SeriesIds)))
+		pars := make([]interface{}, 0)
+		pars = append(pars, req.SeriesIds)
+		items, e := ob.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", ob.Cols().PrimaryId))
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
+			return
+		}
+		if len(items) != len(req.SeriesIds) {
+			br.Msg = "获取失败"
+			br.ErrMsg = "因子指标系列数量有误"
+			return
+		}
+		for _, v := range items {
+			seriesIdItem[v.FactorEdbSeriesId] = v
+		}
+	}
+
+	// 获取因子指标
+	edbMappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
+	edbInfoIds := make([]int, 0)
+	{
+		ob := new(data_manage.FactorEdbSeriesMapping)
+		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(req.SeriesIds)))
+		pars := make([]interface{}, 0)
+		pars = append(pars, req.SeriesIds)
+		order := fmt.Sprintf("%s ASC, %s ASC", ob.Cols().FactorEdbSeriesId, ob.Cols().EdbInfoId)
+		items, e := ob.GetItemsByCondition(cond, pars, []string{}, order)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取因子指标关联失败, Err: " + e.Error()
+			return
+		}
+		for _, v := range items {
+			edbInfoIds = append(edbInfoIds, v.EdbInfoId)
+		}
+		edbMappings = items
+	}
+	edbIdItem := make(map[int]*data_manage.EdbInfo)
+	edbItems, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取因子指标失败, Err: " + e.Error()
+		return
+	}
+	for _, v := range edbItems {
+		edbIdItem[v.EdbInfoId] = v
+	}
+
+	// 获取因子指标数据, 计算相关性
+	resp := new(data_manage.FactorEdbSeriesCorrelationMatrixResp)
+	calculateDataOb := new(data_manage.FactorEdbSeriesCalculateData)
+
+	calculateWorkers := make(chan struct{}, 10)
+	wg := sync.WaitGroup{}
+	edbExists := make(map[string]bool)
+	for _, v := range edbMappings {
+		existsKey := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
+		if edbExists[existsKey] {
+			continue
+		}
+		edbExists[existsKey] = true
+
+		edbItem := edbIdItem[v.EdbInfoId]
+		if edbItem == nil {
+			continue
+		}
+		seriesItem := seriesIdItem[v.FactorEdbSeriesId]
+		if seriesItem == nil {
+			continue
+		}
+
+		wg.Add(1)
+		go func(mapping *data_manage.FactorEdbSeriesMapping, edb *data_manage.EdbInfo, series *data_manage.FactorEdbSeries) {
+			defer func() {
+				wg.Done()
+				<-calculateWorkers
+			}()
+			calculateWorkers <- struct{}{}
+
+			var item data_manage.FactorEdbSeriesCorrelationMatrixItem
+			item.SeriesId = series.FactorEdbSeriesId
+			item.EdbInfoId = edb.EdbInfoId
+			item.EdbCode = edb.EdbCode
+			item.EdbName = edb.EdbName
+
+			// 获取指标数据
+			dataListB := make([]*data_manage.EdbDataList, 0)
+			if series.CalculateState == data_manage.FactorEdbSeriesCalculated {
+				cond := fmt.Sprintf(" AND %s = ? AND %s = ?", calculateDataOb.Cols().FactorEdbSeriesId, calculateDataOb.Cols().EdbInfoId)
+				pars := make([]interface{}, 0)
+				pars = append(pars, mapping.FactorEdbSeriesId, mapping.EdbInfoId)
+				dataItems, e := calculateDataOb.GetItemsByCondition(cond, pars, []string{calculateDataOb.Cols().DataTime, calculateDataOb.Cols().Value}, fmt.Sprintf("%s ASC", calculateDataOb.Cols().DataTime))
+				if e != nil {
+					item.Msg = fmt.Sprintf("计算失败")
+					item.ErrMsg = fmt.Sprintf("获取计算数据失败, err: %v", e)
+					resp.Fail = append(resp.Fail, item)
+					return
+				}
+				dataListB = data_manage.TransEdbSeriesCalculateData2EdbDataList(dataItems)
+			} else {
+				switch edb.EdbInfoType {
+				case 0:
+					dataListB, e = data_manage.GetEdbDataList(edb.Source, edb.SubSource, edb.EdbInfoId, "", "")
+				case 1:
+					_, dataListB, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(edb.EdbInfoId, "", "", false)
+				default:
+					item.Msg = fmt.Sprintf("计算失败")
+					item.ErrMsg = fmt.Sprintf("指标类型异常, edbType: %d", edb.EdbInfoType)
+					resp.Fail = append(resp.Fail, item)
+					return
+				}
+			}
+
+			// 计算相关性
+			xEdbIdValue, yDataList, e := correlationServ.CalculateCorrelation(req.Correlation.LeadValue, req.Correlation.LeadUnit, baseEdb.Frequency, edb.Frequency, dataListA, dataListB)
+			if e != nil {
+				item.Msg = fmt.Sprintf("计算失败")
+				item.ErrMsg = fmt.Sprintf("相关性计算失败, err: %v", e)
+				resp.Fail = append(resp.Fail, item)
+				return
+			}
+
+			// 按照固定规则排期数[0 1 2 3 -1 -2 -3]
+			yData := yDataList[0].Value
+			yLen := len(yData)
+			values := make([]data_manage.FactorEdbSeriesCorrelationMatrixValues, len(xEdbIdValue))
+			for k, x := range xEdbIdValue {
+				// y值常常会出现无数据的情况
+				var y float64
+				if k >= 0 && k < yLen {
+					y = yData[k]
+				}
+				y = utils.SubFloatToFloat(y, 2)
+				values[k] = data_manage.FactorEdbSeriesCorrelationMatrixValues{
+					XData: x, YData: y,
+				}
+			}
+			sort.Sort(data_manage.FactorEdbSeriesCorrelationMatrixOrder(values))
+
+			item.Msg = "计算成功"
+			item.Values = values
+			resp.Success = append(resp.Success, item)
+
+			// TODO:存储计算结果
+
+		}(v, edbItem, seriesItem)
+	}
+	wg.Wait()
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 11 - 0
models/data_manage/edb_info.go

@@ -1651,3 +1651,14 @@ func getAllDataByMongo(edbInfoId, source, subSource int, startDataTime string) (
 
 	return
 }
+
+func GetEdbInfoListByCond(condition string, pars []interface{}) (list []*EdbInfoList, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM edb_info WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY create_time DESC `
+	_, err = o.Raw(sql, pars).QueryRows(&list)
+	return
+}

+ 9 - 0
models/data_manage/edb_info_calculate.go

@@ -167,6 +167,7 @@ type EdbInfoBase struct {
 	UnitEn        string `description:"英文单位"`
 	ClassifyId    int    `description:"分类id"`
 	HaveOperaAuth bool   `description:"是否有数据权限,默认:false"`
+	EdbInfoType   int    `description:"指标类型: 0-普通指标; 1-预测指标"`
 }
 
 type CalculateEdbInfoItem struct {
@@ -511,6 +512,7 @@ type CalculateMultiEdbSearchResp struct {
 	SearchItem []CalculateMultiEdbSearchItem `description:"查询结果"`
 	Paging     *paging.PagingItem
 }
+
 type CalculateMultiEdbSearchItem struct {
 	EdbInfoId       int    `description:"指标id"`
 	EdbName         string `description:"指标名称"`
@@ -524,4 +526,11 @@ type CalculateMultiEdbSearchItem struct {
 	EndValue        float64 `description:"数据的最新值(预测日期的最新值)"`
 	EndDate         string  `description:"终止日期"`
 	HaveOperaAuth   bool    `description:"是否有数据权限,默认:false"`
+	EdbInfoType     int     `description:"指标类型: 0-普通指标; 1-预测指标"`
+}
+
+// BaseStepCalculateReq 指标库-基础分步骤计算请求
+type BaseStepCalculateReq struct {
+	DataList   []*EdbInfoSearchData
+	Calculates []FactorEdbSeriesCalculatePars
 }

+ 348 - 0
models/data_manage/factor_edb_series.go

@@ -0,0 +1,348 @@
+package data_manage
+
+import (
+	"encoding/json"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+const (
+	FactorEdbSeriesCalculateNone = 0
+	FactorEdbSeriesCalculating   = 1
+	FactorEdbSeriesCalculated    = 2
+)
+
+// FactorEdbSeries 因子指标系列表
+type FactorEdbSeries struct {
+	FactorEdbSeriesId int       `orm:"column(factor_edb_series_id);pk"`
+	SeriesName        string    `description:"系列名称"`
+	EdbInfoType       int       `description:"关联指标类型:0-普通指标;1-预测指标"`
+	CalculateStep     string    `description:"计算步骤-JSON"`
+	CalculateState    int       `description:"计算状态: 0-无计算; 1-计算中; 2-计算完成"`
+	CreateTime        time.Time `description:"创建时间"`
+	ModifyTime        time.Time `description:"修改时间"`
+}
+
+func (m *FactorEdbSeries) TableName() string {
+	return "factor_edb_series"
+}
+
+type FactorEdbSeriesCols struct {
+	PrimaryId      string
+	SeriesName     string
+	EdbInfoType    string
+	CalculateStep  string
+	CalculateState string
+	CreateTime     string
+	ModifyTime     string
+}
+
+func (m *FactorEdbSeries) Cols() FactorEdbSeriesCols {
+	return FactorEdbSeriesCols{
+		PrimaryId:      "factor_edb_series_id",
+		SeriesName:     "series_name",
+		EdbInfoType:    "edb_info_type",
+		CalculateStep:  "calculate_step",
+		CalculateState: "calculate_state",
+		CreateTime:     "create_time",
+		ModifyTime:     "modify_time",
+	}
+}
+
+func (m *FactorEdbSeries) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.FactorEdbSeriesId = int(id)
+	return
+}
+
+func (m *FactorEdbSeries) CreateMulti(items []*FactorEdbSeries) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *FactorEdbSeries) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *FactorEdbSeries) Remove() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	_, err = o.Raw(sql, m.FactorEdbSeriesId).Exec()
+	return
+}
+
+func (m *FactorEdbSeries) MultiRemove(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.Cols().PrimaryId, utils.GetOrmInReplace(len(ids)))
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func (m *FactorEdbSeries) GetItemById(id int) (item *FactorEdbSeries, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeries) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeries, err error) {
+	o := orm.NewOrmUsingDB("data")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeries) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *FactorEdbSeries) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FactorEdbSeries, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *FactorEdbSeries) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FactorEdbSeries, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// FactorEdbSeriesItem 多因子系列信息
+type FactorEdbSeriesItem struct {
+	SeriesId      int                            `description:"多因子系列ID"`
+	SeriesName    string                         `description:"系列名称"`
+	EdbInfoType   int                            `description:"关联指标类型:0-普通指标;1-预测指标"`
+	CalculateStep []FactorEdbSeriesCalculatePars `description:"计算步骤-JSON"`
+	CreateTime    string                         `description:"创建时间"`
+	ModifyTime    string                         `description:"修改时间"`
+}
+
+func (m *FactorEdbSeries) Format2Item() (item *FactorEdbSeriesItem) {
+	item = new(FactorEdbSeriesItem)
+	item.SeriesId = m.FactorEdbSeriesId
+	item.SeriesName = m.SeriesName
+	item.EdbInfoType = m.EdbInfoType
+	if m.CalculateStep != "" {
+		_ = json.Unmarshal([]byte(m.CalculateStep), &item.CalculateStep)
+	}
+	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, m.CreateTime)
+	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, m.ModifyTime)
+	return
+}
+
+// FactorEdbSeriesCalculatePars 计算参数
+type FactorEdbSeriesCalculatePars struct {
+	Formula       interface{} `description:"N值/移动天数/指数修匀alpha值/计算公式等"`
+	Calendar      string      `description:"公历/农历"`
+	Frequency     string      `description:"需要转换的频度"`
+	MoveType      int         `description:"移动方式: 1-领先(默认); 2-滞后"`
+	MoveFrequency string      `description:"移动频度"`
+	FromFrequency string      `description:"来源的频度"`
+	Source        int         `description:"计算方式来源(不是指标来源)"`
+	Sort          int         `description:"计算顺序"`
+}
+
+// CreateSeriesAndMapping 新增系列和指标关联
+func (m *FactorEdbSeries) CreateSeriesAndMapping(item *FactorEdbSeries, mappings []*FactorEdbSeriesMapping) (seriesId int, err error) {
+	if item == nil {
+		err = fmt.Errorf("series is nil")
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	tx, e := o.Begin()
+	if e != nil {
+		err = fmt.Errorf("orm begin err: %v", e)
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+	}()
+
+	id, e := tx.Insert(item)
+	if e != nil {
+		err = fmt.Errorf("insert series err: %v", e)
+		return
+	}
+	seriesId = int(id)
+	item.FactorEdbSeriesId = seriesId
+
+	if len(mappings) > 0 {
+		for _, v := range mappings {
+			v.FactorEdbSeriesId = seriesId
+		}
+		_, e = tx.InsertMulti(200, mappings)
+		if e != nil {
+			err = fmt.Errorf("insert multi mapping err: %v", e)
+			return
+		}
+	}
+	return
+}
+
+// EditSeriesAndMapping 编辑系列和指标关联
+func (m *FactorEdbSeries) EditSeriesAndMapping(item *FactorEdbSeries, mappings []*FactorEdbSeriesMapping, updateCols []string) (err error) {
+	if item == nil {
+		err = fmt.Errorf("series is nil")
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	tx, e := o.Begin()
+	if e != nil {
+		err = fmt.Errorf("orm begin err: %v", e)
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+	}()
+
+	_, e = tx.Update(item, updateCols...)
+	if e != nil {
+		err = fmt.Errorf("update series err: %v", e)
+		return
+	}
+
+	// 清除原指标关联
+	mappingOb := new(FactorEdbSeriesMapping)
+	cond := fmt.Sprintf("%s = ?", mappingOb.Cols().FactorEdbSeriesId)
+	pars := make([]interface{}, 0)
+	pars = append(pars, item.FactorEdbSeriesId)
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, mappingOb.TableName(), cond)
+	_, e = tx.Raw(sql, pars).Exec()
+	if e != nil {
+		err = fmt.Errorf("remove mapping err: %v", e)
+		return
+	}
+
+	if len(mappings) > 0 {
+		for _, v := range mappings {
+			v.FactorEdbSeriesId = item.FactorEdbSeriesId
+		}
+		_, e = tx.InsertMulti(200, mappings)
+		if e != nil {
+			err = fmt.Errorf("insert multi mapping err: %v", e)
+			return
+		}
+	}
+	return
+}
+
+// FactorEdbSeriesStepCalculateResp 批量计算响应
+type FactorEdbSeriesStepCalculateResp struct {
+	SeriesId int                                  `description:"多因子指标系列ID"`
+	Fail     []FactorEdbSeriesStepCalculateResult `description:"计算失败的指标"`
+	Success  []FactorEdbSeriesStepCalculateResult `description:"计算成功的指标"`
+}
+
+// FactorEdbSeriesStepCalculateResult 批量计算结果
+type FactorEdbSeriesStepCalculateResult struct {
+	EdbInfoId int    `description:"指标ID"`
+	EdbCode   string `description:"指标编码"`
+	Msg       string `description:"提示信息"`
+	ErrMsg    string `description:"错误信息"`
+}
+
+// FactorEdbSeriesDetail 因子指标系列-详情
+type FactorEdbSeriesDetail struct {
+	*FactorEdbSeriesItem
+	EdbMappings []*FactorEdbSeriesMappingItem
+}
+
+// FactorEdbSeriesCorrelationMatrixResp 因子指标系列-相关性矩阵响应
+type FactorEdbSeriesCorrelationMatrixResp struct {
+	Fail    []FactorEdbSeriesCorrelationMatrixItem `description:"计算失败的指标"`
+	Success []FactorEdbSeriesCorrelationMatrixItem `description:"计算成功的指标"`
+}
+
+// FactorEdbSeriesCorrelationMatrixItem 因子指标系列-相关性矩阵信息
+type FactorEdbSeriesCorrelationMatrixItem struct {
+	SeriesId  int                                      `description:"因子指标系列ID"`
+	EdbInfoId int                                      `description:"指标ID"`
+	EdbCode   string                                   `description:"指标编码"`
+	EdbName   string                                   `description:"指标名称"`
+	Values    []FactorEdbSeriesCorrelationMatrixValues `description:"X轴和Y轴数据"`
+	Msg       string                                   `description:"提示信息"`
+	ErrMsg    string                                   `description:"错误信息"`
+}
+
+// FactorEdbSeriesCorrelationMatrixValues 因子指标系列-相关性矩阵XY值
+type FactorEdbSeriesCorrelationMatrixValues struct {
+	XData int     `description:"X轴数据"`
+	YData float64 `description:"Y轴数据"`
+}
+
+// FactorEdbSeriesCorrelationMatrixOrder 排序规则[0 1 2 3 -1 -2 -3]
+type FactorEdbSeriesCorrelationMatrixOrder []FactorEdbSeriesCorrelationMatrixValues
+
+func (a FactorEdbSeriesCorrelationMatrixOrder) Len() int {
+	return len(a)
+}
+
+func (a FactorEdbSeriesCorrelationMatrixOrder) Swap(i, j int) {
+	a[i], a[j] = a[j], a[i]
+}
+
+func (a FactorEdbSeriesCorrelationMatrixOrder) Less(i, j int) bool {
+	// 非负数优先
+	if a[i].XData >= 0 && a[j].XData < 0 {
+		return true
+	}
+	if a[i].XData < 0 && a[j].XData >= 0 {
+		return false
+	}
+	// 非负数升序排序
+	if a[i].XData >= 0 {
+		return a[i].XData < a[j].XData
+	}
+	// 负数按绝对值的降序排序(即数值的升序)
+	return a[i].XData > a[j].XData
+}

+ 190 - 0
models/data_manage/factor_edb_series_calculate_data.go

@@ -0,0 +1,190 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// FactorEdbSeriesCalculateData 因子指标系列-指标计算数据表
+type FactorEdbSeriesCalculateData struct {
+	FactorEdbSeriesCalculateDataId int       `orm:"column(factor_edb_series_calculate_data_id);pk"`
+	FactorEdbSeriesId              int       `description:"因子指标系列ID"`
+	EdbInfoId                      int       `description:"指标ID"`
+	EdbCode                        string    `description:"指标编码"`
+	DataTime                       time.Time `description:"数据日期"`
+	Value                          float64   `description:"数据值"`
+	CreateTime                     time.Time `description:"创建时间"`
+	ModifyTime                     time.Time `description:"修改时间"`
+	DataTimestamp                  int64     `description:"数据日期时间戳"`
+}
+
+func (m *FactorEdbSeriesCalculateData) TableName() string {
+	return "factor_edb_series_calculate_data"
+}
+
+type FactorEdbSeriesCalculateDataCols struct {
+	PrimaryId         string
+	FactorEdbSeriesId string
+	EdbInfoId         string
+	EdbCode           string
+	DataTime          string
+	Value             string
+	CreateTime        string
+	ModifyTime        string
+	DataTimestamp     string
+}
+
+func (m *FactorEdbSeriesCalculateData) Cols() FactorEdbSeriesCalculateDataCols {
+	return FactorEdbSeriesCalculateDataCols{
+		PrimaryId:         "factor_edb_series_calculate_data_id",
+		FactorEdbSeriesId: "factor_edb_series_id",
+		EdbInfoId:         "edb_info_id",
+		EdbCode:           "edb_code",
+		DataTime:          "data_time",
+		Value:             "value",
+		CreateTime:        "create_time",
+		ModifyTime:        "modify_time",
+		DataTimestamp:     "data_timestamp",
+	}
+}
+
+func (m *FactorEdbSeriesCalculateData) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.FactorEdbSeriesCalculateDataId = int(id)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) CreateMulti(items []*FactorEdbSeriesCalculateData) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(500, items)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) Remove() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	_, err = o.Raw(sql, m.FactorEdbSeriesCalculateDataId).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) MultiRemove(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.Cols().PrimaryId, utils.GetOrmInReplace(len(ids)))
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) RemoveByCondition(condition string, pars []interface{}) (err error) {
+	if condition == "" {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, m.TableName(), condition)
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) GetItemById(id int) (item *FactorEdbSeriesCalculateData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeriesCalculateData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FactorEdbSeriesCalculateData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateData) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FactorEdbSeriesCalculateData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// FactorEdbSeriesCalculateDataItem 因子指标系列-计算数据信息
+type FactorEdbSeriesCalculateDataItem struct {
+	DataId            int     `description:"数据ID"`
+	FactorEdbSeriesId int     `description:"因子指标系列ID"`
+	EdbInfoId         int     `description:"指标ID"`
+	EdbCode           string  `description:"指标编码"`
+	DataTime          string  `description:"数据日期"`
+	Value             float64 `description:"数据值"`
+}
+
+func (m *FactorEdbSeriesCalculateData) Format2Item() (item *FactorEdbSeriesCalculateDataItem) {
+	item = new(FactorEdbSeriesCalculateDataItem)
+	item.DataId = m.FactorEdbSeriesCalculateDataId
+	item.FactorEdbSeriesId = m.FactorEdbSeriesId
+	item.EdbInfoId = m.EdbInfoId
+	item.EdbCode = m.EdbCode
+	return
+}
+
+// TransEdbSeriesCalculateData2EdbDataList 转换数据格式
+func TransEdbSeriesCalculateData2EdbDataList(items []*FactorEdbSeriesCalculateData) (list []*EdbDataList) {
+	list = make([]*EdbDataList, 0)
+	for _, v := range items {
+		list = append(list, &EdbDataList{
+			DataTime: v.DataTime.Format(utils.FormatDate),
+			Value:    v.Value,
+		})
+	}
+	return
+}

+ 153 - 0
models/data_manage/factor_edb_series_calculate_func.go

@@ -0,0 +1,153 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// FactorEdbSeriesCalculateFunc 多因子系列-计算方式表
+type FactorEdbSeriesCalculateFunc struct {
+	FactorEdbSeriesCalculateFuncId int       `orm:"column(factor_edb_series_calculate_func_id);pk"`
+	CalculateName                  string    `description:"计算方式名称"`
+	Source                         int       `description:"计算方式来源"`
+	EdbInfoType                    int       `description:"指标计算类型:0-普通指标;1-预测指标"`
+	CreateTime                     time.Time `description:"创建时间"`
+	ModifyTime                     time.Time `description:"修改时间"`
+}
+
+func (m *FactorEdbSeriesCalculateFunc) TableName() string {
+	return "factor_edb_series_calculate_func"
+}
+
+type FactorEdbSeriesCalculateFuncCols struct {
+	PrimaryId     string
+	CalculateName string
+	Source        string
+	EdbInfoType   string
+	CreateTime    string
+	ModifyTime    string
+}
+
+func (m *FactorEdbSeriesCalculateFunc) Cols() FactorEdbSeriesCalculateFuncCols {
+	return FactorEdbSeriesCalculateFuncCols{
+		PrimaryId:     "factor_edb_series_calculate_func_id",
+		CalculateName: "calculate_name",
+		Source:        "source",
+		EdbInfoType:   "edb_info_type",
+		CreateTime:    "create_time",
+		ModifyTime:    "modify_time",
+	}
+}
+
+func (m *FactorEdbSeriesCalculateFunc) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.FactorEdbSeriesCalculateFuncId = int(id)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) CreateMulti(items []*FactorEdbSeriesCalculateFunc) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) Remove() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	_, err = o.Raw(sql, m.FactorEdbSeriesCalculateFuncId).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) MultiRemove(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.Cols().PrimaryId, utils.GetOrmInReplace(len(ids)))
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) GetItemById(id int) (item *FactorEdbSeriesCalculateFunc, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeriesCalculateFunc, err error) {
+	o := orm.NewOrmUsingDB("data")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FactorEdbSeriesCalculateFunc, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateFunc) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FactorEdbSeriesCalculateFunc, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// FactorEdbSeriesCalculateFuncItem 多因子系列-计算方式
+type FactorEdbSeriesCalculateFuncItem struct {
+	CalculateName string `description:"计算方式名称"`
+	Source        int    `description:"计算方式来源"`
+}
+
+func (m *FactorEdbSeriesCalculateFunc) Format2Item() (item *FactorEdbSeriesCalculateFuncItem) {
+	item = new(FactorEdbSeriesCalculateFuncItem)
+	item.CalculateName = m.CalculateName
+	item.Source = m.Source
+	return
+}

+ 140 - 0
models/data_manage/factor_edb_series_chart_mapping.go

@@ -0,0 +1,140 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// FactorEdbSeriesChartMapping 因子指标系列-图表关联
+type FactorEdbSeriesChartMapping struct {
+	MultipleFactorSeriesChartMappingId int       `orm:"column(factor_edb_series_chart_mapping_id);pk"`
+	MultipleFactorSeriesId             int       `description:"因子指标系列ID"`
+	ChartInfoId                        int       `description:"图表ID"`
+	Source                             int       `description:"图表来源,同chart_info表source"`
+	CreateTime                         time.Time `description:"创建时间"`
+	ModifyTime                         time.Time `description:"修改时间"`
+}
+
+func (m *FactorEdbSeriesChartMapping) TableName() string {
+	return "factor_edb_series_chart_mapping"
+}
+
+type MultipleFactorSeriesChartMappingCols struct {
+	PrimaryId         string
+	FactorEdbSeriesId string
+	ChartInfoId       string
+	Source            string
+	CreateTime        string
+	ModifyTime        string
+}
+
+func (m *FactorEdbSeriesChartMapping) Cols() MultipleFactorSeriesChartMappingCols {
+	return MultipleFactorSeriesChartMappingCols{
+		PrimaryId:         "factor_edb_series_chart_mapping_id",
+		FactorEdbSeriesId: "factor_edb_series_id",
+		ChartInfoId:       "chart_info_id",
+		Source:            "source",
+		CreateTime:        "create_time",
+		ModifyTime:        "modify_time",
+	}
+}
+
+func (m *FactorEdbSeriesChartMapping) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.MultipleFactorSeriesChartMappingId = int(id)
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) CreateMulti(items []*FactorEdbSeriesChartMapping) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) Remove() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	_, err = o.Raw(sql, m.MultipleFactorSeriesChartMappingId).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) MultiRemove(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.Cols().PrimaryId, utils.GetOrmInReplace(len(ids)))
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) GetItemById(id int) (item *FactorEdbSeriesChartMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeriesChartMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FactorEdbSeriesChartMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *FactorEdbSeriesChartMapping) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FactorEdbSeriesChartMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}

+ 165 - 0
models/data_manage/factor_edb_series_mapping.go

@@ -0,0 +1,165 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// FactorEdbSeriesMapping 因子指标系列-指标关联表
+type FactorEdbSeriesMapping struct {
+	FactorEdbSeriesMappingId int       `orm:"column(factor_edb_series_mapping_id);pk"`
+	FactorEdbSeriesId        int       `description:"因子指标系列ID"`
+	EdbInfoId                int       `description:"指标ID"`
+	EdbCode                  string    `description:"指标编码"`
+	CreateTime               time.Time `description:"创建时间"`
+	ModifyTime               time.Time `description:"修改时间"`
+}
+
+func (m *FactorEdbSeriesMapping) TableName() string {
+	return "factor_edb_series_mapping"
+}
+
+type FactorEdbSeriesMappingCols struct {
+	PrimaryId         string
+	FactorEdbSeriesId string
+	EdbInfoId         string
+	EdbCode           string
+	CreateTime        string
+	ModifyTime        string
+}
+
+func (m *FactorEdbSeriesMapping) Cols() FactorEdbSeriesMappingCols {
+	return FactorEdbSeriesMappingCols{
+		PrimaryId:         "factor_edb_series_mapping_id",
+		FactorEdbSeriesId: "factor_edb_series_id",
+		EdbInfoId:         "edb_info_id",
+		EdbCode:           "edb_code",
+		CreateTime:        "create_time",
+		ModifyTime:        "modify_time",
+	}
+}
+
+func (m *FactorEdbSeriesMapping) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.FactorEdbSeriesMappingId = int(id)
+	return
+}
+
+func (m *FactorEdbSeriesMapping) CreateMulti(items []*FactorEdbSeriesMapping) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *FactorEdbSeriesMapping) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *FactorEdbSeriesMapping) Remove() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	_, err = o.Raw(sql, m.FactorEdbSeriesMappingId).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesMapping) MultiRemove(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.Cols().PrimaryId, utils.GetOrmInReplace(len(ids)))
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesMapping) RemoveByCondition(condition string, pars []interface{}) (err error) {
+	if condition == "" {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, m.TableName(), condition)
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesMapping) GetItemById(id int) (item *FactorEdbSeriesMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesMapping) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeriesMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesMapping) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *FactorEdbSeriesMapping) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FactorEdbSeriesMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *FactorEdbSeriesMapping) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FactorEdbSeriesMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// FactorEdbSeriesMappingItem 因子指标系列-指标关联信息
+type FactorEdbSeriesMappingItem struct {
+	SeriesId  int    `description:"因子指标系列ID"`
+	EdbInfoId int    `description:"指标ID"`
+	EdbCode   string `description:"指标编码"`
+}
+
+func (m *FactorEdbSeriesMapping) Format2Item() (item *FactorEdbSeriesMappingItem) {
+	item = new(FactorEdbSeriesMappingItem)
+	item.SeriesId = m.FactorEdbSeriesId
+	item.EdbInfoId = m.EdbInfoId
+	item.EdbCode = m.EdbCode
+	return
+}

+ 25 - 0
models/data_manage/request/factor_edb_series.go

@@ -0,0 +1,25 @@
+package request
+
+import "eta/eta_api/models/data_manage"
+
+// AddFactorEdbSeriesReq 新增因子指标系列
+type AddFactorEdbSeriesReq struct {
+	SeriesName  string                                     `description:"系列名称"`
+	EdbInfoType int                                        `description:"指标类型: 0-普通指标; 1-预测指标"`
+	Calculates  []data_manage.FactorEdbSeriesCalculatePars `description:"多步骤计算方式"`
+	EdbInfoIds  []int                                      `description:"指标IDs"`
+}
+
+// EditFactorEdbSeriesReq 编辑因子指标系列
+type EditFactorEdbSeriesReq struct {
+	SeriesId int `description:"系列ID"`
+	AddFactorEdbSeriesReq
+	Recalculate bool `description:"是否需要重新计算"`
+}
+
+// FactorEdbSeriesCorrelationMatrixReq 因子指标系列-相关性矩阵
+type FactorEdbSeriesCorrelationMatrixReq struct {
+	BaseEdbInfoId int                           `description:"标的指标ID"`
+	SeriesIds     []int                         `description:"因子指标系列IDs"`
+	Correlation   data_manage.CorrelationConfig `description:"相关性配置"`
+}

+ 13 - 0
models/db.go

@@ -198,6 +198,9 @@ func init() {
 	// 初始化外汇日历
 	initFeCalendar()
 
+	// 初始化因子指标系列
+	initFactorEdbSeries()
+
 	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
 	data_manage.InitEdbSourceVar()
 }
@@ -599,3 +602,13 @@ func initFeCalendar() {
 		new(fe_calendar.FeCalendarMatter), // 事项表
 	)
 }
+
+// initFactorEdbSeries 因子指标系列数据表
+func initFactorEdbSeries() {
+	orm.RegisterModel(
+		new(data_manage.FactorEdbSeries),              // 因子指标系列
+		new(data_manage.FactorEdbSeriesChartMapping),  // 因子指标系列-图表关联
+		new(data_manage.FactorEdbSeriesMapping),       // 因子指标系列-指标计算数据
+		new(data_manage.FactorEdbSeriesCalculateData), // 因子指标系列-指标关联
+	)
+}

+ 45 - 0
routers/commentsRouter.go

@@ -4264,6 +4264,51 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/factor_edb_series/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"],
+        beego.ControllerComments{
+            Method: "CalculateFuncList",
+            Router: `/factor_edb_series/calculate_func/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"],
+        beego.ControllerComments{
+            Method: "CorrelationMatrix",
+            Router: `/factor_edb_series/correlation/matrix`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/factor_edb_series/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:FactorEdbSeriesController"],
+        beego.ControllerComments{
+            Method: "Edit",
+            Router: `/factor_edb_series/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:JiaYueEdbSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:JiaYueEdbSourceController"],
         beego.ControllerComments{
             Method: "FrequencyList",

+ 1 - 0
routers/router.go

@@ -170,6 +170,7 @@ func init() {
 				&data_manage_permission.DataMangePermissionController{},
 				&data_manage.BloombergDataController{},
 				&data_manage.EdbBusinessController{},
+				&data_manage.FactorEdbSeriesController{},
 			),
 		),
 		web.NSNamespace("/my_chart",

+ 11 - 0
services/data/base_edb_lib.go

@@ -558,3 +558,14 @@ func HttpPost(url, postData, lang string, params ...string) ([]byte, error) {
 	utils.FileLog.Debug("HttpPost:" + string(b))
 	return b, err
 }
+
+// BaseStepCalculate 基础运算-多步骤
+func BaseStepCalculate(param, lang string) (resp *BaseCalculateResp, err error) {
+	urlStr := "calculate/base/step_calculate"
+	_, resultByte, err := postAddEdbData(param, urlStr, lang)
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}

+ 188 - 0
services/data/correlation/chart_info.go

@@ -1219,3 +1219,191 @@ func CopyChartInfo(configId, classifyId int, chartName string, correlationChartI
 
 	return
 }
+
+// CalculateCorrelation 计算相关性-获取x轴和y轴
+func CalculateCorrelation(leadValue int, leadUnit, frequencyA, frequencyB string, dataListA, dataListB []*data_manage.EdbDataList) (xEdbIdValue []int, yDataList []data_manage.YData, err error) {
+	xData := make([]int, 0)
+	yData := make([]float64, 0)
+	if leadValue == 0 {
+		xData = append(xData, 0)
+	}
+	if leadValue > 0 {
+		leadMin := 0 - leadValue
+		xLen := 2*leadValue + 1
+		for i := 0; i < xLen; i++ {
+			n := leadMin + i
+			xData = append(xData, n)
+		}
+	}
+
+	// 计算窗口,不包含第一天
+	//startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+	//startDate = startDateTime.AddDate(0, 0, 1).Format(utils.FormatDate)
+
+	//// 2023-03-02 时间序列始终以指标B为基准, 始终是A进行平移
+	//baseEdbInfo := edbInfoMappingB
+	//changeEdbInfo := edbInfoMappingA
+	// 2023-03-17 时间序列始终以指标A为基准, 始终是B进行平移
+	//baseEdbInfo := edbInfoMappingA
+	//changeEdbInfo := edbInfoMappingB
+
+	// 获取时间基准指标在时间区间内的值
+	//aDataList := make([]*data_manage.EdbDataList, 0)
+	//switch baseEdbInfo.EdbInfoCategoryType {
+	//case 0:
+	//	aDataList, err = data_manage.GetEdbDataList(baseEdbInfo.Source, baseEdbInfo.SubSource, baseEdbInfo.EdbInfoId, startDate, endDate)
+	//case 1:
+	//	_, aDataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdbInfo.EdbInfoId, startDate, endDate, false)
+	//default:
+	//	err = errors.New("指标base类型异常")
+	//	return
+	//}
+	//
+	//// 获取变频指标所有日期的值, 插值法完善数据
+	//bDataList := make([]*data_manage.EdbDataList, 0)
+	//switch changeEdbInfo.EdbInfoCategoryType {
+	//case 0:
+	//	bDataList, err = data_manage.GetEdbDataList(changeEdbInfo.Source, changeEdbInfo.SubSource, changeEdbInfo.EdbInfoId, "", "")
+	//case 1:
+	//	_, bDataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(changeEdbInfo.EdbInfoId, "", "", false)
+	//default:
+	//	err = errors.New("指标change类型异常")
+	//	return
+	//}
+	//changeDataMap := make(map[string]float64)
+	//newChangeDataList, e := HandleDataByLinearRegression(bDataList, changeDataMap)
+	//if e != nil {
+	//	err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
+	//	return
+	//}
+
+	// 2023-03-17 时间序列始终以指标A为基准, 始终是B进行平移
+	baseDataList := make([]*data_manage.EdbDataList, 0)
+	baseDataMap := make(map[string]float64)
+	changeDataList := make([]*data_manage.EdbDataList, 0)
+	changeDataMap := make(map[string]float64)
+
+	// 先把低频指标升频为高频
+	{
+		frequencyIntMap := map[string]int{
+			"日度": 1,
+			"周度": 2,
+			"旬度": 3,
+			"月度": 4,
+			"季度": 5,
+			"年度": 6,
+		}
+
+		// 如果A指标是高频,那么就需要对B指标进行升频
+		if frequencyIntMap[frequencyA] < frequencyIntMap[frequencyB] {
+			tmpNewChangeDataList, e := HandleDataByLinearRegression(dataListB, changeDataMap)
+			if e != nil {
+				err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
+				return
+			}
+			changeDataList = tmpNewChangeDataList
+			baseDataList = dataListA
+			for _, v := range baseDataList {
+				baseDataMap[v.DataTime] = v.Value
+			}
+
+		} else if frequencyIntMap[frequencyA] > frequencyIntMap[frequencyB] {
+			// 如果B指标是高频,那么就需要对A指标进行升频
+			tmpNewChangeDataList, e := HandleDataByLinearRegression(dataListA, baseDataMap)
+			if e != nil {
+				err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
+				return
+			}
+			baseDataList = tmpNewChangeDataList
+
+			changeDataList = dataListB
+			for _, v := range changeDataList {
+				changeDataMap[v.DataTime] = v.Value
+			}
+		} else {
+			baseDataList = dataListA
+			for _, v := range baseDataList {
+				baseDataMap[v.DataTime] = v.Value
+			}
+			changeDataList = dataListB
+			for _, v := range changeDataList {
+				changeDataMap[v.DataTime] = v.Value
+			}
+		}
+
+	}
+
+	// 计算不领先也不滞后时的相关系数
+	baseCalculateData := make([]float64, 0)
+	baseDataTimeArr := make([]string, 0)
+	for i := range baseDataList {
+		baseDataTimeArr = append(baseDataTimeArr, baseDataList[i].DataTime)
+		baseCalculateData = append(baseCalculateData, baseDataList[i].Value)
+	}
+
+	//zeroBaseData := make([]float64, 0)
+	//zeroCalculateData := make([]float64, 0)
+	//for i := range baseDataTimeArr {
+	//	tmpBaseVal, ok1 := baseDataMap[baseDataTimeArr[i]]
+	//	tmpCalculateVal, ok2 := changeDataMap[baseDataTimeArr[i]]
+	//	if ok1 && ok2 {
+	//		zeroBaseData = append(zeroBaseData, tmpBaseVal)
+	//		zeroCalculateData = append(zeroCalculateData, tmpCalculateVal)
+	//	}
+	//}
+	//if len(zeroBaseData) != len(zeroCalculateData) {
+	//	err = fmt.Errorf("相关系数两组序列元素数不一致, %d-%d", len(baseCalculateData), len(zeroCalculateData))
+	//	return
+	//}
+	//zeroRatio := utils.CalculateCorrelationByIntArr(zeroBaseData, zeroCalculateData)
+	//if leadValue == 0 {
+	//	yData = append(yData, zeroRatio)
+	//}
+
+	// 计算领先/滞后N期
+	if leadValue > 0 {
+		// 平移变频指标领先/滞后的日期(单位天)
+		moveUnitDays := utils.FrequencyDaysMap[leadUnit]
+
+		for i := range xData {
+			//if xData[i] == 0 {
+			//	yData = append(yData, zeroRatio)
+			//	continue
+			//}
+			xCalculateData := make([]float64, 0)
+			yCalculateData := make([]float64, 0)
+
+			// 平移指定天数
+			mDays := int(moveUnitDays) * xData[i]
+			_, dMap := MoveDataDaysToNewDataList(changeDataList, mDays)
+
+			// 取出对应的基准日期的值
+			for i2 := range baseDataTimeArr {
+				tmpDate := baseDataTimeArr[i2]
+				if yVal, ok := dMap[tmpDate]; ok {
+					xCalculateData = append(xCalculateData, baseCalculateData[i2])
+					yCalculateData = append(yCalculateData, yVal)
+				}
+			}
+			if len(yCalculateData) <= 0 {
+				//err = fmt.Errorf("领先滞后相关系数两组序列元素数不一致, %d-%d", len(baseCalculateData), len(yCalculateData))
+				//return
+				// 领先滞后后,没有可以计算的数据了
+				continue
+			}
+
+			// 公式计算出领先/滞后频度对应点的相关性系数
+			ratio := utils.CalculateCorrelationByIntArr(xCalculateData, yCalculateData)
+			yData = append(yData, ratio)
+		}
+	}
+
+	xEdbIdValue = xData
+	yDataList = make([]data_manage.YData, 0)
+	yDate := "0000-00-00"
+	yDataList = append(yDataList, data_manage.YData{
+		Date:  yDate,
+		Value: yData,
+	})
+	return
+}

+ 143 - 0
services/data/factor_edb_series.go

@@ -0,0 +1,143 @@
+package data
+
+import (
+	"encoding/json"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/utils"
+	"fmt"
+	"sync"
+	"time"
+)
+
+// FactorEdbStepCalculate 因子指标-多公式计算
+func FactorEdbStepCalculate(seriesId int, edbArr []*data_manage.EdbInfo, calculates []data_manage.FactorEdbSeriesCalculatePars, lang string, recalculate bool) (calculateResp data_manage.FactorEdbSeriesStepCalculateResp, err error) {
+	if len(edbArr) == 0 || len(calculates) == 0 {
+		return
+	}
+	defer func() {
+		if err != nil {
+			tips := fmt.Sprintf("StepCalculate计算失败, ErrMsg: %v", err)
+			fmt.Println(tips)
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 3)
+		}
+		if len(calculateResp.Fail) > 0 {
+			tips := "StepCalculate计算失败, ErrMsg: "
+			for _, f := range calculateResp.Fail {
+				tips += fmt.Sprintf("code: %s, err: %s\n", f.EdbCode, f.ErrMsg)
+			}
+			fmt.Println(tips)
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 2)
+		}
+	}()
+
+	// 重新计算-先清除原数据
+	calculateDataOb := new(data_manage.FactorEdbSeriesCalculateData)
+	if recalculate {
+		cond := fmt.Sprintf("%s = ?", calculateDataOb.Cols().FactorEdbSeriesId)
+		pars := make([]interface{}, 0)
+		pars = append(pars, seriesId)
+		if e := calculateDataOb.RemoveByCondition(cond, pars); e != nil {
+			err = fmt.Errorf("清除原数据失败, err: %v", e)
+			return
+		}
+	}
+
+	wg := sync.WaitGroup{}
+	calculateWorkers := make(chan struct{}, 10)
+	for _, edb := range edbArr {
+		wg.Add(1)
+		go func(v *data_manage.EdbInfo) {
+			defer func() {
+				wg.Done()
+				<-calculateWorkers
+			}()
+			calculateWorkers <- struct{}{}
+
+			var result data_manage.FactorEdbSeriesStepCalculateResult
+			result.EdbInfoId = v.EdbInfoId
+			result.EdbCode = v.EdbCode
+			result.Msg = "计算失败"
+
+			// 获取基础数据
+			edbData, e := data_manage.GetEdbDataAllByEdbCode(v.EdbCode, v.Source, v.SubSource, 0)
+			if e != nil {
+				result.ErrMsg = fmt.Sprintf("获取基础数据失败, edbCode: %s, err: %v", v.EdbCode, e)
+				calculateResp.Fail = append(calculateResp.Fail, result)
+				return
+			}
+			if len(edbData) == 0 {
+				result.Msg = "该指标无基础数据"
+				result.ErrMsg = fmt.Sprintf("该指标无基础数据, edbCode: %s", v.EdbCode)
+				calculateResp.Fail = append(calculateResp.Fail, result)
+				return
+			}
+
+			// 请求指标服务进行计算
+			j, e := json.Marshal(data_manage.BaseStepCalculateReq{
+				DataList:   edbData,
+				Calculates: calculates,
+			})
+			if e != nil {
+				result.ErrMsg = fmt.Sprintf("请求体JSON格式化失败, edbCode: %s, err: %v", v.EdbCode, e)
+				calculateResp.Fail = append(calculateResp.Fail, result)
+				return
+			}
+			requestRes, e := BaseStepCalculate(string(j), lang)
+			if e != nil {
+				result.ErrMsg = fmt.Sprintf("指标计算响应失败, edbCode: %s, err: %v", v.EdbCode, e)
+				calculateResp.Fail = append(calculateResp.Fail, result)
+				return
+			}
+			if requestRes.Ret != 200 {
+				result.Msg = requestRes.Msg
+				result.ErrMsg = requestRes.ErrMsg
+				calculateResp.Fail = append(calculateResp.Fail, result)
+				return
+			}
+
+			// 计算成功的保存结果
+			dataArr := make([]*data_manage.FactorEdbSeriesCalculateData, 0)
+			for _, d := range requestRes.Data.DateList {
+				val, ok := requestRes.Data.DataMap[d]
+				if !ok {
+					continue
+				}
+				dataTime, e := time.ParseInLocation(time.DateOnly, d, time.Local)
+				if e != nil {
+					result.ErrMsg = fmt.Sprintf("解析计算结果日期失败, edbCode: %s, date: %s, err: %v, ", v.EdbCode, d, e)
+					calculateResp.Fail = append(calculateResp.Fail, result)
+					return
+				}
+				dataArr = append(dataArr, &data_manage.FactorEdbSeriesCalculateData{
+					FactorEdbSeriesId: seriesId,
+					EdbInfoId:         v.EdbInfoId,
+					EdbCode:           v.EdbCode,
+					DataTime:          dataTime,
+					Value:             val,
+					CreateTime:        time.Now().Local(),
+					ModifyTime:        time.Now().Local(),
+					DataTimestamp:     dataTime.UnixNano() / 1e6,
+				})
+			}
+			if len(dataArr) == 0 {
+				result.Msg = "计算结果无数据"
+				result.ErrMsg = fmt.Sprintf("计算结果无数据, edbCode: %s", v.EdbCode)
+				calculateResp.Fail = append(calculateResp.Fail, result)
+				return
+			}
+			if e = calculateDataOb.CreateMulti(dataArr); e != nil {
+				result.ErrMsg = fmt.Sprintf("保存计算结果失败, edbCode: %s, err: %v, ", v.EdbCode, e)
+				calculateResp.Fail = append(calculateResp.Fail, result)
+				return
+			}
+
+			result.Msg = "计算成功"
+			calculateResp.Success = append(calculateResp.Success, result)
+		}(edb)
+	}
+	wg.Wait()
+	return
+}

+ 20 - 0
utils/constants.go

@@ -430,3 +430,23 @@ const (
 	ZhLangVersion = "zh" // 中文语言版本
 	EnLangVersion = "en" // 英文语言版本
 )
+
+// 指标计算方式
+const (
+	EdbBaseCalculateLjzzy                = 1  // 累计值转月->1
+	EdbBaseCalculateLjzzj                = 2  // 累计值转季->2
+	EdbBaseCalculateTbz                  = 3  // 同比值->3
+	EdbBaseCalculateTcz                  = 4  // 同差值->4
+	EdbBaseCalculateNszydpjjs            = 5  // N数值移动平均数计算->5
+	EdbBaseCalculateHbz                  = 6  // 环比值->6
+	EdbBaseCalculateHcz                  = 7  // 环差值->7
+	EdbBaseCalculateUpFrequency          = 8  // 升频->8
+	EdbBaseCalculateDownFrequency        = 9  // 降频->9
+	EdbBaseCalculateTimeShift            = 10 // 时间移位->10
+	EdbBaseCalculateCjjx                 = 11 // 超季节性->11
+	EdbBaseCalculateAnnualized           = 12 // 年化->12
+	EdbBaseCalculateLjz                  = 13 // 累计值->13
+	EdbBaseCalculateLjzNczj              = 14 // 累计值年初至今->14
+	EdbBaseCalculateExponentialSmoothing = 15 // 指数修匀->15
+	EdbBaseCalculateRjz                  = 16 // 日均值->16
+)