浏览代码

Merge branch 'master' of http://8.136.199.33:3000/hongze/hongze_edb_lib

tuoling805 1 年之前
父节点
当前提交
bf630a27cc

+ 93 - 0
controllers/base_from_calculate.go

@@ -1793,3 +1793,96 @@ func (this *CalculateController) SaveAdjust() {
 	br.Data = resp
 	br.IsAddLog = true
 }
+
+// CalculateComputeCorrelation
+// @Title 拟合残差计算相关性
+// @Description 拟合残差计算相关性接口
+// @Param request body models.EdbInfoCalculateBatchSaveReq true "type json string"
+// @Success Ret=200 返回指标id
+// @router /compute_correlation [post]
+func (this *CalculateController) CalculateComputeCorrelation() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req models.EdbInfoCalculateBatchSaveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if len(req.EdbInfoIdArr) != 2 {
+		br.Msg = "选择的指标异常,请重新选择"
+		return
+	}
+
+	//校验时间格式
+	//数据格式:2022-11-01,2022-11-10
+	timeList := strings.Split(req.Formula, ",")
+	if len(timeList) != 2 {
+		br.Msg = "选择时间有误,请重新输入"
+		return
+	}
+	startDate, err := time.ParseInLocation(utils.FormatDate, timeList[0], time.Local)
+	if err != nil {
+		br.Msg = "开始日期有误,请重新输入"
+		return
+	}
+	endDate, err := time.ParseInLocation(utils.FormatDate, timeList[1], time.Local)
+	if err != nil {
+		br.Msg = "结束日期有误,请重新输入"
+		return
+	}
+	if utils.GetTimeSubDay(startDate, endDate) < 2 {
+		br.Msg = "日期间隔不得少于两天"
+		return
+	}
+	var nhccDate models.NhccDate // 拟合残差的日期
+	nhccDate.StartDate = startDate
+	nhccDate.EndDate = endDate
+
+	// 基础指标id
+	fromEdbInfoId := req.EdbInfoIdArr[0].EdbInfoId
+	if fromEdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	// 来源指标(自变量指标)
+	fromEdbInfo, err := models.GetEdbInfoById(fromEdbInfoId)
+	if err != nil {
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标信息失败:Err:" + err.Error()
+		return
+	}
+
+	// 因变量指标
+	secondEdbInfoReq := req.EdbInfoIdArr[1]
+	secondEdbInfo, tmpErr := models.GetEdbInfoById(secondEdbInfoReq.EdbInfoId)
+	if tmpErr != nil {
+		br.Msg = "获取因变量的指标信息失败"
+		br.ErrMsg = "获取因变量的指标信息失败:Err:" + tmpErr.Error()
+		return
+	}
+
+	if fromEdbInfo.EdbInfoId == secondEdbInfo.EdbInfoId {
+		br.Msg = "两个指标不允许为同一个"
+		br.ErrMsg = "两个指标不允许为同一个"
+		return
+	}
+	rVal, err := models.CalculateComputeCorrelation(&req, fromEdbInfo, secondEdbInfo, nhccDate)
+	if err != nil {
+		br.Msg = "计算失败"
+		br.ErrMsg = "计算失败,ERR:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "计算成功"
+	br.Data = rVal
+	br.IsAddLog = true
+}

+ 2 - 2
controllers/base_from_predict.go

@@ -58,7 +58,7 @@ func addPredict(br *models.BaseResponse, req models.AddPredictEdbInfoReq) {
 	}
 
 	// 添加指标
