Browse Source

多因子相关性图

hsun 8 months ago
parent
commit
a44420262f

+ 945 - 57
controllers/data_manage/correlation/correlation_chart_info.go

@@ -698,49 +698,72 @@ func (this *CorrelationChartInfoController) Detail() {
 		br.ErrMsg = "获取相关性图表, A指标mapping信息失败, Err:" + e.Error()
 		return
 	}
-	edbInfoMappingB, e := data_manage.GetChartEdbMappingByEdbInfoId(correlationChart.EdbInfoIdSecond)
-	if e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取相关性图表, B指标mapping信息失败, Err:" + e.Error()
-		return
+	edbInfoMappingB := new(data_manage.ChartEdbInfoMapping)
+	// 非多因子
+	if correlationChart.AnalysisMode != 1 {
+		edbInfoMappingB, e = data_manage.GetChartEdbMappingByEdbInfoId(correlationChart.EdbInfoIdSecond)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取相关性图表, B指标mapping信息失败, Err:" + e.Error()
+			return
+		}
 	}
 
 	var dataResp interface{} // 绘图数据返回(目前是滚动相关性的图)
 	var xEdbIdValue []int
 	var yDataList []data_manage.YData
-	switch chartInfo.Source {
-	case utils.CHART_SOURCE_CORRELATION: // 相关性图
-		moveUnitDays, ok := utils.FrequencyDaysMap[correlationChart.CalculateUnit]
-		if !ok {
-			br.Msg = "错误的分析周期"
-			br.IsSendEmail = false
-			return
-		}
-		startDate := time.Now().AddDate(0, 0, -correlationChart.CalculateValue*moveUnitDays).Format(utils.FormatDate)
-		endDate := time.Now().Format(utils.FormatDate)
+	if correlationChart.AnalysisMode != 1 {
+		switch chartInfo.Source {
+		case utils.CHART_SOURCE_CORRELATION: // 相关性图
+			moveUnitDays, ok := utils.FrequencyDaysMap[correlationChart.CalculateUnit]
+			if !ok {
+				br.Msg = "错误的分析周期"
+				br.IsSendEmail = false
+				return
+			}
+			startDate := time.Now().AddDate(0, 0, -correlationChart.CalculateValue*moveUnitDays).Format(utils.FormatDate)
+			endDate := time.Now().Format(utils.FormatDate)
 
-		xEdbIdValue, yDataList, e = correlationServ.GetChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, correlationChart.LeadValue, correlationChart.LeadUnit, startDate, endDate)
+			xEdbIdValue, yDataList, e = correlationServ.GetChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, correlationChart.LeadValue, correlationChart.LeadUnit, startDate, endDate)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取相关性图表, 图表计算值失败, Err:" + e.Error()
+				return
+			}
+		case utils.CHART_SOURCE_ROLLING_CORRELATION: // 滚动相关性图
+			startDate, endDate := utils.GetDateByDateType(correlationChart.DateType, correlationChart.StartDate.Format(utils.FormatDate), correlationChart.EndDate.Format(utils.FormatDate))
+			dataResp, e = correlationServ.GetRollingCorrelationChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, correlationChart.LeadValue, correlationChart.LeadUnit, correlationChart.CalculateValue, correlationChart.CalculateUnit, startDate, endDate, chartInfo.ChartName, chartInfo.ChartNameEn)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取滚动相关性图表, 图表计算值失败, Err:" + e.Error()
+				return
+			}
+		}
+	} else {
+		xEdbIdValue, yDataList, e = correlationServ.GetFactorChartDataByChartId(chartInfoId, chartInfo.ExtraConfig)
 		if e != nil {
 			br.Msg = "获取失败"
 			br.ErrMsg = "获取相关性图表, 图表计算值失败, Err:" + e.Error()
 			return
 		}
-	case utils.CHART_SOURCE_ROLLING_CORRELATION: // 滚动相关性图
-		startDate, endDate := utils.GetDateByDateType(correlationChart.DateType, correlationChart.StartDate.Format(utils.FormatDate), correlationChart.EndDate.Format(utils.FormatDate))
-		dataResp, e = correlationServ.GetRollingCorrelationChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, correlationChart.LeadValue, correlationChart.LeadUnit, correlationChart.CalculateValue, correlationChart.CalculateUnit, startDate, endDate, chartInfo.ChartName, chartInfo.ChartNameEn)
+	}
+
+	// 完善指标信息
+	edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	if correlationChart.AnalysisMode != 1 {
+		edbList, e = correlationServ.GetChartEdbInfoFormat(chartInfo.ChartInfoId, edbInfoMappingA, edbInfoMappingB)
 		if e != nil {
 			br.Msg = "获取失败"
-			br.ErrMsg = "获取滚动相关性图表, 图表计算值失败, Err:" + e.Error()
+			br.ErrMsg = "获取相关性图表, 完善指标信息失败, Err:" + e.Error()
+			return
+		}
+	} else {
+		// 多因子指标, 获取图表引用到的系列指标(去重后)
+		edbList, e = data_manage.GetChartEdbMappingListByIdList([]int{chartInfoId})
+		if e != nil {
+			err = fmt.Errorf("获取图表引用系列指标失败, err: %v", e)
 			return
 		}
-	}
-
-	// 完善指标信息
-	edbList, e := correlationServ.GetChartEdbInfoFormat(chartInfo.ChartInfoId, edbInfoMappingA, edbInfoMappingB)
-	if e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取相关性图表, 完善指标信息失败, Err:" + e.Error()
-		return
 	}
 	correlationInfo := new(data_manage.CorrelationInfo)
 	correlationInfo.LeadValue = correlationChart.LeadValue
