|
@@ -0,0 +1,221 @@
|
|
|
+package services
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ aiPredictModel "eta/eta_mobile/models/ai_predict_model"
|
|
|
+ "eta/eta_mobile/models/data_manage"
|
|
|
+ "eta/eta_mobile/services/data"
|
|
|
+ "eta/eta_mobile/utils"
|
|
|
+ "fmt"
|
|
|
+ "sort"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+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 && e.Error() != utils.ErrNoRow() {
|
|
|
+ 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
|
|
|
+}
|