-	edbInfo, err, errMsg := logic.AddPredictEdbInfo(req.SourceEdbInfoId, req.ClassifyId, req.EdbName, req.RuleList, req.MinValue, req.MaxValue, req.AdminId, req.AdminName)
+	edbInfo, err, errMsg := logic.AddPredictEdbInfo(req.SourceEdbInfoId, req.ClassifyId, req.EdbName, req.DataDateType, req.RuleList, req.MinValue, req.MaxValue, req.AdminId, req.AdminName)
 	if err != nil {
 		br.Msg = "保存失败"
 		if errMsg != `` {
@@ -96,7 +96,7 @@ func editPredict(br *models.BaseResponse, req models.AddPredictEdbInfoReq) {
 	}
 
 	// 编辑指标
-	edbInfo, err, errMsg := logic.EditPredictEdbInfo(req.EdbInfoId, req.ClassifyId, req.EdbName, req.RuleList, req.MinValue, req.MaxValue)
+	edbInfo, err, errMsg := logic.EditPredictEdbInfo(req.EdbInfoId, req.ClassifyId, req.EdbName, req.DataDateType, req.RuleList, req.MinValue, req.MaxValue)
 	if err != nil {
 		br.Msg = "保存失败"
 		if errMsg != `` {

+ 99 - 0
controllers/base_from_predict_calculate.go

@@ -1183,3 +1183,102 @@ func (this *PredictCalculateController) Refresh() {
 	br.Success = true
 	br.Msg = "获取成功"
 }
+
+// CalculateComputeCorrelation
+// @Title 拟合残差计算相关性接口
+// @Description 拟合残差计算相关性接口
+// @Param	request	body models.EdbInfoCalculateBatchSaveReq true "type json string"
+// @Success Ret=200 返回指标id
+// @router /compute_correlation [post]
+func (this *PredictCalculateController) CalculateComputeCorrelation() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req models.EdbInfoCalculateBatchSaveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if len(req.EdbInfoIdArr) != 2 {
+		br.Msg = "选择的指标异常,请重新选择"
+		return
+	}
+
+	//校验时间格式
+	//数据格式:2022-11-01,2022-11-10
+	timeList := strings.Split(req.Formula, ",")
+	if len(timeList) != 2 {
+		br.Msg = "选择时间有误,请重新输入"
+		return
+	}
+	startDate, err := time.ParseInLocation(utils.FormatDate, timeList[0], time.Local)
+	if err != nil {
+		br.Msg = "开始日期有误,请重新输入"
+		return
+	}
+	endDate, err := time.ParseInLocation(utils.FormatDate, timeList[1], time.Local)
+	if err != nil {
+		br.Msg = "结束日期有误,请重新输入"
+		return
+	}
+	if utils.GetTimeSubDay(startDate, endDate) < 2 {
+		br.Msg = "日期间隔不得少于两天"
+		return
+	}
+
+	var nhccDate models.NhccDate // 拟合残差的日期
+	nhccDate.StartDate = startDate
+	nhccDate.EndDate = endDate
+
+	// 来源预测指标信息
+	fromEdbInfoId := req.EdbInfoIdArr[0].EdbInfoId
+	if fromEdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	// 来源指标(自变量指标)
+	fromEdbInfo, err := models.GetEdbInfoById(fromEdbInfoId)
+	if err != nil {
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标信息失败:Err:" + err.Error()
+		return
+	}
+	if fromEdbInfo.EdbInfoType != 1 {
+		br.Msg = "来源指标不是预测指标"
+		br.ErrMsg = "来源指标不是预测指标"
+		return
+	}
+
+	// 因变量指标
+	secondEdbInfoReq := req.EdbInfoIdArr[1]
+	secondEdbInfo, tmpErr := models.GetEdbInfoById(secondEdbInfoReq.EdbInfoId)
+	if tmpErr != nil {
+		br.Msg = "获取因变量的指标信息失败"
+		br.ErrMsg = "获取因变量的指标信息失败:Err:" + tmpErr.Error()
+		return
+	}
+
+	if fromEdbInfo.EdbInfoId == secondEdbInfo.EdbInfoId {
+		br.Msg = "两个指标不允许为同一个"
+		br.ErrMsg = "两个指标不允许为同一个"
+		return
+	}
+	rVal, err := models.CalculatePredictComputeCorrelation(&req, fromEdbInfo, secondEdbInfo, nhccDate)
+	if err != nil {
+		br.Msg = "计算失败"
+		br.ErrMsg = "计算失败,ERR:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "计算成功"
+	br.Data = rVal
+	br.IsAddLog = true
+}

+ 11 - 3
logic/predict_edb.go

@@ -10,7 +10,7 @@ import (
 )
 
 // AddPredictEdbInfo 新增预测指标
-func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName string, ruleList []models.RuleConfig, minValue, maxValue float64, sysUserId int, sysUserName string) (edbInfo *models.EdbInfo, err error, errMsg string) {
+func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName, dataDateType string, ruleList []models.RuleConfig, minValue, maxValue float64, sysUserId int, sysUserName string) (edbInfo *models.EdbInfo, err error, errMsg string) {
 	var sourceEdbInfo *models.EdbInfo
 	// 来源指标信息校验
 	{
@@ -86,6 +86,9 @@ func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName string, ruleList
 	}
 
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	if dataDateType == `` {
+		dataDateType = `自然日`
+	}
 	edbInfo = &models.EdbInfo{
 		//EdbInfoId:   0,
 		EdbInfoType:      1,
@@ -114,6 +117,7 @@ func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName string, ruleList
 		MoveFrequency: sourceEdbInfo.MoveFrequency,
 		NoUpdate:      sourceEdbInfo.NoUpdate,
 		ServerUrl:     "",
+		DataDateType:  dataDateType,
 	}
 
 	// 关联关系表
@@ -381,7 +385,7 @@ func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName string, ruleList
 }
 
 // EditPredictEdbInfo 编辑预测指标
-func EditPredictEdbInfo(edbInfoId, classifyId int, edbName string, ruleList []models.RuleConfig, minValue, maxValue float64) (edbInfo *models.EdbInfo, err error, errMsg string) {
+func EditPredictEdbInfo(edbInfoId, classifyId int, edbName, dataDateType string, ruleList []models.RuleConfig, minValue, maxValue float64) (edbInfo *models.EdbInfo, err error, errMsg string) {
 	// 指标信息校验
 	{
 		edbInfo, err = models.GetEdbInfoById(edbInfoId)
@@ -447,13 +451,17 @@ func EditPredictEdbInfo(edbInfoId, classifyId int, edbName string, ruleList []mo
 		return
 	}
 
+	if dataDateType == `` {
+		dataDateType = `自然日`
+	}
 	edbInfo.EdbName = edbName
 	edbInfo.EdbNameSource = edbName
 	edbInfo.ClassifyId = classifyId
 	edbInfo.MinValue = minValue
 	edbInfo.MaxValue = maxValue
+	edbInfo.DataDateType = dataDateType
 	edbInfo.ModifyTime = time.Now()
-	updateEdbInfoCol := []string{"EdbName", "EdbNameSource", "ClassifyId", "EndDate", "MinValue", "MaxValue", "ModifyTime"}
+	updateEdbInfoCol := []string{"EdbName", "EdbNameSource", "ClassifyId", "EndDate", "MinValue", "MaxValue", "DataDateType", "ModifyTime"}
 
 	var sourceEdbInfo *models.EdbInfo
 	// 来源指标信息校验

+ 222 - 69
models/edb_data_calculate_nhcc.go

@@ -435,75 +435,77 @@ func refreshAllCalculateNhcc(to orm.TxOrmer, edbInfo *EdbInfo, existItemA, exist
 
 	addDataList := make([]*EdbDataCalculateNhcc, 0)
 
-	//第一个指标
-	aDataList := make([]EdbInfoSearchData, 0)
-	aDataMap := make(map[string]float64)
-	{
-		var condition string
-		var pars []interface{}
-
-		condition += " AND edb_info_id=? "
-		pars = append(pars, existItemA.FromEdbInfoId)
-
-		//第一个指标的数据列表
-		firstDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemA.FromSource, 0)
-		if tmpErr != nil {
-			return tmpErr
-		}
-		aDataList, aDataMap = handleNhccData(firstDataList, existItemA.MoveValue)
-
-	}
-
-	//第二个指标
-	bDataList := make([]EdbInfoSearchData, 0)
-	secondDataList := make([]*EdbInfoSearchData, 0)
-	bDataMap := make(map[string]float64)
-	{
-		condition = ``
-		pars = make([]interface{}, 0)
-
-		condition += "  AND edb_info_id = ? "
-		pars = append(pars, existItemB.FromEdbInfoId)
-
-		//第二个指标的数据列表
-		secondDataList, err = GetEdbDataListAllByTo(to, condition, pars, existItemB.FromSource, 0)
-		if err != nil {
-			return
-		}
-		bDataList, bDataMap = handleNhccData(secondDataList, existItemB.MoveValue)
-	}
-
-	if len(aDataList) <= 0 {
-		err = errors.New("指标A没有数据")
-		return
-	}
-	if len(bDataList) <= 0 {
-		err = errors.New("指标B没有数据")
-		return
-	}
-	// 拟合残差计算的结束日期判断
-	{
-		endAData := aDataList[len(aDataList)-1]
-		tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, endAData.DataTime, time.Local)
-		if tmpErr != nil {
-			err = tmpErr
-			return
-		}
-		// 如果A指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
-		if tmpEndDate.Before(nhccDate.EndDate) {
-			nhccDate.EndDate = tmpEndDate
-		}
-		endBData := bDataList[len(bDataList)-1]
-		tmpEndDate, tmpErr = time.ParseInLocation(utils.FormatDate, endBData.DataTime, time.Local)
-		if tmpErr != nil {
-			err = tmpErr
-			return
-		}
-		// 如果B指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
-		if tmpEndDate.Before(nhccDate.EndDate) {
-			nhccDate.EndDate = tmpEndDate
-		}
-	}
+	////第一个指标
+	//aDataList := make([]EdbInfoSearchData, 0)
+	//aDataMap := make(map[string]float64)
+	//{
+	//	var condition string
+	//	var pars []interface{}
+	//
+	//	condition += " AND edb_info_id=? "
+	//	pars = append(pars, existItemA.FromEdbInfoId)
+	//
+	//	//第一个指标的数据列表
+	//	firstDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemA.FromSource, 0)
+	//	if tmpErr != nil {
+	//		return tmpErr
+	//	}
+	//	aDataList, aDataMap = handleNhccData(firstDataList, existItemA.MoveValue)
+	//
+	//}
+	//
+	////第二个指标
+	//bDataList := make([]EdbInfoSearchData, 0)
+	//secondDataList := make([]*EdbInfoSearchData, 0)
+	//bDataMap := make(map[string]float64)
+	//{
+	//	condition = ``
+	//	pars = make([]interface{}, 0)
+	//
+	//	condition += "  AND edb_info_id = ? "
+	//	pars = append(pars, existItemB.FromEdbInfoId)
+	//
+	//	//第二个指标的数据列表
+	//	secondDataList, err = GetEdbDataListAllByTo(to, condition, pars, existItemB.FromSource, 0)
+	//	if err != nil {
+	//		return
+	//	}
+	//	bDataList, bDataMap = handleNhccData(secondDataList, existItemB.MoveValue)
+	//}
+	//
+	//if len(aDataList) <= 0 {
+	//	err = errors.New("指标A没有数据")
+	//	return
+	//}
+	//if len(bDataList) <= 0 {
+	//	err = errors.New("指标B没有数据")
+	//	return
+	//}
+	//// 拟合残差计算的结束日期判断
+	//{
+	//	endAData := aDataList[len(aDataList)-1]
+	//	tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, endAData.DataTime, time.Local)
+	//	if tmpErr != nil {
+	//		err = tmpErr
+	//		return
+	//	}
+	//	// 如果A指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
+	//	if tmpEndDate.Before(nhccDate.EndDate) {
+	//		nhccDate.EndDate = tmpEndDate
+	//	}
+	//	endBData := bDataList[len(bDataList)-1]
+	//	tmpEndDate, tmpErr = time.ParseInLocation(utils.FormatDate, endBData.DataTime, time.Local)
+	//	if tmpErr != nil {
+	//		err = tmpErr
+	//		return
+	//	}
+	//	// 如果B指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
+	//	if tmpEndDate.Before(nhccDate.EndDate) {
+	//		nhccDate.EndDate = tmpEndDate
+	//	}
+	//}
+
+	aDataList, secondDataList, aDataMap, bDataMap, err := getNhccData(to, existItemA, existItemB, nhccDate)
 
 	// 计算线性方程公式
 	var a, b float64
@@ -642,6 +644,157 @@ func refreshAllCalculateNhcc(to orm.TxOrmer, edbInfo *EdbInfo, existItemA, exist
 	return
 }
 
+// CalculateComputeCorrelation 计算相关性结果
+func CalculateComputeCorrelation(req *EdbInfoCalculateBatchSaveReq, firstEdbInfo, secondEdbInfo *EdbInfo, nhccDate NhccDate) (r float64, err error) {
+	var existItemA, existItemB *EdbInfoCalculateMapping
+	//第一个指标
+	{
+		existItemA = &EdbInfoCalculateMapping{
+			EdbInfoCalculateMappingId: 0,
+			FromEdbInfoId:             firstEdbInfo.EdbInfoId,
+			FromEdbCode:               firstEdbInfo.EdbCode,
+			FromEdbName:               firstEdbInfo.EdbName,
+			FromSource:                firstEdbInfo.Source,
+			FromSourceName:            firstEdbInfo.SourceName,
+			FromTag:                   "A",
+			MoveValue:                 req.EdbInfoIdArr[0].MoveValue,
+			Sort:                      1,
+			CreateTime:                time.Now(),
+			ModifyTime:                time.Now(),
+		}
+	}
+
+	//第二个指标
+	{
+		existItemB = &EdbInfoCalculateMapping{
+			EdbInfoCalculateMappingId: 0,
+			FromEdbInfoId:             secondEdbInfo.EdbInfoId,
+			FromEdbCode:               secondEdbInfo.EdbCode,
+			FromEdbName:               secondEdbInfo.EdbName,
+			FromSource:                secondEdbInfo.Source,
+			FromSourceName:            secondEdbInfo.SourceName,
+			FromTag:                   "B",
+			MoveValue:                 req.EdbInfoIdArr[1].MoveValue,
+			Sort:                      1,
+			CreateTime:                time.Now(),
+			ModifyTime:                time.Now(),
+		}
+	}
+
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateNhcc,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	// 获取相关数据
+	_, _, aDataMap, bDataMap, err := getNhccData(to, existItemA, existItemB, nhccDate)
+
+	// 计算相关性
+	coordinateData := make([]utils.Coordinate, 0)
+	for i := nhccDate.StartDate; i.Before(nhccDate.EndDate) || i.Equal(nhccDate.EndDate); i = i.AddDate(0, 0, 1) {
+		dateStr := i.Format(utils.FormatDate)
+		xValue, ok := aDataMap[dateStr]
+		if !ok {
+			err = errors.New("指标A日期:" + dateStr + "数据异常,导致计算线性方程公式失败")
+			return
+		}
+		yValue, ok := bDataMap[dateStr]
+		if !ok {
+			err = errors.New("指标B日期:" + dateStr + "数据异常,导致计算线性方程公式失败")
+			return
+		}
+		tmpCoordinate := utils.Coordinate{
+			X: xValue,
+			Y: yValue,
+		}
+		coordinateData = append(coordinateData, tmpCoordinate)
+	}
+	r = utils.ComputeCorrelation(coordinateData)
+
+	return
+}
+
+// getNhccData 获取拟合残差需要的数据
+func getNhccData(to orm.TxOrmer, existItemA, existItemB *EdbInfoCalculateMapping, nhccDate NhccDate) (aDataList []EdbInfoSearchData, secondDataList []*EdbInfoSearchData, aDataMap, bDataMap map[string]float64, err error) {
+	//第一个指标
+	aDataList = make([]EdbInfoSearchData, 0)
+	aDataMap = make(map[string]float64)
+	{
+		var condition string
+		var pars []interface{}
+
+		condition += " AND edb_info_id=? "
+		pars = append(pars, existItemA.FromEdbInfoId)
+
+		//第一个指标的数据列表
+		firstDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemA.FromSource, 0)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		aDataList, aDataMap = handleNhccData(firstDataList, existItemA.MoveValue)
+
+	}
+
+	//第二个指标
+	bDataList := make([]EdbInfoSearchData, 0)
+	secondDataList = make([]*EdbInfoSearchData, 0)
+	bDataMap = make(map[string]float64)
+	{
+		condition := ``
+		pars := make([]interface{}, 0)
+
+		condition += "  AND edb_info_id = ? "
+		pars = append(pars, existItemB.FromEdbInfoId)
+
+		//第二个指标的数据列表
+		secondDataList, err = GetEdbDataListAllByTo(to, condition, pars, existItemB.FromSource, 0)
+		if err != nil {
+			return
+		}
+		bDataList, bDataMap = handleNhccData(secondDataList, existItemB.MoveValue)
+	}
+
+	if len(aDataList) <= 0 {
+		err = errors.New("指标A没有数据")
+		return
+	}
+	if len(bDataList) <= 0 {
+		err = errors.New("指标B没有数据")
+		return
+	}
+	// 拟合残差计算的结束日期判断
+	{
+		endAData := aDataList[len(aDataList)-1]
+		tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, endAData.DataTime, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		// 如果A指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
+		if tmpEndDate.Before(nhccDate.EndDate) {
+			nhccDate.EndDate = tmpEndDate
+		}
+		endBData := bDataList[len(bDataList)-1]
+		tmpEndDate, tmpErr = time.ParseInLocation(utils.FormatDate, endBData.DataTime, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		// 如果B指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
+		if tmpEndDate.Before(nhccDate.EndDate) {
+			nhccDate.EndDate = tmpEndDate
+		}
+	}
+
+	return
+}
+
 // handleNhccData 处理拟合残差需要的数据
 func handleNhccData(dataList []*EdbInfoSearchData, moveDay int) (newDataList []EdbInfoSearchData, dateDataMap map[string]float64) {
 	dateMap := make(map[time.Time]float64)

+ 17 - 63
models/edb_info.go

@@ -38,13 +38,14 @@ type EdbInfo struct {
 	NoUpdate         int8    `description:"是否停止更新,0:继续更新;1:停止更新"`
 	ServerUrl        string  `description:"服务器地址"`
 
-	EdbInfoType int     `description:"指标类型,0:普通指标,1:预测指标"`
-	EdbNameEn   string  `description:"英文指标名称"`
-	UnitEn      string  `description:"英文单位"`
-	LatestDate  string  `description:"数据最新日期"`
-	LatestValue float64 `description:"数据最新值"`
-	ChartImage  string  `description:"图表图片"`
-	Calendar    string  `description:"公历/农历"`
+	EdbInfoType  int     `description:"指标类型,0:普通指标,1:预测指标"`
+	EdbNameEn    string  `description:"英文指标名称"`
+	UnitEn       string  `description:"英文单位"`
+	LatestDate   string  `description:"数据最新日期"`
+	LatestValue  float64 `description:"数据最新值"`
+	ChartImage   string  `description:"图表图片"`
+	Calendar     string  `description:"公历/农历"`
+	DataDateType string  `orm:"column(data_date_type);size(255);null;default(交易日)"`
 }
 
 // AddEdbInfo 添加指标
@@ -419,57 +420,8 @@ func UnifiedModifyPredictEdbInfoMaxAndMinInfo(edbInfo *EdbInfo, latestDateStr st
 	return
 }
 
-// GetChartPredictEdbInfoDataList 获取图表的预测指标的未来数据
-func GetChartPredictEdbInfoDataList(predictEdbConf PredictEdbConf, latestDateStr string, lastDataValue float64, endDateStr, frequency string, order int) (predictEdbInfoData []*EdbInfoSearchData, err error) {
-	endDate, err := time.ParseInLocation(utils.FormatDate, endDateStr, time.Local)
-	if err != nil {
-		return
-	}
-
-	latestDate, err := time.ParseInLocation(utils.FormatDate, latestDateStr, time.Local)
-	if err != nil {
-		return
-	}
-
-	// 开始预测数据的时间
-	startDate := latestDate
-
-	dataValue := lastDataValue
-	if predictEdbConf.RuleType == 2 {
-		dataValue = predictEdbConf.FixedValue
-	}
-	//获取后面的预测数据
-	dayList := getPredictEdbDayList(startDate, endDate, frequency)
-	predictEdbInfoData = make([]*EdbInfoSearchData, 0)
-
-	// order:1升序,其余值为降序
-	if order == 1 {
-		for k, v := range dayList {
-			predictEdbInfoData = append(predictEdbInfoData, &EdbInfoSearchData{
-				EdbDataId: predictEdbConf.PredictEdbInfoId + 10000000000 + k,
-				DataTime:  v.Format(utils.FormatDate),
-				Value:     dataValue,
-			})
-		}
-	} else {
-		lenDayList := len(dayList)
-		if lenDayList > 0 {
-			for i := lenDayList - 1; i >= 0; i-- {
-				v := dayList[i]
-				predictEdbInfoData = append(predictEdbInfoData, &EdbInfoSearchData{
-					EdbDataId: predictEdbConf.PredictEdbInfoId + 10000000000 + i,
-					DataTime:  v.Format(utils.FormatDate),
-					Value:     dataValue,
-				})
-			}
-		}
-	}
-
-	return
-}
-
 // GetChartPredictEdbInfoDataListByConfList 获取图表的预测指标的未来数据
-func GetChartPredictEdbInfoDataListByConfList(predictEdbConfList []*PredictEdbConfAndData, filtrateStartDateStr, latestDateStr, endDateStr, frequency string, realPredictEdbInfoData []*EdbInfoSearchData) (predictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64, err error) {
+func GetChartPredictEdbInfoDataListByConfList(predictEdbConfList []*PredictEdbConfAndData, filtrateStartDateStr, latestDateStr, endDateStr, frequency, dataDateType string, realPredictEdbInfoData []*EdbInfoSearchData) (predictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64, err error) {
 	endDate, err := time.ParseInLocation(utils.FormatDate, endDateStr, time.Local)
 	if err != nil {
 		return
@@ -516,7 +468,7 @@ func GetChartPredictEdbInfoDataListByConfList(predictEdbConfList []*PredictEdbCo
 
 		var tmpMinValue, tmpMaxValue float64 // 当前预测结果中的最大/最小值
 
-		dayList := getPredictEdbDayList(startDate, dataEndTime, frequency)
+		dayList := getPredictEdbDayList(startDate, dataEndTime, frequency, dataDateType)
 		if len(dayList) <= 0 { // 如果未来没有日期的话,那么就退出当前循环,进入下一个循环
 			continue
 		}
@@ -747,13 +699,15 @@ func GetChartPredictEdbInfoDataListByConfList(predictEdbConfList []*PredictEdbCo
 // GetPredictEdbDayList 获取预测指标日期列表
 
 // GetPredictEdbDayList 获取预测指标日期列表
-func getPredictEdbDayList(startDate, endDate time.Time, frequency string) (dayList []time.Time) {
-	//if !utils.InArrayByStr([]string{"日度", "周度", "月度"}, frequency)
+func getPredictEdbDayList(startDate, endDate time.Time, frequency, dataDateType string) (dayList []time.Time) {
+	if dataDateType == `` {
+		dataDateType = `交易日`
+	}
 	switch frequency {
 	case "日度":
 		for currDate := startDate.AddDate(0, 0, 1); currDate.Before(endDate) || currDate.Equal(endDate); currDate = currDate.AddDate(0, 0, 1) {
-			//周六、日排除
-			if currDate.Weekday() == time.Sunday || currDate.Weekday() == time.Saturday {
+			// 如果日期类型是交易日的时候,那么需要将周六、日排除
+			if dataDateType == `交易日` && (currDate.Weekday() == time.Sunday || currDate.Weekday() == time.Saturday) {
 				continue
 			}
 			dayList = append(dayList, currDate)
@@ -880,7 +834,7 @@ func GetPredictDataListByPredictEdbConfList(edbInfo, sourceEdbInfoItem *EdbInfo,
 	var predictMinValue, predictMaxValue float64
 	// 如果有配置的预测规则,那么就进行预测
 	if len(predictEdbConfList) > 0 {
-		predictDataList, predictMinValue, predictMaxValue, err = GetChartPredictEdbInfoDataListByConfList(predictEdbConfList, startDate, sourceEdbInfoItem.LatestDate, endDateStr, edbInfo.Frequency, allDataList)
+		predictDataList, predictMinValue, predictMaxValue, err = GetChartPredictEdbInfoDataListByConfList(predictEdbConfList, startDate, sourceEdbInfoItem.LatestDate, endDateStr, edbInfo.Frequency, edbInfo.DataDateType, allDataList)
 		if err != nil {
 			return
 		}

+ 1 - 1
models/predict_edb.go

@@ -281,7 +281,7 @@ func CalculateByRuleByRuleLineNh(to orm.TxOrmer, predictEdbInfo EdbInfo, predict
 		startDate, _ := time.ParseInLocation(utils.FormatDate, startDateStr, time.Local)
 		//endDate, _ := time.ParseInLocation(utils.FormatDate, ruleConf.EndDate, time.Local)
 		endDate := rule.EndDate
-		dayList := getPredictEdbDayList(startDate, endDate, predictEdbInfo.Frequency)
+		dayList := getPredictEdbDayList(startDate, endDate, predictEdbInfo.Frequency, predictEdbInfo.DataDateType)
 		if len(dayList) <= 0 { // 如果未来没有日期的话,那么就退出当前循环,进入下一个循环
 			return
 		}

+ 1 - 0
models/predict_edb_conf.go

@@ -17,6 +17,7 @@ type AddPredictEdbInfoReq struct {
 	RuleList        []RuleConfig `description:"配置规则列表"`
 	MaxValue        float64      `description:"最大值"`
 	MinValue        float64      `description:"最小值"`
+	DataDateType    string       `description:"日期类型,枚举值:交易日、自然日"`
 }
 
 // RuleConfig 预测规则配置

+ 161 - 78
models/predict_edb_data_calculate_nhcc.go

@@ -417,84 +417,7 @@ func refreshAllPredictCalculateNhcc(to orm.TxOrmer, edbInfo, firstEdbInfo, secon
 
 	addDataList := make([]*EdbDataPredictCalculateNhcc, 0)
 
-	//第一个指标
-	aDataList := make([]EdbInfoSearchData, 0)
-	aDataMap := make(map[string]float64)
-	{
-		/*var condition string
-		var pars []interface{}
-
-		condition += " AND edb_info_id=? "
-		pars = append(pars, existItemA.FromEdbInfoId)
-
-		//第一个指标的数据列表
-		firstDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemA.FromSource, 0)
-		if tmpErr != nil {
-
-			return tmpErr
-		}*/
-		var firstDataList []*EdbInfoSearchData
-		firstDataList, err = GetPredictEdbDataListAllByStartDate(firstEdbInfo, 0, "")
-		if err != nil {
-			return
-		}
-		aDataList, aDataMap = handleNhccData(firstDataList, existItemA.MoveValue)
-	}
-
-	//第二个指标
-	bDataList := make([]EdbInfoSearchData, 0)
-	secondDataList := make([]*EdbInfoSearchData, 0)
-	bDataMap := make(map[string]float64)
-	{
-		/*condition = ``
-		pars = make([]interface{}, 0)
-
-		condition += "  AND edb_info_id = ? "
-		pars = append(pars, existItemB.FromEdbInfoId)
-
-		//第二个指标的数据列表
-		secondDataList, err = GetEdbDataListAllByTo(to, condition, pars, existItemB.FromSource, 0)
-		if err != nil {
-			return
-		}*/
-		secondDataList, err = GetPredictEdbDataListAllByStartDate(secondEdbInfo, 0, "")
-		if err != nil {
-			return
-		}
-		bDataList, bDataMap = handleNhccData(secondDataList, existItemB.MoveValue)
-	}
-
-	if len(aDataList) <= 0 {
-		err = errors.New("指标A没有数据")
-		return
-	}
-	if len(bDataList) <= 0 {
-		err = errors.New("指标B没有数据")
-		return
-	}
-	// 拟合残差计算的结束日期判断
-	{
-		endAData := aDataList[len(aDataList)-1]
-		tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, endAData.DataTime, time.Local)
-		if tmpErr != nil {
-			err = tmpErr
-			return
-		}
-		// 如果A指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
-		if tmpEndDate.Before(nhccDate.EndDate) {
-			nhccDate.EndDate = tmpEndDate
-		}
-		endBData := bDataList[len(bDataList)-1]
-		tmpEndDate, tmpErr = time.ParseInLocation(utils.FormatDate, endBData.DataTime, time.Local)
-		if tmpErr != nil {
-			err = tmpErr
-			return
-		}
-		// 如果B指标的最新数据日期早于拟合残差的结束日期,那么就用B指标的最新数据日期
-		if tmpEndDate.Before(nhccDate.EndDate) {
-			nhccDate.EndDate = tmpEndDate
-		}
-	}
+	aDataList, secondDataList, aDataMap, bDataMap, err := getPredictNhccData(firstEdbInfo, secondEdbInfo, existItemA, existItemB, nhccDate)
 
 	// 计算线性方程公式
 	var a, b float64
@@ -645,3 +568,163 @@ func refreshAllPredictCalculateNhcc(to orm.TxOrmer, edbInfo, firstEdbInfo, secon
 	}
 	return
 }
+
+// CalculatePredictComputeCorrelation 计算相关性结果
+func CalculatePredictComputeCorrelation(req *EdbInfoCalculateBatchSaveReq, firstEdbInfo, secondEdbInfo *EdbInfo, nhccDate NhccDate) (r float64, err error) {
+	var existItemA, existItemB *EdbInfoCalculateMapping
+	//第一个指标
+	{
+		existItemA = &EdbInfoCalculateMapping{
+			EdbInfoCalculateMappingId: 0,
+			FromEdbInfoId:             firstEdbInfo.EdbInfoId,
+			FromEdbCode:               firstEdbInfo.EdbCode,
+			FromEdbName:               firstEdbInfo.EdbName,
+			FromSource:                firstEdbInfo.Source,
+			FromSourceName:            firstEdbInfo.SourceName,
+			FromTag:                   "A",
+			MoveValue:                 req.EdbInfoIdArr[0].MoveValue,
+			Sort:                      1,
+			CreateTime:                time.Now(),
+			ModifyTime:                time.Now(),
+		}
+	}
+
+	//第二个指标
+	{
+		existItemB = &EdbInfoCalculateMapping{
+			EdbInfoCalculateMappingId: 0,
+			FromEdbInfoId:             secondEdbInfo.EdbInfoId,
+			FromEdbCode:               secondEdbInfo.EdbCode,
+			FromEdbName:               secondEdbInfo.EdbName,
+			FromSource:                secondEdbInfo.Source,
+			FromSourceName:            secondEdbInfo.SourceName,
+			FromTag:                   "B",
+			MoveValue:                 req.EdbInfoIdArr[1].MoveValue,
+			Sort:                      1,
+			CreateTime:                time.Now(),
+			ModifyTime:                time.Now(),
+		}
+	}
+
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateNhcc,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	// 获取相关数据
+	_, _, aDataMap, bDataMap, err := getPredictNhccData(firstEdbInfo, secondEdbInfo, existItemA, existItemB, nhccDate)
+
+	// 计算相关性
+	coordinateData := make([]utils.Coordinate, 0)
+	for i := nhccDate.StartDate; i.Before(nhccDate.EndDate) || i.Equal(nhccDate.EndDate); i = i.AddDate(0, 0, 1) {
+		dateStr := i.Format(utils.FormatDate)
+		xValue, ok := aDataMap[dateStr]
+		if !ok {
+			err = errors.New("指标A日期:" + dateStr + "数据异常,导致计算线性方程公式失败")
+			return
+		}
+		yValue, ok := bDataMap[dateStr]
+		if !ok {
+			err = errors.New("指标B日期:" + dateStr + "数据异常,导致计算线性方程公式失败")
+			return
+		}
+		tmpCoordinate := utils.Coordinate{
+			X: xValue,
+			Y: yValue,
+		}
+		coordinateData = append(coordinateData, tmpCoordinate)
+	}
+	r = utils.ComputeCorrelation(coordinateData)
+
+	return
+}
+
+// getNhccData 获取拟合残差需要的数据
+func getPredictNhccData(firstEdbInfo, secondEdbInfo *EdbInfo, existItemA, existItemB *EdbInfoCalculateMapping, nhccDate NhccDate) (aDataList []EdbInfoSearchData, secondDataList []*EdbInfoSearchData, aDataMap, bDataMap map[string]float64, err error) {
+	//第一个指标
+	aDataList = make([]EdbInfoSearchData, 0)
+	aDataMap = make(map[string]float64)
+	{
+		/*var condition string
+		var pars []interface{}
+
+		condition += " AND edb_info_id=? "
+		pars = append(pars, existItemA.FromEdbInfoId)
+
+		//第一个指标的数据列表
+		firstDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemA.FromSource, 0)
+		if tmpErr != nil {
+
+			return tmpErr
+		}*/
+		var firstDataList []*EdbInfoSearchData
+		firstDataList, err = GetPredictEdbDataListAllByStartDate(firstEdbInfo, 0, "")
+		if err != nil {
+			return
+		}
+		aDataList, aDataMap = handleNhccData(firstDataList, existItemA.MoveValue)
+	}
+
+	//第二个指标
+	bDataList := make([]EdbInfoSearchData, 0)
+	secondDataList = make([]*EdbInfoSearchData, 0)
+	bDataMap = make(map[string]float64)
+	{
+		/*condition = ``
+		pars = make([]interface{}, 0)
+
+		condition += "  AND edb_info_id = ? "
+		pars = append(pars, existItemB.FromEdbInfoId)
+
+		//第二个指标的数据列表
+		secondDataList, err = GetEdbDataListAllByTo(to, condition, pars, existItemB.FromSource, 0)
+		if err != nil {
+			return
+		}*/
+		secondDataList, err = GetPredictEdbDataListAllByStartDate(secondEdbInfo, 0, "")
+		if err != nil {
+			return
+		}
+		bDataList, bDataMap = handleNhccData(secondDataList, existItemB.MoveValue)
+	}
+
+	if len(aDataList) <= 0 {
+		err = errors.New("指标A没有数据")
+		return
+	}
+	if len(bDataList) <= 0 {
+		err = errors.New("指标B没有数据")
+		return
+	}
+
+	// 拟合残差计算的结束日期判断
+	{
+		endAData := aDataList[len(aDataList)-1]
+		tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, endAData.DataTime, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		// 如果A指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
+		if tmpEndDate.Before(nhccDate.EndDate) {
+			nhccDate.EndDate = tmpEndDate
+		}
+		endBData := bDataList[len(bDataList)-1]
+		tmpEndDate, tmpErr = time.ParseInLocation(utils.FormatDate, endBData.DataTime, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		// 如果B指标的最新数据日期早于拟合残差的结束日期,那么就用B指标的最新数据日期
+		if tmpEndDate.Before(nhccDate.EndDate) {
+			nhccDate.EndDate = tmpEndDate
+		}
+	}
+
+	return
+}

+ 27 - 0
routers/commentsRouter.go

@@ -106,6 +106,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:CalculateController"] = append(beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:CalculateController"],
+        beego.ControllerComments{
+            Method: "CalculateComputeCorrelation",
+            Router: `/compute_correlation`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:CalculateController"] = append(beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:CalculateController"],
         beego.ControllerComments{
             Method: "Edit",
@@ -214,6 +223,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:EdbInfoController"] = append(beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:EiaSteoController"] = append(beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:EiaSteoController"],
         beego.ControllerComments{
             Method: "Add",
@@ -547,6 +565,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:PredictCalculateController"] = append(beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:PredictCalculateController"],
+        beego.ControllerComments{
+            Method: "CalculateComputeCorrelation",
+            Router: `/compute_correlation`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:PredictCalculateController"] = append(beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:PredictCalculateController"],
         beego.ControllerComments{
             Method: "Refresh",