@@ -752,6 +775,7 @@ func (this *CorrelationChartInfoController) Detail() {
 	correlationInfo.LeadValue = correlationChart.LeadValue
 	correlationInfo.EdbInfoIdFirst = correlationChart.EdbInfoIdFirst
 	correlationInfo.EdbInfoIdSecond = correlationChart.EdbInfoIdSecond
+	correlationInfo.AnalysisMode = correlationChart.AnalysisMode
 
 	// 判断是否加入我的图库
 	if chartInfoId > 0 && chartInfo != nil {
@@ -783,7 +807,7 @@ func (this *CorrelationChartInfoController) Detail() {
 	chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList[0:1], chartInfo.Source, chartInfo.ChartType)
 	chartInfo.UnitEn = edbInfoMappingA.UnitEn
 
-	// 图表的指标来源
+	// TODO:图表来源
 	sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
 	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
 	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
@@ -1310,50 +1334,74 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 		errMsg = "获取相关性图表, A指标mapping信息失败, Err:" + e.Error()
 		return
 	}
-	edbInfoMappingB, e := data_manage.GetChartEdbMappingByEdbInfoId(correlationChart.EdbInfoIdSecond)
-	if e != nil {
-		msg = "获取失败"
-		errMsg = "获取相关性图表, B指标mapping信息失败, Err:" + e.Error()
-		return
+	edbInfoMappingB := new(data_manage.ChartEdbInfoMapping)
+	// 非多因子
+	if correlationChart.AnalysisMode != 1 {
+		edbInfoMappingB, e = data_manage.GetChartEdbMappingByEdbInfoId(correlationChart.EdbInfoIdSecond)
+		if e != nil {
+			msg = "获取失败"
+			errMsg = "获取相关性图表, B指标mapping信息失败, Err:" + e.Error()
+			return
+		}
 	}
 
 	var dataResp interface{} // 绘图数据返回(目前是滚动相关性的图)
 	var xEdbIdValue []int
 	var yDataList []data_manage.YData
-	switch chartInfo.Source {
-	case utils.CHART_SOURCE_CORRELATION: // 相关性图
-		moveUnitDays, ok := utils.FrequencyDaysMap[correlationChart.CalculateUnit]
-		if !ok {
-			msg = "错误的分析周期"
-			errMsg = "相关性图表数据有误"
-			return
-		}
-		startDate := time.Now().AddDate(0, 0, -correlationChart.CalculateValue*moveUnitDays).Format(utils.FormatDate)
-		endDate := time.Now().Format(utils.FormatDate)
+	if correlationChart.AnalysisMode != 1 {
+		switch chartInfo.Source {
+		case utils.CHART_SOURCE_CORRELATION: // 相关性图
+			moveUnitDays, ok := utils.FrequencyDaysMap[correlationChart.CalculateUnit]
+			if !ok {
+				msg = "错误的分析周期"
+				errMsg = "相关性图表数据有误"
+				return
+			}
+			startDate := time.Now().AddDate(0, 0, -correlationChart.CalculateValue*moveUnitDays).Format(utils.FormatDate)
+			endDate := time.Now().Format(utils.FormatDate)
+
+			xEdbIdValue, yDataList, e = correlationServ.GetChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, correlationChart.LeadValue, correlationChart.LeadUnit, startDate, endDate)
+			if e != nil {
+				msg = "获取失败"
+				errMsg = "获取相关性图表, 图表计算值失败, Err:" + e.Error()
+				return
+			}
+		case utils.CHART_SOURCE_ROLLING_CORRELATION: // 滚动相关性图
+			startDate, endDate := utils.GetDateByDateType(correlationChart.DateType, correlationChart.StartDate.Format(utils.FormatDate), correlationChart.EndDate.Format(utils.FormatDate))
 
-		xEdbIdValue, yDataList, e = correlationServ.GetChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, correlationChart.LeadValue, correlationChart.LeadUnit, startDate, endDate)
+			dataResp, e = correlationServ.GetRollingCorrelationChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, correlationChart.LeadValue, correlationChart.LeadUnit, correlationChart.CalculateValue, correlationChart.CalculateUnit, startDate, endDate, chartInfo.ChartName, chartInfo.ChartNameEn)
+			if e != nil {
+				msg = "获取失败"
+				errMsg = "获取滚动相关性图表, 图表计算值失败, Err:" + e.Error()
+				return
+			}
+		}
+	} else {
+		xEdbIdValue, yDataList, e = correlationServ.GetFactorChartDataByChartId(chartInfoId, chartInfo.ExtraConfig)
 		if e != nil {
 			msg = "获取失败"
 			errMsg = "获取相关性图表, 图表计算值失败, Err:" + e.Error()
 			return
 		}
-	case utils.CHART_SOURCE_ROLLING_CORRELATION: // 滚动相关性图
-		startDate, endDate := utils.GetDateByDateType(correlationChart.DateType, correlationChart.StartDate.Format(utils.FormatDate), correlationChart.EndDate.Format(utils.FormatDate))
+	}
 
-		dataResp, e = correlationServ.GetRollingCorrelationChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, correlationChart.LeadValue, correlationChart.LeadUnit, correlationChart.CalculateValue, correlationChart.CalculateUnit, startDate, endDate, chartInfo.ChartName, chartInfo.ChartNameEn)
+	// 完善指标信息
+	edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	if correlationChart.AnalysisMode != 1 {
+		edbList, e = correlationServ.GetChartEdbInfoFormat(chartInfo.ChartInfoId, edbInfoMappingA, edbInfoMappingB)
 		if e != nil {
 			msg = "获取失败"
-			errMsg = "获取滚动相关性图表, 图表计算值失败, Err:" + e.Error()
+			errMsg = "获取相关性图表, 完善指标信息失败, Err:" + e.Error()
+			return
+		}
+	} else {
+		// 多因子指标, 获取图表引用到的系列指标(去重后)
+		edbList, e = data_manage.GetChartEdbMappingListByIdList([]int{chartInfoId})
+		if e != nil {
+			msg = "获取失败"
+			errMsg = "获取图表引用系列指标失败, Err:" + e.Error()
 			return
 		}
-	}
-
-	// 完善指标信息
-	edbList, e := correlationServ.GetChartEdbInfoFormat(chartInfo.ChartInfoId, edbInfoMappingA, edbInfoMappingB)
-	if e != nil {
-		msg = "获取失败"
-		errMsg = "获取相关性图表, 完善指标信息失败, Err:" + e.Error()
-		return
 	}
 	correlationInfo := new(data_manage.CorrelationInfo)
 	correlationInfo.LeadValue = correlationChart.LeadValue
@@ -1365,6 +1413,7 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 	correlationInfo.LeadValue = correlationChart.LeadValue
 	correlationInfo.EdbInfoIdFirst = correlationChart.EdbInfoIdFirst
 	correlationInfo.EdbInfoIdSecond = correlationChart.EdbInfoIdSecond
