package services import ( "encoding/json" aiPredictModel "eta/eta_api/models/ai_predict_model" "eta/eta_api/models/data_manage" "eta/eta_api/services/data" "eta/eta_api/utils" "fmt" "sort" "strconv" "time" ) func ImportAiPredictModelIndexAndData(imports []*aiPredictModel.AiPredictModelImportData, adminId int, adminRealName string) (err error) { if len(imports) == 0 { return } // 查询已存在的标的 indexOb := new(aiPredictModel.AiPredictModelIndex) indexNameItem := make(map[string]*aiPredictModel.AiPredictModelIndex) { list, e := indexOb.GetItemsByCondition("", make([]interface{}, 0), []string{}, "") if e != nil { err = fmt.Errorf("获取标的失败, %v", e) return } for _, v := range list { indexNameItem[v.IndexName] = v } } updateCols := []string{indexOb.Cols().ClassifyId, indexOb.Cols().ModelFramework, indexOb.Cols().PredictDate, indexOb.Cols().PredictValue, indexOb.Cols().DirectionAccuracy, indexOb.Cols().AbsoluteDeviation, indexOb.Cols().ExtraConfig, indexOb.Cols().SysUserId, indexOb.Cols().SysUserRealName, indexOb.Cols().ModifyTime} updateIndexes := make([]*aiPredictModel.AiPredictModelImportData, 0) createIndexes := make([]*aiPredictModel.AiPredictModelImportData, 0) for _, v := range imports { exist := indexNameItem[v.Index.IndexName] // 编辑 if exist != nil { // 图例信息 if exist.ExtraConfig != "" && v.Index.ExtraConfig != "" { var oldConfig, newConfig aiPredictModel.AiPredictModelIndexExtraConfig if e := json.Unmarshal([]byte(exist.ExtraConfig), &oldConfig); e != nil { err = fmt.Errorf("标的原配置解析失败, Config: %s, Err: %v", exist.ExtraConfig, e) return } if e := json.Unmarshal([]byte(v.Index.ExtraConfig), &newConfig); e != nil { err = fmt.Errorf("标的新配置解析失败, Config: %s, Err: %v", v.Index.ExtraConfig, e) return } oldConfig.DailyChart.PredictLegendName = newConfig.DailyChart.PredictLegendName b, _ := json.Marshal(oldConfig) v.Index.ExtraConfig = string(b) } v.Index.AiPredictModelIndexId = exist.AiPredictModelIndexId v.Index.IndexCode = exist.IndexCode updateIndexes = append(updateIndexes, v) continue } // 新增标的/图表 indexCode, e := utils.GenerateEdbCode(1, "IPM") if e != nil { err = fmt.Errorf("生成标的编码失败, %v", e) return } v.Index.IndexCode = indexCode v.Charts = GetAiPredictCharts(v.Index.IndexName, adminId, adminRealName) createIndexes = append(createIndexes, v) } // 新增/更新指标 chartIds, e := indexOb.ImportIndexAndData(createIndexes, updateIndexes, updateCols) if e != nil { err = fmt.Errorf("导入指标失败, %v", e) return } // 更新图表ES if len(chartIds) == 0 { return } go func() { for _, v := range chartIds { data.EsAddOrEditChartInfo(v) } }() return } func GetAiPredictChartDetailByData(indexItem *aiPredictModel.AiPredictModelIndex, indexData []*aiPredictModel.AiPredictModelData, source int) (resp *data_manage.ChartInfoDetailResp, err error) { resp = new(data_manage.ChartInfoDetailResp) // 标的配置 var extraConfig aiPredictModel.AiPredictModelIndexExtraConfig if indexItem.ExtraConfig != "" { if e := json.Unmarshal([]byte(indexItem.ExtraConfig), &extraConfig); e != nil { err = fmt.Errorf("标的额外配置解析失败, Config: %s, Err: %v", indexItem.ExtraConfig, e) return } } // 图表信息 var predictLegendName, confLeftMin, confLeftMax, unit string if source == aiPredictModel.ModelDataSourceDaily { predictLegendName = extraConfig.DailyChart.PredictLegendName if predictLegendName == "" { predictLegendName = "Predicted" } unit = extraConfig.DailyChart.Unit confLeftMin = extraConfig.DailyChart.LeftMin confLeftMax = extraConfig.DailyChart.LeftMax } if source == aiPredictModel.ModelDataSourceMonthly { predictLegendName = "预测值" unit = extraConfig.MonthlyChart.Unit confLeftMin = extraConfig.MonthlyChart.LeftMin confLeftMax = extraConfig.MonthlyChart.LeftMax } // 这里简单兼容下吧,暂时就不修数据了 if confLeftMin == "" { confLeftMin = indexItem.LeftMin } if confLeftMax == "" { confLeftMax = indexItem.LeftMax } // 获取指标对应的图表 chartSourceMapping := map[int]int{ aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY, aiPredictModel.ModelDataSourceDaily: utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY, } chartInfo, e := data_manage.GetAiPredictChartInfoByIndexId(chartSourceMapping[source], indexItem.AiPredictModelIndexId) if e != nil && !utils.IsErrNoRow(e) { err = fmt.Errorf("获取标的图表失败, %v", e) return } // 获取曲线图主题样式 chartView := new(data_manage.ChartInfoView) if chartInfo != nil && chartInfo.ChartInfoId > 0 { chartView.ChartInfoId = chartInfo.ChartInfoId chartView.ChartName = chartInfo.ChartName chartView.ChartNameEn = chartInfo.ChartNameEn chartView.Source = chartInfo.Source chartView.ChartImage = chartInfo.ChartImage } else { chartView.ChartName = indexItem.IndexName chartView.ChartNameEn = indexItem.IndexName } chartView.ChartType = utils.CHART_SOURCE_DEFAULT chartTheme, e := data.GetChartThemeConfig(0, chartView.ChartType, utils.CHART_TYPE_CURVE) if e != nil { err = fmt.Errorf("获取图表主题样式失败, %v", e) return } chartView.ChartThemeStyle = chartTheme.Config chartView.ChartThemeId = chartTheme.ChartThemeId chartView.ChartName = indexItem.IndexName chartView.ChartNameEn = indexItem.IndexName chartView.DateType = 3 chartView.Calendar = "公历" chartView.ChartSource = "AI预测模型" chartView.ChartSourceEn = "AI预测模型" chartView.Unit = unit chartView.UnitEn = unit // EdbList-固定一条为标的实际值、一条为预测值 edbList := make([]*data_manage.ChartEdbInfoMapping, 0) edbActual, edbPredict := new(data_manage.ChartEdbInfoMapping), new(data_manage.ChartEdbInfoMapping) edbActual.EdbName = indexItem.IndexName edbActual.EdbNameEn = indexItem.IndexName edbActual.IsAxis = 1 edbActual.Unit = unit edbActual.UnitEn = unit edbPredict.EdbName = predictLegendName edbPredict.EdbNameEn = predictLegendName edbPredict.IsAxis = 1 edbPredict.Unit = unit edbPredict.UnitEn = unit actualData, predictData := make([]*data_manage.EdbDataList, 0), make([]*data_manage.EdbDataList, 0) var startDate, endDate time.Time var actualValues, predictValues []float64 var actualNewest, predictNewest bool var actualLatestTimestamp int64 // 实际值最后一天的时间戳,作为日度图表的分割线 for k, v := range indexData { // 如果实际值和预测值都是null那么该日期无效直接忽略 if !v.Value.Valid && !v.PredictValue.Valid { continue } // 将有效值加入[]float64,最后取极值 if v.Value.Valid { actualValues = append(actualValues, v.Value.Float64) } if v.PredictValue.Valid { predictValues = append(predictValues, v.PredictValue.Float64) } // 开始结束时间 if k == 0 { startDate = v.DataTime endDate = v.CreateTime } if v.DataTime.Before(startDate) { startDate = v.DataTime } if v.DataTime.After(endDate) { endDate = v.DataTime } // 指标数据 if v.Value.Valid { if !actualNewest { edbActual.LatestDate = v.DataTime.Format(utils.FormatDate) edbActual.LatestValue = v.Value.Float64 actualLatestTimestamp = v.DataTime.UnixNano() / 1e6 actualNewest = true } actualData = append(actualData, &data_manage.EdbDataList{ DataTime: v.DataTime.Format(utils.FormatDate), Value: v.Value.Float64, DataTimestamp: v.DataTimestamp, }) } if v.PredictValue.Valid { if !predictNewest { edbPredict.LatestDate = v.DataTime.Format(utils.FormatDate) edbPredict.LatestValue = v.Value.Float64 predictNewest = true } predictData = append(predictData, &data_manage.EdbDataList{ DataTime: v.DataTime.Format(utils.FormatDate), Value: v.PredictValue.Float64, DataTimestamp: v.DataTimestamp, }) } } // 图表数据这里均做一个升序排序 sort.Slice(actualData, func(i, j int) bool { return actualData[i].DataTimestamp < actualData[j].DataTimestamp }) sort.Slice(predictData, func(i, j int) bool { return predictData[i].DataTimestamp < predictData[j].DataTimestamp }) // 极值 actualMin, actualMax := utils.FindMinMax(actualValues) predictMin, predictMax := utils.FindMinMax(predictValues) edbActual.MinData = actualMin edbActual.MaxData = actualMax edbPredict.MinData = predictMin edbPredict.MaxData = predictMax edbActual.DataList = actualData edbPredict.DataList = predictData edbList = append(edbList, edbActual, edbPredict) // 上下限 if confLeftMin != "" { chartView.LeftMin = confLeftMin } else { leftMin := actualMin if leftMin > predictMin { leftMin = predictMin } chartView.LeftMin = fmt.Sprint(leftMin) } if confLeftMax != "" { chartView.LeftMax = confLeftMax } else { leftMax := actualMax if leftMax < predictMax { leftMax = predictMax } chartView.LeftMax = fmt.Sprint(leftMax) } chartView.StartDate = startDate.Format(utils.FormatDate) chartView.EndDate = endDate.Format(utils.FormatDate) // 日度图表的分割线日期 if source == aiPredictModel.ModelDataSourceDaily { var dataResp struct { ActualLatestTimestamp int64 } dataResp.ActualLatestTimestamp = actualLatestTimestamp resp.DataResp = dataResp } resp.ChartInfo = chartView resp.EdbInfoList = edbList return } // GetAiPredictCharts 获取AI预测模型图表 func GetAiPredictCharts(indexName string, adminId int, adminRealName string) (charts []*aiPredictModel.AiPredictModelImportCharts) { charts = make([]*aiPredictModel.AiPredictModelImportCharts, 0) // 日度/月度图表 frequencyArr := []int{aiPredictModel.ModelDataSourceMonthly, aiPredictModel.ModelDataSourceDaily} sourceMapping := map[int]int{ aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY, aiPredictModel.ModelDataSourceDaily: utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY, } suffixNameMapping := map[int]string{ aiPredictModel.ModelDataSourceMonthly: "预测模型/回测", aiPredictModel.ModelDataSourceDaily: "预测模型", } for _, v := range frequencyArr { chartSource := sourceMapping[v] newChart := new(aiPredictModel.AiPredictModelImportCharts) // 新增图表 chartName := fmt.Sprintf("%s%s", indexName, suffixNameMapping[v]) chartInfo := new(data_manage.ChartInfo) chartInfo.ChartName = chartName chartInfo.ChartNameEn = chartName chartInfo.ChartType = utils.CHART_TYPE_CURVE chartInfo.Calendar = "公历" chartInfo.SysUserId = adminId chartInfo.SysUserRealName = adminRealName chartInfo.CreateTime = time.Now() chartInfo.ModifyTime = time.Now() chartInfo.Source = chartSource time.Sleep(time.Microsecond) chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10)) newChart.ChartInfo = chartInfo // chart_edb_mapping中edb_info_id为标的ID edbMapping := new(data_manage.ChartEdbMapping) //edbMapping.EdbInfoId = indexId //edbMapping.UniqueCode = utils.MD5(fmt.Sprint(utils.CHART_PREFIX, "_", indexId, "_", strconv.FormatInt(time.Now().UnixNano(), 10))) edbMapping.Source = chartSource edbMapping.CreateTime = time.Now().Local() edbMapping.ModifyTime = time.Now().Local() newChart.EdbMappings = append(newChart.EdbMappings, edbMapping) charts = append(charts, newChart) } return } // FixAiPredictCharts 修复AI预测模型图表 func FixAiPredictCharts() { var err error defer func() { if err != nil { fmt.Println(err) } fmt.Println("修复完成") }() fmt.Println("开始修复") indexOb := new(aiPredictModel.AiPredictModelIndex) indexes, e := indexOb.GetItemsByCondition("", make([]interface{}, 0), []string{}, "") if e != nil { err = fmt.Errorf("获取所有标的失败, %v", e) return } // 日度/月度图表 frequencyArr := []int{aiPredictModel.ModelDataSourceMonthly, aiPredictModel.ModelDataSourceDaily} sourceMapping := map[int]int{ aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY, aiPredictModel.ModelDataSourceDaily: utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY, } suffixNameMapping := map[int]string{ aiPredictModel.ModelDataSourceMonthly: "预测模型/回测", aiPredictModel.ModelDataSourceDaily: "预测模型", } chartOb := new(data_manage.ChartInfo) for _, v := range indexes { for _, fre := range frequencyArr { chartSource := sourceMapping[fre] item, e := data_manage.GetAiPredictChartInfoByIndexId(chartSource, v.AiPredictModelIndexId) if e != nil && !utils.IsErrNoRow(e) { err = fmt.Errorf("获取AI预测模型图表失败, %v", e) return } // 由于标的名称是固定的所以chart_info没有什么可更新的, 已加入过就忽略 if item != nil && item.ChartInfoId > 0 { fmt.Printf("标的%d-%d图表已存在, continue\n", v.AiPredictModelIndexId, chartSource) continue } // 新增图表 chartName := fmt.Sprintf("%s%s", v.IndexName, suffixNameMapping[fre]) chartInfo := new(data_manage.ChartInfo) chartInfo.ChartName = chartName chartInfo.ChartNameEn = chartName chartInfo.ChartType = utils.CHART_TYPE_CURVE chartInfo.Calendar = "公历" chartInfo.SysUserId = v.SysUserId chartInfo.SysUserRealName = v.SysUserRealName chartInfo.CreateTime = time.Now() chartInfo.ModifyTime = time.Now() chartInfo.Source = chartSource time.Sleep(time.Microsecond) chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10)) // chart_edb_mapping中edb_info_id为标的ID mappings := make([]*data_manage.ChartEdbMapping, 0) edbMapping := new(data_manage.ChartEdbMapping) edbMapping.EdbInfoId = v.AiPredictModelIndexId edbMapping.UniqueCode = utils.MD5(fmt.Sprint(utils.CHART_PREFIX, "_", v.AiPredictModelIndexId, "_", strconv.FormatInt(time.Now().UnixNano(), 10))) edbMapping.Source = chartSource edbMapping.CreateTime = time.Now().Local() edbMapping.ModifyTime = time.Now().Local() mappings = append(mappings, edbMapping) // 新增图表 if e = chartOb.AddChartInfoAndEdbMappings(chartInfo, mappings); e != nil { err = fmt.Errorf("新增图表及mapping失败, %v", e) return } // 写入ES if chartInfo.ChartInfoId <= 0 { err = fmt.Errorf("图表ID有误") return } go data.EsAddOrEditChartInfo(chartInfo.ChartInfoId) } } return }