+	correlationInfo.AnalysisMode = correlationChart.AnalysisMode
 
 	if chartInfoId > 0 && chartInfo != nil {
 		//判断是否加入我的图库
@@ -1821,3 +1870,842 @@ func (this *CorrelationChartInfoController) BaseInfoEdit() {
 	br.Msg = "编辑成功"
 	br.IsAddLog = true
 }
+
+// MultiFactorAdd
+// @Title 多因子图表-新增
+// @Description 多因子图表-新增
+// @Param	request	body request.CorrelationChartMultiFactorSaveReq true "type json string"
+// @Success Ret=200 返回图表id
+// @router /chart_info/multi_factor/add [post]
+func (this *CorrelationChartInfoController) MultiFactorAdd() {
+	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.CorrelationChartMultiFactorSaveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = fmt.Sprintf("参数解析失败, Err: %v", e)
+		return
+	}
+	// 此方法只加多因子图表
+	if req.AnalysisMode != 1 {
+		br.Msg = "分析模式有误"
+		br.ErrMsg = fmt.Sprintf("分析模式有误, Mode: %d", req.AnalysisMode)
+		return
+	}
+	if req.BaseEdbInfoId <= 0 {
+		br.Msg = "请选择标的指标"
+		return
+	}
+	if len(req.FactorCorrelation.SeriesEdb) == 0 {
+		br.Msg = "请选择因子指标"
+		return
+	}
+	if req.FactorCorrelation.LeadValue <= 0 {
+		br.Msg = "分析周期不允许设置为负数或0"
+		return
+	}
+	if req.FactorCorrelation.LeadUnit == "" {
+		br.Msg = "请选择分析周期频度"
+		return
+	}
+	leadUnitDays, ok := utils.FrequencyDaysMap[req.FactorCorrelation.LeadUnit]
+	if !ok {
+		br.Msg = "错误的分析周期频度"
+		br.ErrMsg = fmt.Sprintf("分析周期频度有误: %s", req.FactorCorrelation.LeadUnit)
+		return
+	}
+	if req.FactorCorrelation.CalculateUnit == "" {
+		br.Msg = "请选择计算窗口频度"
+		return
+	}
+	calculateUnitDays, ok := utils.FrequencyDaysMap[req.FactorCorrelation.CalculateUnit]
+	if !ok {
+		br.Msg = "错误的计算窗口频度"
+		br.ErrMsg = fmt.Sprintf("计算窗口频度有误: %s", req.FactorCorrelation.CalculateUnit)
+		return
+	}
+	leadDays := 2 * req.FactorCorrelation.LeadValue * leadUnitDays
+	calculateDays := req.FactorCorrelation.CalculateValue * calculateUnitDays
+	if calculateDays < leadDays {
+		br.Msg = "计算窗口必须≥2*分析周期"
+		return
+	}
+	req.ChartName = strings.TrimSpace(req.ChartName)
+	if req.ChartName == "" {
+		br.Msg = "请输入图表名称"
+		return
+	}
+	if req.ClassifyId <= 0 {
+		br.Msg = "请选择图表分类"
+		return
+	}
+
+	cacheKey := "CACHE_CORRELATION_CHART_INFO_ADD_" + strconv.Itoa(sysUser.AdminId)
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		br.Msg = "系统处理中, 请稍后重试"
+		return
+	}
+	defer func() {
+		_ = utils.Rc.Delete(cacheKey)
+	}()
+
+	chartType := 9
+	chartSource := utils.CHART_SOURCE_CORRELATION // TODO:暂定相关性图表不新加source
+	startDate := time.Now().AddDate(0, 0, -calculateDays).Format(utils.FormatDate)
+	endDate := time.Now().Format(utils.FormatDate)
+	mappingEdbIds := make([]int, 0) // 该图表关联的指标(去除系列中重复指标之后的)
+	{
+		exists := make(map[int]bool)
+		for _, v := range req.FactorCorrelation.SeriesEdb {
+			if !exists[v.EdbInfoId] {
+				mappingEdbIds = append(mappingEdbIds, v.EdbInfoId)
+			}
+		}
+	}
+
+	// 校验分类、图表名称
+	{
+		var cond string
+		var pars []interface{}
+		switch this.Lang {
+		case utils.EnLangVersion:
+			cond += " AND chart_name_en = ? AND source = ? "
+		default:
+			cond += " AND chart_name = ? AND source = ? "
+		}
+		pars = append(pars, req.ChartName, chartSource)
+		count, e := data_manage.GetChartInfoCountByCondition(cond, pars)
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("获取同名图表失败, Err: %v", e)
+			return
+		}
+		if count > 0 {
+			br.Msg = "图表名称已存在, 请重新填写"
+			return
+		}
+
+		_, e = data_manage.GetChartClassifyById(req.ClassifyId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "分类不存在"
+				return
+			}
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("获取图表分类失败, Err: %v", e)
+			return
+		}
+	}
+
+	// 图表来源、图例设置
+	var sourceFrom, extraConfig string
+	if req.SourcesFrom != nil {
+		b, e := json.Marshal(req.SourcesFrom)
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("图表来源JSON格式化失败, Err: %v", e)
+			return
+		}
+		sourceFrom = string(b)
+	}
+	if req.ExtraConfig != nil {
+		b, e := json.Marshal(req.ExtraConfig)
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("图表来源JSON格式化失败, Err: %v", e)
+			return
+		}
+		extraConfig = string(b)
+	}
+
+	// 图表信息
+	chartInfo := new(data_manage.ChartInfo)
+	chartInfo.ChartName = req.ChartName
+	chartInfo.ChartNameEn = req.ChartName
+	chartInfo.ChartClassifyId = req.ClassifyId
+	chartInfo.SysUserId = sysUser.AdminId
+	chartInfo.SysUserRealName = sysUser.RealName
+	chartInfo.CreateTime = time.Now()
+	chartInfo.ModifyTime = time.Now()
+	chartInfo.IsSetName = 0
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)
+	chartInfo.ChartType = chartType
+	chartInfo.Calendar = "公历"
+	chartInfo.DateType = 6
+	chartInfo.StartDate = startDate
+	chartInfo.EndDate = endDate
+	chartInfo.SeasonStartDate = startDate
+	chartInfo.SeasonEndDate = endDate
+	chartInfo.Disabled = data.CheckIsDisableChart(mappingEdbIds)
+	chartInfo.Source = chartSource
+	chartInfo.ExtraConfig = extraConfig
+	chartInfo.SourcesFrom = sourceFrom
+
+	// 相关性图
+	chartCorrelate := new(data_manage.ChartInfoCorrelation)
+	chartCorrelate.LeadValue = req.FactorCorrelation.LeadValue
+	chartCorrelate.LeadUnit = req.FactorCorrelation.LeadUnit
+	chartCorrelate.CalculateValue = req.FactorCorrelation.CalculateValue
+	chartCorrelate.CalculateUnit = req.FactorCorrelation.CalculateUnit
+	chartCorrelate.EdbInfoIdFirst = req.BaseEdbInfoId
+	chartCorrelate.AnalysisMode = 1
+	chartCorrelate.CreateTime = time.Now().Local()
+	chartCorrelate.ModifyTime = time.Now().Local()
+
+	// 图表指标关联
+	edbMappings := make([]*data_manage.ChartEdbMapping, 0)
+	for _, v := range mappingEdbIds {
+		m := new(data_manage.ChartEdbMapping)
+		m.EdbInfoId = v
+		m.CreateTime = time.Now()
+		m.ModifyTime = time.Now()
+		edbTimestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+		m.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + edbTimestamp + "_" + strconv.Itoa(v))
+		m.IsOrder = true
+		m.IsAxis = 1
+		m.EdbInfoType = 1
+		m.Source = utils.CHART_SOURCE_CORRELATION
+		edbMappings = append(edbMappings, m)
+	}
+
+	// 指标系列-图表关联
+	seriesMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
+	for _, v := range req.FactorCorrelation.SeriesEdb {
+		seriesMappings = append(seriesMappings, &data_manage.FactorEdbSeriesChartMapping{
+			FactorEdbSeriesId: v.SeriesId,
+			EdbInfoId:         v.EdbInfoId,
+			Source:            chartSource,
+			CreateTime:        time.Now().Local(),
+			ModifyTime:        time.Now().Local(),
+		})
+	}
+
+	// 新增图表/相关性图表/图表指标关联/指标系列图表关联
+	chartInfoId, e := data_manage.CreateMultiFactorCorrelationChartAndEdb(chartInfo, edbMappings, chartCorrelate, seriesMappings)
+	if e != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = fmt.Sprintf("新增多因子相关性图表失败, Err: %v", e)
+		return
+	}
+	go data.EsAddOrEditChartInfo(chartInfoId)
+
+	// 操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartInfoId = chartInfo.ChartInfoId
+		chartLog.ChartName = req.ChartName
+		chartLog.ChartClassifyId = req.ClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(this.Ctx.Input.RequestBody)
+		chartLog.Status = "新增多因子相关性图表"
+		chartLog.Method = this.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartInfo.ChartInfoId
+	resp.UniqueCode = chartInfo.UniqueCode
+	resp.ChartType = chartInfo.ChartType
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.IsAddLog = true
+}
+
+// MultiFactorEdit
+// @Title 多因子图表-编辑
+// @Description 多因子图表-编辑
+// @Param	request	body request.CorrelationChartMultiFactorSaveReq true "type json string"
+// @Success Ret=200 返回图表id
+// @router /chart_info/multi_factor/edit [post]
+func (this *CorrelationChartInfoController) MultiFactorEdit() {
+	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.CorrelationChartMultiFactorSaveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = fmt.Sprintf("参数解析失败, Err: %v", e)
+		return
+	}
+	if req.ChartInfoId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ChartInfoId: %d", req.ChartInfoId)
+		return
+	}
+	// 此方法只加多因子图表
+	if req.AnalysisMode != 1 {
+		br.Msg = "分析模式有误"
+		br.ErrMsg = fmt.Sprintf("分析模式有误, Mode: %d", req.AnalysisMode)
+		return
+	}
+	if req.BaseEdbInfoId <= 0 {
+		br.Msg = "请选择标的指标"
+		return
+	}
+	if len(req.FactorCorrelation.SeriesEdb) == 0 {
+		br.Msg = "请选择因子指标"
+		return
+	}
+	if req.FactorCorrelation.LeadValue <= 0 {
+		br.Msg = "分析周期不允许设置为负数或0"
+		return
+	}
+	if req.FactorCorrelation.LeadUnit == "" {
+		br.Msg = "请选择分析周期频度"
+		return
+	}
+	leadUnitDays, ok := utils.FrequencyDaysMap[req.FactorCorrelation.LeadUnit]
+	if !ok {
+		br.Msg = "错误的分析周期频度"
+		br.ErrMsg = fmt.Sprintf("分析周期频度有误: %s", req.FactorCorrelation.LeadUnit)
+		return
+	}
+	if req.FactorCorrelation.CalculateUnit == "" {
+		br.Msg = "请选择计算窗口频度"
+		return
+	}
+	calculateUnitDays, ok := utils.FrequencyDaysMap[req.FactorCorrelation.CalculateUnit]
+	if !ok {
+		br.Msg = "错误的计算窗口频度"
+		br.ErrMsg = fmt.Sprintf("计算窗口频度有误: %s", req.FactorCorrelation.CalculateUnit)
+		return
+	}
+	leadDays := 2 * req.FactorCorrelation.LeadValue * leadUnitDays
+	calculateDays := req.FactorCorrelation.CalculateValue * calculateUnitDays
+	if calculateDays < leadDays {
+		br.Msg = "计算窗口必须≥2*分析周期"
+		return
+	}
+	req.ChartName = strings.TrimSpace(req.ChartName)
+	if req.ChartName == "" {
+		br.Msg = "请输入图表名称"
+		return
+	}
+	if req.ClassifyId <= 0 {
+		br.Msg = "请选择图表分类"
+		return
+	}
+
+	cacheKey := "CACHE_CORRELATION_CHART_INFO_EDIT_" + strconv.Itoa(sysUser.AdminId)
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		br.Msg = "系统处理中, 请稍后重试"
+		return
+	}
+	defer func() {
+		_ = utils.Rc.Delete(cacheKey)
+	}()
+
+	chartSource := utils.CHART_SOURCE_CORRELATION
+	startDate := time.Now().AddDate(0, 0, -calculateDays).Format(utils.FormatDate)
+	endDate := time.Now().Format(utils.FormatDate)
+	mappingEdbIds := make([]int, 0) // 该图表关联的指标(去除系列中重复指标之后的)
+	{
+		exists := make(map[int]bool)
+		for _, v := range req.FactorCorrelation.SeriesEdb {
+			if !exists[v.EdbInfoId] {
+				mappingEdbIds = append(mappingEdbIds, v.EdbInfoId)
+			}
+		}
+	}
+
+	chartInfo, e := data_manage.GetChartInfoById(req.ChartInfoId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "图表已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "保存失败"
+		br.ErrMsg = fmt.Sprintf("获取图表信息失败, Err: %v", e)
+		return
+	}
+	chartCorrelate := new(data_manage.ChartInfoCorrelation)
+	if e = chartCorrelate.GetItemById(chartInfo.ChartInfoId); e != nil {
+		br.Msg = "图表相关性信息不存在"
+		br.ErrMsg = fmt.Sprintf("获取图表相关性信息失败, Err: %v", e)
+		return
+	}
+
+	// 图表检验
+	{
+		if chartInfo.Source != chartSource {
+			br.Msg = "该图表不是相关性图表"
+			return
+		}
+
+		// 图表操作权限
+		authOk := data.CheckOpChartPermission(sysUser, chartInfo.SysUserId, true)
+		if !authOk {
+			br.Msg = "没有该图表的操作权限"
+			return
+		}
+
+		// 图表名称、分类
+		var cond string
+		var pars []interface{}
+		switch this.Lang {
+		case utils.EnLangVersion:
+			cond += " AND chart_name_en = ? AND source = ? AND chart_info_id <> ? "
+		default:
+			cond += " AND chart_name = ? AND source = ? AND chart_info_id <> ? "
+		}
+		pars = append(pars, req.ChartName, chartSource, chartInfo.ChartInfoId)
+		count, e := data_manage.GetChartInfoCountByCondition(cond, pars)
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("获取同名图表失败, Err: %v", e)
+			return
+		}
+		if count > 0 {
+			br.Msg = "图表名称已存在, 请重新填写"
+			return
+		}
+
+		_, e = data_manage.GetChartClassifyById(req.ClassifyId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "分类不存在"
+				return
+			}
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("获取图表分类失败, Err: %v", e)
+			return
+		}
+	}
+
+	// 图表来源、图例设置
+	var sourceFrom, extraConfig string
+	if req.SourcesFrom != nil {
+		b, e := json.Marshal(req.SourcesFrom)
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("图表来源JSON格式化失败, Err: %v", e)
+			return
+		}
+		sourceFrom = string(b)
+	}
+	if req.ExtraConfig != nil {
+		b, e := json.Marshal(req.ExtraConfig)
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("图表来源JSON格式化失败, Err: %v", e)
+			return
+		}
+		extraConfig = string(b)
+	}
+
+	// 图表信息
+	chartInfo.ChartName = req.ChartName
+	chartInfo.ChartNameEn = req.ChartName
+	chartInfo.ChartClassifyId = req.ClassifyId
+	chartInfo.ModifyTime = time.Now()
+	chartInfo.StartDate = startDate
+	chartInfo.EndDate = endDate
+	chartInfo.SeasonStartDate = startDate
+	chartInfo.SeasonEndDate = endDate
+	chartInfo.ExtraConfig = extraConfig
+	chartInfo.SourcesFrom = sourceFrom
+	chartInfo.Disabled = data.CheckIsDisableChart(mappingEdbIds)
+	chartUpdateCols := []string{"ChartName", "ChartNameEn", "ChartClassifyId", "ModifyTime", "StartDate", "EndDate", "SeasonStartDate", "SeasonEndDate", "ExtraConfig", "SourcesFrom", "Disabled"}
+
+	// 相关性图
+	chartCorrelate.LeadValue = req.FactorCorrelation.LeadValue
+	chartCorrelate.LeadUnit = req.FactorCorrelation.LeadUnit
+	chartCorrelate.CalculateValue = req.FactorCorrelation.CalculateValue
+	chartCorrelate.CalculateUnit = req.FactorCorrelation.CalculateUnit
+	chartCorrelate.EdbInfoIdFirst = req.BaseEdbInfoId
+	chartCorrelate.ModifyTime = time.Now().Local()
+	correlateUpdateCols := []string{"LeadValue", "LeadUnit", "CalculateValue", "CalculateUnit", "EdbInfoIdFirst", "ModifyTime"}
+
+	// 图表指标关联
+	edbMappings := make([]*data_manage.ChartEdbMapping, 0)
+	for _, v := range mappingEdbIds {
+		m := new(data_manage.ChartEdbMapping)
+		m.EdbInfoId = v
+		m.CreateTime = time.Now()
+		m.ModifyTime = time.Now()
+		edbTimestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+		m.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + edbTimestamp + "_" + strconv.Itoa(v))
+		m.IsOrder = true
+		m.IsAxis = 1
+		m.EdbInfoType = 1
+		m.Source = utils.CHART_SOURCE_CORRELATION
+		edbMappings = append(edbMappings, m)
+	}
+
+	// 指标系列-图表关联
+	seriesMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
+	for _, v := range req.FactorCorrelation.SeriesEdb {
+		seriesMappings = append(seriesMappings, &data_manage.FactorEdbSeriesChartMapping{
+			FactorEdbSeriesId: v.SeriesId,
+			EdbInfoId:         v.EdbInfoId,
+			Source:            chartSource,
+			CreateTime:        time.Now().Local(),
+			ModifyTime:        time.Now().Local(),
+		})
+	}
+
+	// 更新图表/相关性图表/图表指标关联/指标系列图表关联
+	e = data_manage.UpdateMultiFactorCorrelationChartAndEdb(chartInfo, edbMappings, chartCorrelate, seriesMappings, chartUpdateCols, correlateUpdateCols)
+	if e != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = fmt.Sprintf("新增多因子相关性图表失败, Err: %v", e)
+		return
+	}
+
+	// ES
+	go func() {
+		data.EsAddOrEditChartInfo(chartInfo.ChartInfoId)
+		data.EsAddOrEditMyChartInfoByChartInfoId(chartInfo.ChartInfoId)
+	}()
+
+	// 操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartInfoId = chartInfo.ChartInfoId
+		chartLog.ChartName = req.ChartName
+		chartLog.ChartClassifyId = req.ClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(this.Ctx.Input.RequestBody)
+		chartLog.Status = "编辑多因子相关性图表"
+		chartLog.Method = this.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartInfo.ChartInfoId
+	resp.UniqueCode = chartInfo.UniqueCode
+	resp.ChartType = chartInfo.ChartType
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.IsAddLog = true
+}
+
+// MultiFactorSaveAs
+// @Title 多因子图表-另存为
+// @Description 多因子图表-另存为
+// @Param	request	body request.CorrelationChartMultiFactorSaveAsReq true "type json string"
+// @Success Ret=200 返回图表id
+// @router /chart_info/multi_factor/save_as [post]
+func (this *CorrelationChartInfoController) MultiFactorSaveAs() {
+	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.CorrelationChartMultiFactorSaveAsReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = fmt.Sprintf("参数解析失败, Err: %v", e)
+		return
+	}
+	if req.ChartInfoId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ChartInfoId: %d", req.ChartInfoId)
+		return
+	}
+	req.ChartName = strings.TrimSpace(req.ChartName)
+	if req.ChartName == "" {
+		br.Msg = "请输入图表名称"
+		return
+	}
+	if req.ClassifyId <= 0 {
+		br.Msg = "请选择图表分类"
+		return
+	}
+
+	cacheKey := "CACHE_CORRELATION_CHART_INFO_COPY_" + strconv.Itoa(sysUser.AdminId)
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		br.Msg = "系统处理中, 请稍后重试"
+		return
+	}
+	defer func() {
+		_ = utils.Rc.Delete(cacheKey)
+	}()
+
+	chartSource := utils.CHART_SOURCE_CORRELATION
+	// 校验分类、图表名称
+	{
+		var cond string
+		var pars []interface{}
+		switch this.Lang {
+		case utils.EnLangVersion:
+			cond += " AND chart_name_en = ? AND source = ? "
+		default:
+			cond += " AND chart_name = ? AND source = ? "
+		}
+		pars = append(pars, req.ChartName, chartSource)
+		count, e := data_manage.GetChartInfoCountByCondition(cond, pars)
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("获取同名图表失败, Err: %v", e)
+			return
+		}
+		if count > 0 {
+			br.Msg = "图表名称已存在, 请重新填写"
+			return
+		}
+
+		_, e = data_manage.GetChartClassifyById(req.ClassifyId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "分类不存在"
+				return
+			}
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("获取图表分类失败, Err: %v", e)
+			return
+		}
+	}
+
+	// 图表信息
+	originChart, e := data_manage.GetChartInfoById(req.ChartInfoId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "原图表不存在"
+			return
+		}
+		br.Msg = "保存失败"
+		br.ErrMsg = fmt.Sprintf("获取原图表信息失败, Err: %v", e)
+		return
+	}
+
+	chartInfo := new(data_manage.ChartInfo)
+	chartInfo.ChartName = req.ChartName
+	chartInfo.ChartNameEn = req.ChartName
+	chartInfo.ChartClassifyId = req.ClassifyId
+	chartInfo.SysUserId = sysUser.AdminId
+	chartInfo.SysUserRealName = sysUser.RealName
+	chartInfo.CreateTime = time.Now()
+	chartInfo.ModifyTime = time.Now()
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)
+	chartInfo.ChartType = originChart.ChartType
+	chartInfo.Calendar = originChart.Calendar
+	chartInfo.DateType = originChart.DateType
+	chartInfo.StartDate = originChart.StartDate
+	chartInfo.EndDate = originChart.EndDate
+	chartInfo.SeasonStartDate = originChart.StartDate
+	chartInfo.SeasonEndDate = originChart.EndDate
+	chartInfo.Disabled = originChart.Disabled
+	chartInfo.Source = originChart.Source
+	chartInfo.ChartThemeId = originChart.ChartThemeId
+	chartInfo.ExtraConfig = originChart.ExtraConfig
+	chartInfo.SourcesFrom = originChart.SourcesFrom
+	chartInfo.Instructions = originChart.Instructions
+	chartInfo.MarkersLines = originChart.MarkersLines
+	chartInfo.MarkersAreas = originChart.MarkersAreas
+
+	// 相关性图
+	originCorrelate := new(data_manage.ChartInfoCorrelation)
+	if e = originCorrelate.GetItemById(req.ChartInfoId); e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "原相关性图表不存在"
+			return
+		}
+		br.Msg = "保存失败"
+		br.ErrMsg = fmt.Sprintf("获取原相关性图表信息失败, Err: %v", e)
+		return
+	}
+	chartCorrelate := new(data_manage.ChartInfoCorrelation)
+	chartCorrelate.LeadValue = originCorrelate.LeadValue
+	chartCorrelate.LeadUnit = originCorrelate.LeadUnit
+	chartCorrelate.CalculateValue = originCorrelate.CalculateValue
+	chartCorrelate.CalculateUnit = originCorrelate.CalculateUnit
+	chartCorrelate.EdbInfoIdFirst = originCorrelate.EdbInfoIdFirst
+	chartCorrelate.CreateTime = time.Now().Local()
+	chartCorrelate.ModifyTime = time.Now().Local()
+
+	// 图表指标关联
+	edbMappings := make([]*data_manage.ChartEdbMapping, 0)
+	{
+		mappings, e := data_manage.GetChartMappingList(req.ChartInfoId)
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("获取图表指标关联失败, Err: %v", e)
+			return
+		}
+		for _, v := range mappings {
+			m := new(data_manage.ChartEdbMapping)
+			m.EdbInfoId = v.EdbInfoId
+			edbTimestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+			m.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + edbTimestamp + "_" + strconv.Itoa(v.EdbInfoId))
+			m.IsOrder = true
+			m.IsAxis = 1
+			m.EdbInfoType = 1
+			m.Source = utils.CHART_SOURCE_CORRELATION
+			m.CreateTime = time.Now()
+			m.ModifyTime = time.Now()
+			edbMappings = append(edbMappings, m)
+		}
+	}
+
+	// 指标系列-图表关联
+	seriesMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
+	{
+		ob := new(data_manage.FactorEdbSeriesChartMapping)
+		cond := fmt.Sprintf(" AND %s = ?", ob.Cols().ChartInfoId)
+		pars := make([]interface{}, 0)
+		pars = append(pars, req.ChartInfoId)
+		mappings, e := ob.GetItemsByCondition(cond, pars, []string{}, "")
+		if e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = fmt.Sprintf("获取指标系列-图表关联失败, Err: %v", e)
+			return
+		}
+		for _, v := range mappings {
+			seriesMappings = append(seriesMappings, &data_manage.FactorEdbSeriesChartMapping{
+				FactorEdbSeriesId: v.FactorEdbSeriesId,
+				ChartInfoId:       req.ChartInfoId,
+				EdbInfoId:         v.EdbInfoId,
+				Source:            v.Source,
+				CreateTime:        time.Now().Local(),
+				ModifyTime:        time.Now().Local(),
+			})
+		}
+	}
+
+	// 新增图表/相关性图表/图表指标关联/指标系列图表关联
+	chartInfoId, e := data_manage.CreateMultiFactorCorrelationChartAndEdb(chartInfo, edbMappings, chartCorrelate, seriesMappings)
+	if e != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = fmt.Sprintf("新增多因子相关性图表失败, Err: %v", e)
+		return
+	}
+	go data.EsAddOrEditChartInfo(chartInfoId)
+
+	// 操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartInfoId = chartInfo.ChartInfoId
+		chartLog.ChartName = req.ChartName
+		chartLog.ChartClassifyId = req.ClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(this.Ctx.Input.RequestBody)
+		chartLog.Status = "另存为多因子相关性图表"
+		chartLog.Method = this.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartInfo.ChartInfoId
+	resp.UniqueCode = chartInfo.UniqueCode
+	resp.ChartType = chartInfo.ChartType
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.IsAddLog = true
+}
+
+// MultiFactorDetail
+// @Title 多因子图表-编辑页详情
+// @Description 多因子图表-编辑页详情
+// @Param   UniqueCode  query  string  true  "图表唯一编码"
+// @Success Ret=200 返回图表id
+// @router /chart_info/multi_factor/detail [get]
+func (this *CorrelationChartInfoController) MultiFactorDetail() {
+	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
+	}
+	uniqueCode := this.GetString("UniqueCode")
+	if uniqueCode == "" {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, UniqueCode: %s", uniqueCode)
+		return
+	}
+
+	chartInfo, e := data_manage.GetChartInfoByUniqueCode(uniqueCode)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "图表已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprintf("获取图表信息失败, Err: %v", e)
+		return
+	}
+	chartCorrelate := new(data_manage.ChartInfoCorrelation)
+	if e = chartCorrelate.GetItemById(chartInfo.ChartInfoId); e != nil {
+		br.Msg = "图表相关性信息不存在"
+		br.ErrMsg = fmt.Sprintf("获取图表相关性信息失败, Err: %v", e)
+		return
+	}
+	if chartCorrelate.AnalysisMode != 1 {
+		br.Msg = "图表分析模式有误"
+		br.ErrMsg = fmt.Sprintf("图表分析模式有误, Err: %v", e)
+		return
+	}
+
+	// TODO:
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 31 - 12
controllers/data_manage/factor_edb_series.go

@@ -11,6 +11,7 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"sort"
+	"strconv"
 	"strings"
 	"sync"
 	"time"
@@ -128,11 +129,12 @@ func (this *FactorEdbSeriesController) Add() {
 					br.Msg = "请输入N值"
 					return
 				}
-				formulaInt, ok := v.Formula.(float64)
+				formula, ok := v.Formula.(string)
 				if !ok {
 					br.Msg = "N值格式有误"
 					return
 				}
+				formulaInt, _ := strconv.Atoi(formula)
 				if formulaInt <= 0 {
 					br.Msg = "N值不可小于0, 重新输入"
 					return
@@ -142,11 +144,12 @@ func (this *FactorEdbSeriesController) Add() {
 					br.Msg = "请填写alpha值"
 					return
 				}
-				alpha, ok := v.Formula.(float64)
-				if ok {
+				formula, ok := v.Formula.(string)
+				if !ok {
 					br.Msg = "alpha值格式有误"
 					return
 				}
+				alpha, _ := strconv.ParseFloat(formula, 64)
 				if alpha <= 0 || alpha >= 1 {
 					br.Msg = "alpha值应在0-1之间, 请重新输入"
 					return
@@ -296,11 +299,12 @@ func (this *FactorEdbSeriesController) Edit() {
 					br.Msg = "请输入N值"
 					return
 				}
-				formulaInt, ok := v.Formula.(float64)
+				formula, ok := v.Formula.(string)
 				if !ok {
 					br.Msg = "N值格式有误"
 					return
 				}
+				formulaInt, _ := strconv.Atoi(formula)
 				if formulaInt <= 0 {
 					br.Msg = "N值不可小于0, 重新输入"
 					return
@@ -310,11 +314,12 @@ func (this *FactorEdbSeriesController) Edit() {
 					br.Msg = "请填写alpha值"
 					return
 				}
-				alpha, ok := v.Formula.(float64)
-				if ok {
+				formula, ok := v.Formula.(string)
+				if !ok {
 					br.Msg = "alpha值格式有误"
 					return
 				}
+				alpha, _ := strconv.ParseFloat(formula, 64)
 				if alpha <= 0 || alpha >= 1 {
 					br.Msg = "alpha值应在0-1之间, 请重新输入"
 					return
@@ -714,12 +719,11 @@ func (this *FactorEdbSeriesController) CorrelationMatrix() {
 				return
 			}
 
-			// 按照固定规则排期数[0 1 2 3 -1 -2 -3]
+			// X及Y轴数据
 			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]
@@ -729,14 +733,29 @@ func (this *FactorEdbSeriesController) CorrelationMatrix() {
 					XData: x, YData: y,
 				}
 			}
-			sort.Sort(data_manage.FactorEdbSeriesCorrelationMatrixOrder(values))
 
+			// 存储计算结果, 注此处保存的是排序前的顺序
+			b, e := json.Marshal(values)
+			if e != nil {
+				item.Msg = fmt.Sprintf("计算失败")
+				item.ErrMsg = fmt.Sprintf("计算结果JSON格式化失败, err: %v", e)
+				resp.Fail = append(resp.Fail, item)
+				return
+			}
+			mapping.CalculateData = string(b)
+			mapping.ModifyTime = time.Now().Local()
+			if e = mapping.Update([]string{mapping.Cols().CalculateData, mapping.Cols().ModifyTime}); 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], 仅矩阵展示为此顺序
+			sort.Sort(data_manage.FactorEdbSeriesCorrelationMatrixOrder(values))
 			item.Msg = "计算成功"
 			item.Values = values
 			resp.Success = append(resp.Success, item)
-
-			// TODO:存储计算结果
-
 		}(v, edbItem, seriesItem)
 	}
 	wg.Wait()

+ 8 - 0
models/data_manage/chart_info.go

@@ -2352,3 +2352,11 @@ type RadarYData struct {
 	Name  string    `description:"别名"`
 	Value []float64 `description:"每个指标的值"`
 }
+
+// ChartInfoSourcesFrom 图表来源
+type ChartInfoSourcesFrom struct {
+	IsShow   bool   `description:"是否展示" json:"isShow"`
+	Text     string `description:"来源文本" json:"text"`
+	Color    string `description:"来源颜色" json:"color"`
+	FontSize int    `description:"来源字号" json:"fontSize"`
+}

+ 169 - 0
models/data_manage/chart_info_correlation.go

@@ -25,6 +25,7 @@ type ChartInfoCorrelation struct {
 	CorrelationData        string    `description:"Y轴-相关性系数"`
 	CreateTime             time.Time `description:"创建时间"`
 	ModifyTime             time.Time `description:"更新时间"`
+	AnalysisMode           int       `description:"分析模式: 0-单因子; 1-多因子"`
 }
 
 type CorrelationInfo struct {
@@ -38,6 +39,7 @@ type CorrelationInfo struct {
 	EdbInfoIdSecond int    `description:"B指标ID"`
 	PeriodData      string `description:"X轴-期数数据"`
 	CorrelationData string `description:"Y轴-相关性系数"`
+	AnalysisMode    int    `description:"分析模式: 0-单因子; 1-多因子"`
 }
 
 func (m *ChartInfoCorrelation) TableName() string {
@@ -135,3 +137,170 @@ func CreateCorrelationChartAndEdb(chartInfo *ChartInfo, edbMappingList []*ChartE
 	}
 	return
 }
+
+// FactorCorrelationConfig 因子指标系列-相关性配置
+type FactorCorrelationConfig struct {
+	LeadValue      int                       `description:"领先期数"`
+	LeadUnit       string                    `description:"频度"`
+	CalculateValue int                       `description:"计算窗口"`
+	CalculateUnit  string                    `description:"计算频度"`
+	SeriesEdb      []CorrelationSeriesEdbReq `description:"关联系列指标"`
+}
+
+// CorrelationChartLegend 相关性图表图例
+type CorrelationChartLegend struct {
+	LegendName string `description:"图例名称"`
+	EdbInfoId  int    `description:"指标ID"`
+	SeriesId   int    `description:"因子指标系列ID"`
+}
+
+// CorrelationSeriesEdbReq 指标系列
+type CorrelationSeriesEdbReq struct {
+	EdbInfoId int `description:"指标ID"`
+	SeriesId  int `description:"因子指标系列ID"`
+}
+
+// CorrelationChartInfoExtraConfig 相关性图表额外设置
+type CorrelationChartInfoExtraConfig struct {
+	LegendConfig []*CorrelationChartLegend `description:"图例设置"`
+}
+
+// CreateMultiFactorCorrelationChartAndEdb 新增多因子相关性图表
+func CreateMultiFactorCorrelationChartAndEdb(chartInfo *ChartInfo, edbMappingList []*ChartEdbMapping, correlationInfo *ChartInfoCorrelation, seriesMappings []*FactorEdbSeriesChartMapping) (chartInfoId int, err error) {
+	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()
+	}()
+
+	// 新增图表信息
+	chartId, e := tx.Insert(chartInfo)
+	if e != nil {
+		err = fmt.Errorf("chart insert err: %v", e)
+		return
+	}
+	chartInfo.ChartInfoId = int(chartId)
+	chartInfoId = chartInfo.ChartInfoId
+
+	// 指标mapping
+	if len(edbMappingList) > 0 {
+		for i := range edbMappingList {
+			edbMappingList[i].ChartInfoId = chartInfoId
+		}
+		_, e = tx.InsertMulti(200, edbMappingList)
+		if e != nil {
+			err = fmt.Errorf("edb mappings insert err: %v", e)
+			return
+		}
+	}
+
+	// 相关性信息
+	correlationInfo.CorrelationChartInfoId = chartInfoId
+	if _, e = tx.Insert(correlationInfo); e != nil {
+		err = fmt.Errorf("correlate chart insert err: %v", e)
+		return
+	}
+
+	// 指标系列-图表关联
+	if len(seriesMappings) > 0 {
+		for _, v := range seriesMappings {
+			v.ChartInfoId = chartInfoId
+		}
+		if _, e = tx.InsertMulti(200, seriesMappings); e != nil {
+			err = fmt.Errorf("series chart mappings insert err: %v", e)
+			return
+		}
+	}
+	return
+}
+
+// UpdateMultiFactorCorrelationChartAndEdb 编辑多因子相关性图表
+func UpdateMultiFactorCorrelationChartAndEdb(chartInfo *ChartInfo, edbMappingList []*ChartEdbMapping, correlationInfo *ChartInfoCorrelation, seriesMappings []*FactorEdbSeriesChartMapping, chartUpdateCols, correlateUpdateCols []string) (err error) {
+	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(chartInfo, chartUpdateCols...)
+	if e != nil {
+		err = fmt.Errorf("chart update err: %v", e)
+		return
+	}
+
+	// 指标mapping
+	sql := `DELETE FROM chart_edb_mapping WHERE chart_info_id = ?`
+	_, e = tx.Raw(sql, chartInfo.ChartInfoId).Exec()
+	if e != nil {
+		err = fmt.Errorf("clear chart edb mapping err: %v", e)
+		return
+	}
+	if len(edbMappingList) > 0 {
+		for i := range edbMappingList {
+			edbMappingList[i].ChartInfoId = chartInfo.ChartInfoId
+		}
+		_, e = tx.InsertMulti(200, edbMappingList)
+		if e != nil {
+			err = fmt.Errorf("edb mappings insert err: %v", e)
+			return
+		}
+	}
+
+	// 相关性信息
+	_, e = tx.Update(correlationInfo, correlateUpdateCols...)
+	if e != nil {
+		err = fmt.Errorf("correlate chart update err: %v", e)
+		return
+	}
+
+	// 指标系列-图表关联
+	sql = `DELETE FROM factor_edb_series_chart_mapping WHERE chart_info_id = ?`
+	_, e = tx.Raw(sql, chartInfo.ChartInfoId).Exec()
+	if e != nil {
+		err = fmt.Errorf("clear chart series mapping err: %v", e)
+		return
+	}
+	if len(seriesMappings) > 0 {
+		for _, v := range seriesMappings {
+			v.ChartInfoId = chartInfo.ChartInfoId
+		}
+		if _, e = tx.InsertMulti(200, seriesMappings); e != nil {
+			err = fmt.Errorf("series chart mappings insert err: %v", e)
+			return
+		}
+	}
+	return
+}
+
+// FactorCorrelationEditDetail 编辑页详情
+type FactorCorrelationEditDetail struct {
+	ChartInfoId int    `description:"图表ID"`
+	UniqueCode  string `description:"图表唯一编码"`
+
+	// TODO:标的指标,相关性,指标系列
+
+	// TODO:系列矩阵
+	CorrelationMatrix FactorEdbSeriesCorrelationMatrixResp
+
+	// TODO:右下图表
+}
+
+type FactorCorrelationEditDetailBase struct {
+}

+ 21 - 0
models/data_manage/correlation/request/chart.go

@@ -1,5 +1,7 @@
 package request
 
+import "eta/eta_api/models/data_manage"
+
 // EditChartEnInfoReq
 // @Description: 编辑图表英文信息请求
 type EditChartEnInfoReq struct {
@@ -13,3 +15,22 @@ type EditChartInfoBaseReq struct {
 	ChartInfoId int    `description:"图表ID"`
 	ChartName   string `description:"英文图表名称"`
 }
+
+// CorrelationChartMultiFactorSaveReq 多因子相关性图表-保存请求
+type CorrelationChartMultiFactorSaveReq struct {
+	ChartInfoId       int                                          `description:"图表ID"`
+	ChartName         string                                       `description:"图表名称"`
+	ClassifyId        int                                          `description:"分类id"`
+	AnalysisMode      int                                          `description:"分析模式: 0-单因子; 1-多因子"`
+	BaseEdbInfoId     int                                          `description:"标的指标ID"`
+	FactorCorrelation *data_manage.FactorCorrelationConfig         `description:"多因子指标系列-相关性配置"`
+	SourcesFrom       *data_manage.ChartInfoSourcesFrom            `description:"图表来源"`
+	ExtraConfig       *data_manage.CorrelationChartInfoExtraConfig `description:"额外设置"`
+}
+
+// CorrelationChartMultiFactorSaveAsReq 多因子相关性图表-另存为请求
+type CorrelationChartMultiFactorSaveAsReq struct {
+	ChartInfoId int    `description:"图表ID"`
+	ChartName   string `description:"图表名称"`
+	ClassifyId  int    `description:"分类id"`
+}

+ 1 - 0
models/data_manage/factor_edb_series.go

@@ -312,6 +312,7 @@ type FactorEdbSeriesCorrelationMatrixItem struct {
 	Values    []FactorEdbSeriesCorrelationMatrixValues `description:"X轴和Y轴数据"`
 	Msg       string                                   `description:"提示信息"`
 	ErrMsg    string                                   `description:"错误信息"`
+	Used      bool                                     `description:"是否选中"`
 }
 
 // FactorEdbSeriesCorrelationMatrixValues 因子指标系列-相关性矩阵XY值

+ 11 - 8
models/data_manage/factor_edb_series_chart_mapping.go

@@ -10,12 +10,13 @@ import (
 
 // 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:"修改时间"`
+	FactorEdbSeriesChartMappingId int       `orm:"column(factor_edb_series_chart_mapping_id);pk"`
+	FactorEdbSeriesId             int       `description:"因子指标系列ID"`
+	ChartInfoId                   int       `description:"图表ID"`
+	EdbInfoId                     int       `description:"指标ID"`
+	Source                        int       `description:"图表来源,同chart_info表source"`
+	CreateTime                    time.Time `description:"创建时间"`
+	ModifyTime                    time.Time `description:"修改时间"`
 }
 
 func (m *FactorEdbSeriesChartMapping) TableName() string {
@@ -26,6 +27,7 @@ type MultipleFactorSeriesChartMappingCols struct {
 	PrimaryId         string
 	FactorEdbSeriesId string
 	ChartInfoId       string
+	EdbInfoId         string
 	Source            string
 	CreateTime        string
 	ModifyTime        string
@@ -36,6 +38,7 @@ func (m *FactorEdbSeriesChartMapping) Cols() MultipleFactorSeriesChartMappingCol
 		PrimaryId:         "factor_edb_series_chart_mapping_id",
 		FactorEdbSeriesId: "factor_edb_series_id",
 		ChartInfoId:       "chart_info_id",
+		EdbInfoId:         "edb_info_id",
 		Source:            "source",
 		CreateTime:        "create_time",
 		ModifyTime:        "modify_time",
@@ -48,7 +51,7 @@ func (m *FactorEdbSeriesChartMapping) Create() (err error) {
 	if err != nil {
 		return
 	}
-	m.MultipleFactorSeriesChartMappingId = int(id)
+	m.FactorEdbSeriesChartMappingId = int(id)
 	return
 }
 
@@ -70,7 +73,7 @@ func (m *FactorEdbSeriesChartMapping) Update(cols []string) (err error) {
 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()
+	_, err = o.Raw(sql, m.FactorEdbSeriesChartMappingId).Exec()
 	return
 }
 

+ 46 - 0
models/data_manage/factor_edb_series_mapping.go

@@ -14,6 +14,7 @@ type FactorEdbSeriesMapping struct {
 	FactorEdbSeriesId        int       `description:"因子指标系列ID"`
 	EdbInfoId                int       `description:"指标ID"`
 	EdbCode                  string    `description:"指标编码"`
+	CalculateData            string    `description:"计算数据-JSON(如相关性矩阵等等)"`
 	CreateTime               time.Time `description:"创建时间"`
 	ModifyTime               time.Time `description:"修改时间"`
 }
@@ -27,6 +28,7 @@ type FactorEdbSeriesMappingCols struct {
 	FactorEdbSeriesId string
 	EdbInfoId         string
 	EdbCode           string
+	CalculateData     string
 	CreateTime        string
 	ModifyTime        string
 }
@@ -37,6 +39,7 @@ func (m *FactorEdbSeriesMapping) Cols() FactorEdbSeriesMappingCols {
 		FactorEdbSeriesId: "factor_edb_series_id",
 		EdbInfoId:         "edb_info_id",
 		EdbCode:           "edb_code",
+		CalculateData:     "calculate_data",
 		CreateTime:        "create_time",
 		ModifyTime:        "modify_time",
 	}
@@ -163,3 +166,46 @@ func (m *FactorEdbSeriesMapping) Format2Item() (item *FactorEdbSeriesMappingItem
 	item.EdbCode = m.EdbCode
 	return
 }
+
+// FactorEdbSeriesMappingUpdateCalculate 更新计算数据
+//type FactorEdbSeriesMappingUpdateCalculate struct {
+//	SeriesId      int    `description:"因子指标系列ID"`
+//	EdbInfoId     int    `description:"指标ID"`
+//	CalculateData string `description:"计算数据-JSON"`
+//}
+//
+//func (m *FactorEdbSeriesMapping) UpdateCalculateData(updates []*FactorEdbSeriesMappingUpdateCalculate) (err error) {
+//	if len(updates) == 0 {
+//		return
+//	}
+//	o := orm.NewOrm()
+//	sql := fmt.Sprintf(`UPDATE %s SET %s = ? WHERE %s = ? AND %s = ?`, m.TableName(), m.Cols().CalculateData, m.Cols().FactorEdbSeriesId, m.Cols().EdbInfoId)
+//	p, e := o.Raw(sql).Prepare()
+//	if e != nil {
+//		err = fmt.Errorf("sql prepare err: %v", e)
+//		return
+//	}
+//	defer func() {
+//		_ = p.Close()
+//	}()
+//	for _, v := range updates {
+//		_, e = p.Exec(v.CalculateData, v.SeriesId, v.EdbInfoId)
+//		if e != nil {
+//			err = fmt.Errorf("update exec err: %v", e)
+//			return
+//		}
+//	}
+//	return
+//}
+
+// GetChartUsedFactorSeriesEdb 获取图表引用的系列指标
+func GetChartUsedFactorSeriesEdb(chartId int) (items []*FactorEdbSeriesMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	chartOb := new(FactorEdbSeriesChartMapping)
+	edbOb := new(FactorEdbSeriesMapping)
+	sql := fmt.Sprintf(`SELECT b.* FROM %s AS a
+	JOIN %s AS b ON a.%s = b.%s AND a.%s = b.%s
+	WHERE a.%s = ? ORDER BY %s ASC`, chartOb.TableName(), edbOb.TableName(), chartOb.Cols().FactorEdbSeriesId, edbOb.Cols().FactorEdbSeriesId, chartOb.Cols().EdbInfoId, edbOb.Cols().EdbInfoId, chartOb.Cols().ChartInfoId, edbOb.Cols().FactorEdbSeriesId)
+	_, err = o.Raw(sql, chartId).QueryRows(&items)
+	return
+}

+ 36 - 0
routers/commentsRouter.go

@@ -214,6 +214,42 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"],
+        beego.ControllerComments{
+            Method: "MultiFactorAdd",
+            Router: `/chart_info/multi_factor/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"],
+        beego.ControllerComments{
+            Method: "MultiFactorDetail",
+            Router: `/chart_info/multi_factor/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"],
+        beego.ControllerComments{
+            Method: "MultiFactorEdit",
+            Router: `/chart_info/multi_factor/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"],
+        beego.ControllerComments{
+            Method: "MultiFactorSaveAs",
+            Router: `/chart_info/multi_factor/save_as`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartInfoController"],
         beego.ControllerComments{
             Method: "Newest",

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

@@ -1407,3 +1407,92 @@ func CalculateCorrelation(leadValue int, leadUnit, frequencyA, frequencyB string
 	})
 	return
 }
+
+// GetFactorChartDataByChartId 获取多因子相关性图表数据
+func GetFactorChartDataByChartId(chartInfoId int, extraConfig string) (xEdbIdValue []int, yDataList []data_manage.YData, err error) {
+	if chartInfoId <= 0 {
+		return
+	}
+	// 指标对应的图例
+	extra := new(data_manage.CorrelationChartInfoExtraConfig)
+	if extraConfig != "" {
+		if e := json.Unmarshal([]byte(extraConfig), extra); e != nil {
+			err = fmt.Errorf("解析图表额外配置失败, err: %v", e)
+			return
+		}
+	}
+	legends := make(map[string]string)
+	if extra != nil {
+		for _, v := range extra.LegendConfig {
+			s := fmt.Sprintf("%d-%d", v.SeriesId, v.EdbInfoId)
+			legends[s] = v.LegendName
+		}
+	}
+
+	// 获取图表引用到的系列指标
+	edbMappings, e := data_manage.GetChartUsedFactorSeriesEdb(chartInfoId)
+	if e != nil {
+		err = fmt.Errorf("获取图表引用系列指标失败, err: %v", e)
+		return
+	}
+
+	// 取出计算结果
+	yDataList = make([]data_manage.YData, 0)
+	yDate := "0000-00-00"
+	for k, m := range edbMappings {
+		var values []data_manage.FactorEdbSeriesCorrelationMatrixValues
+		if m.CalculateData != "" {
+			e = json.Unmarshal([]byte(m.CalculateData), &values)
+			if e != nil {
+				err = fmt.Errorf("系列指标计算数据有误, err: %v", e)
+				return
+			}
+		}
+		var yData []float64
+		for _, v := range values {
+			if k == 0 {
+				xEdbIdValue = append(xEdbIdValue, v.XData)
+			}
+			yData = append(yData, v.YData)
+		}
+		s := fmt.Sprintf("%d-%d", m.FactorEdbSeriesId, m.EdbInfoId)
+		yDataList = append(yDataList, data_manage.YData{
+			Date:  yDate,
+			Value: yData,
+			Name:  legends[s], // 图例名称
+		})
+	}
+	return
+}
+
+// FormatChartEdbInfoMappings 补充指标信息
+func FormatChartEdbInfoMappings(chartInfoId int, mappings []*data_manage.ChartEdbInfoMapping) (edbList []*data_manage.ChartEdbInfoMapping, err error) {
+	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
+	if len(mappings) == 0 {
+		return
+	}
+
+	for _, v := range mappings {
+		if chartInfoId <= 0 {
+			v.IsAxis = 1
+			v.LeadValue = 0
+			v.LeadUnit = ""
+			v.ChartEdbMappingId = 0
+			v.ChartInfoId = 0
+			v.IsOrder = false
+			v.EdbInfoType = 1
+			v.ChartStyle = ""
+			v.ChartColor = ""
+			v.ChartWidth = 0
+		} else {
+			v.LeadUnitEn = data.GetLeadUnitEn(v.LeadUnit)
+			v.LeadUnitEn = data.GetLeadUnitEn(v.LeadUnit)
+		}
+		v.FrequencyEn = data.GetFrequencyEn(v.Frequency)
+		if v.Unit == `无` {
+			v.Unit = ``
+		}
+		edbList = append(edbList, v)
+	}
+	return
+}