package future_good import ( "errors" "eta/eta_api/models/data_manage" future_good2 "eta/eta_api/models/data_manage/future_good" "eta/eta_api/services/alarm_msg" "eta/eta_api/services/data" "eta/eta_api/utils" "fmt" "github.com/shopspring/decimal" "sort" "strconv" "time" ) // GetChartEdbData 获取图表的指标数据 func GetChartEdbData(chartInfoId int, startDate, endDate string, baseEdbInfoMapping *data_manage.ChartEdbInfoMapping, edbInfoMappingList []*data_manage.ChartEdbInfoMapping, futureGoodEdbInfoMapping *data_manage.ChartEdbInfoMapping, barChartInfoConf data_manage.FutureGoodBarChartInfoReq, needData bool) (barConfigEdbInfoIdList []data_manage.BarChartInfoEdbItemReq, edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, xDataList []data_manage.XData, yDataList []data_manage.YData, err error) { edbList = make([]*data_manage.ChartEdbInfoMapping, 0) barChartInfoDateList := barChartInfoConf.DateList if futureGoodEdbInfoMapping == nil { err = errors.New("商品指标未选取") return } if len(edbInfoMappingList) == 0 { err = errors.New("ETA指标未选取") return } // 指标对应的所有数据 edbDataListMap := make(map[int][]*data_manage.EdbDataList) // todo item //item := new(data_manage.ChartEdbInfoMapping) if futureGoodEdbInfoMapping.Unit == `无` { futureGoodEdbInfoMapping.Unit = `` } if chartInfoId <= 0 { for k, edbInfoMapping := range edbInfoMappingList { edbInfoMapping.FrequencyEn = data.GetFrequencyEn(edbInfoMapping.Frequency) if edbInfoMapping.Unit == `无` { edbInfoMapping.Unit = `` } edbInfoMapping.IsAxis = 1 edbInfoMapping.LeadValue = 0 edbInfoMapping.LeadUnit = "" edbInfoMapping.ChartEdbMappingId = 0 edbInfoMapping.ChartInfoId = 0 edbInfoMapping.IsOrder = false edbInfoMapping.EdbInfoType = 1 edbInfoMapping.ChartStyle = "" edbInfoMapping.ChartColor = "" edbInfoMapping.ChartWidth = 0 edbInfoMappingList[k] = edbInfoMapping } futureGoodEdbInfoMapping.IsAxis = 1 futureGoodEdbInfoMapping.LeadValue = 0 futureGoodEdbInfoMapping.LeadUnit = "" futureGoodEdbInfoMapping.ChartEdbMappingId = 0 futureGoodEdbInfoMapping.ChartInfoId = 0 futureGoodEdbInfoMapping.IsOrder = false futureGoodEdbInfoMapping.EdbInfoType = 1 futureGoodEdbInfoMapping.ChartStyle = "" futureGoodEdbInfoMapping.ChartColor = "" futureGoodEdbInfoMapping.ChartWidth = 0 } else { for k, edbInfoMapping := range edbInfoMappingList { edbInfoMapping.FrequencyEn = data.GetFrequencyEn(edbInfoMapping.Frequency) if edbInfoMapping.Unit == `无` { edbInfoMapping.Unit = `` } edbInfoMapping.LeadUnitEn = data.GetLeadUnitEn(edbInfoMapping.LeadUnit) edbInfoMappingList[k] = edbInfoMapping } futureGoodEdbInfoMapping.LeadUnitEn = data.GetLeadUnitEn(futureGoodEdbInfoMapping.LeadUnit) } //查询横轴配置项 xDataItemMap := make(map[int]data_manage.XData) for k, v := range barChartInfoConf.XDataList { xDataItemMap[k] = v } // 普通的指标数据 { edbList = edbInfoMappingList for k, edbInfoMapping := range edbInfoMappingList { tmp := data_manage.BarChartInfoEdbItemReq{ EdbInfoId: edbInfoMapping.EdbInfoId, Name: edbInfoMapping.EdbName, NameEn: edbInfoMapping.EdbNameEn, Source: edbInfoMapping.Source, } // 如果有配置,则用配置中的指标名称替换 xItem, ok := xDataItemMap[k] if ok && xItem.Name != "" { tmp.Name = xItem.Name tmp.NameEn = xItem.NameEn tmp.IsHide = xItem.IsHide } barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, tmp) } } // 获取主力合约和最新日期 var zlFutureGoodEdbInfo *future_good2.FutureGoodEdbInfo var latestDate string // 最新日期是这个 var regionType string // 交易所来源:“国内”,“海外” var futureGoodEdbType int { // 寻找主力合约 zlFutureGoodEdbInfo, err = future_good2.GetFutureGoodEdbInfo(futureGoodEdbInfoMapping.EdbInfoId) if err != nil { err = fmt.Errorf("查不到期货指标,GetFutureGoodEdbInfo err: %v", err) return } regionType = zlFutureGoodEdbInfo.RegionType futureGoodEdbType = zlFutureGoodEdbInfo.FutureGoodEdbType // 如果当前合约配置的 "画图时,日期来源的指标id" 并不是自己的话,那么就去查找对应配置的合约 if zlFutureGoodEdbInfo.DateSourceId != zlFutureGoodEdbInfo.FutureGoodEdbInfoId { sourceDateFutureGoodEdbInfo, tmpErr := future_good2.GetFutureGoodEdbInfo(zlFutureGoodEdbInfo.DateSourceId) if tmpErr != nil { err = fmt.Errorf("获取期货指标 %d 的日期来源的指标信息失败,错误:%s", zlFutureGoodEdbInfo.DateSourceId, tmpErr.Error()) return } latestDate = sourceDateFutureGoodEdbInfo.EndDate // 最新日期是这个 } else { latestDate = zlFutureGoodEdbInfo.EndDate // 最新日期是这个 } if latestDate == `0000-00-00` { err = errors.New("日期异常") return } } // 获取期货指标以及期货数据 tmpFutureGoodEdbInfoList, err := future_good2.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId) if err != nil { return } latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local) _, futureGoodEdbInfoList, err := getFutureGoodEdbInfoList(latestDateTime, tmpFutureGoodEdbInfoList, barChartInfoDateList) if err != nil { err = fmt.Errorf("获取期货指标列表失败,getFutureGoodEdbInfoList 错误:%s", err.Error()) return } futureGoodMappingList := make([]*data_manage.ChartEdbInfoMapping, 0) for k, v := range futureGoodEdbInfoList { newMappingInfo := &data_manage.ChartEdbInfoMapping{ EdbInfoId: v.FutureGoodEdbInfoId, SourceName: v.Exchange, Source: 0, EdbCode: v.FutureGoodEdbCode, EdbName: v.FutureGoodEdbName, EdbAliasName: v.FutureGoodEdbName, EdbNameEn: v.FutureGoodEdbNameEn, EdbType: baseEdbInfoMapping.EdbType, Frequency: baseEdbInfoMapping.Frequency, FrequencyEn: baseEdbInfoMapping.FrequencyEn, Unit: baseEdbInfoMapping.Unit, UnitEn: baseEdbInfoMapping.UnitEn, StartDate: v.StartDate, EndDate: v.EndDate, ModifyTime: v.ModifyTime.Format(utils.FormatDateTime), ChartEdbMappingId: v.FutureGoodEdbInfoId, ChartInfoId: baseEdbInfoMapping.ChartInfoId, MaxData: v.MaxValue, MinData: v.MinValue, IsOrder: baseEdbInfoMapping.IsOrder, IsAxis: baseEdbInfoMapping.IsAxis, EdbInfoType: baseEdbInfoMapping.EdbInfoType, EdbInfoCategoryType: baseEdbInfoMapping.EdbInfoCategoryType, LeadValue: baseEdbInfoMapping.LeadValue, LeadUnit: baseEdbInfoMapping.LeadUnit, LeadUnitEn: baseEdbInfoMapping.LeadUnitEn, ChartStyle: baseEdbInfoMapping.ChartStyle, ChartColor: baseEdbInfoMapping.ChartColor, PredictChartColor: baseEdbInfoMapping.PredictChartColor, ChartWidth: baseEdbInfoMapping.ChartWidth, ChartType: baseEdbInfoMapping.ChartType, LatestDate: v.LatestDate.Format(utils.FormatDateTime), LatestValue: v.LatestValue, UniqueCode: futureGoodEdbInfoMapping.UniqueCode + strconv.Itoa(k), MinValue: v.MinValue, MaxValue: v.MaxValue, DataList: nil, IsNullData: false, } futureGoodMappingList = append(futureGoodMappingList, newMappingInfo) tmp := data_manage.BarChartInfoEdbItemReq{ EdbInfoId: newMappingInfo.EdbInfoId, Name: fmt.Sprint("M+", v.Month), NameEn: fmt.Sprint("M+", v.Month), Source: newMappingInfo.Source, } // 判断如果有配置,需要替换为配置内容 xItem, ok := xDataItemMap[k] if ok && xItem.Name != "" { tmp.Name = xItem.Name tmp.NameEn = xItem.NameEn tmp.IsHide = xItem.IsHide } barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, tmp) } if regionType == `海外` { zlFutureGoodEdbMapping := &data_manage.ChartEdbInfoMapping{ EdbInfoId: zlFutureGoodEdbInfo.FutureGoodEdbInfoId, SourceName: zlFutureGoodEdbInfo.Exchange, Source: 0, EdbCode: zlFutureGoodEdbInfo.FutureGoodEdbCode, EdbName: zlFutureGoodEdbInfo.FutureGoodEdbName, EdbAliasName: zlFutureGoodEdbInfo.FutureGoodEdbName, EdbNameEn: zlFutureGoodEdbInfo.FutureGoodEdbNameEn, EdbType: baseEdbInfoMapping.EdbType, Frequency: baseEdbInfoMapping.Frequency, FrequencyEn: baseEdbInfoMapping.FrequencyEn, Unit: baseEdbInfoMapping.Unit, UnitEn: baseEdbInfoMapping.UnitEn, StartDate: zlFutureGoodEdbInfo.StartDate, EndDate: zlFutureGoodEdbInfo.EndDate, ModifyTime: zlFutureGoodEdbInfo.ModifyTime.Format(utils.FormatDateTime), ChartEdbMappingId: zlFutureGoodEdbInfo.FutureGoodEdbInfoId, ChartInfoId: baseEdbInfoMapping.ChartInfoId, MaxData: zlFutureGoodEdbInfo.MaxValue, MinData: zlFutureGoodEdbInfo.MinValue, IsOrder: baseEdbInfoMapping.IsOrder, IsAxis: baseEdbInfoMapping.IsAxis, EdbInfoType: baseEdbInfoMapping.EdbInfoType, EdbInfoCategoryType: baseEdbInfoMapping.EdbInfoCategoryType, LeadValue: baseEdbInfoMapping.LeadValue, LeadUnit: baseEdbInfoMapping.LeadUnit, LeadUnitEn: baseEdbInfoMapping.LeadUnitEn, ChartStyle: baseEdbInfoMapping.ChartStyle, ChartColor: baseEdbInfoMapping.ChartColor, PredictChartColor: baseEdbInfoMapping.PredictChartColor, ChartWidth: baseEdbInfoMapping.ChartWidth, ChartType: baseEdbInfoMapping.ChartType, LatestDate: zlFutureGoodEdbInfo.LatestDate.Format(utils.FormatDateTime), LatestValue: zlFutureGoodEdbInfo.LatestValue, UniqueCode: futureGoodEdbInfoMapping.UniqueCode + strconv.Itoa(0), MinValue: zlFutureGoodEdbInfo.MinValue, MaxValue: zlFutureGoodEdbInfo.MaxValue, DataList: nil, IsNullData: false, } edbList = append(edbList, zlFutureGoodEdbMapping) edbList = append(edbList, futureGoodMappingList...) } else { edbList = append(edbList, futureGoodMappingList...) } if !needData { return } // 获取数据 // 现货数据 for _, edbInfoMapping := range edbInfoMappingList { dataList := make([]*data_manage.EdbDataList, 0) dataList, err = data_manage.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.SubSource, edbInfoMapping.EdbInfoId, startDate, endDate) if err != nil { return } edbDataListMap[edbInfoMapping.EdbInfoId] = dataList // todo item //item.DataList = dataList } futureEdbInfoIds := make([]int, 0) for _, v := range futureGoodMappingList { futureEdbInfoIds = append(futureEdbInfoIds, v.EdbInfoId) } tmpDataListMap := make(map[int][]*future_good2.FutureGoodEdbData) if len(futureEdbInfoIds) > 0 { // 期货数据 tmpDataList, tmpErr := future_good2.GetFutureGoodEdbDataListByIdsAndDate(futureEdbInfoIds, startDate, endDate) if tmpErr != nil { err = tmpErr return } for _, v := range tmpDataList { if _, ok := tmpDataListMap[v.FutureGoodEdbInfoId]; !ok { tmpDataListMap[v.FutureGoodEdbInfoId] = make([]*future_good2.FutureGoodEdbData, 0) } tmpDataListMap[v.FutureGoodEdbInfoId] = append(tmpDataListMap[v.FutureGoodEdbInfoId], v) } } for _, v := range futureGoodMappingList { dataList := make([]*data_manage.EdbDataList, 0) tmpDataList, ok := tmpDataListMap[v.EdbInfoId] if !ok { /*err = fmt.Errorf("期货数据不存在 FutureGoodEdbInfoId: %d", v.EdbInfoId) return*/ continue } for _, tmpData := range tmpDataList { dataList = append(dataList, &data_manage.EdbDataList{ EdbDataId: tmpData.FutureGoodEdbDataId, EdbInfoId: tmpData.FutureGoodEdbInfoId, DataTime: tmpData.DataTime.Format(utils.FormatDate), DataTimestamp: tmpData.DataTimestamp, Value: tmpData.Close, }) } edbDataListMap[v.EdbInfoId] = dataList v.DataList = dataList } xEdbIdValue, yDataList, err = BarChartData(baseEdbInfoMapping, edbInfoMappingList, futureGoodEdbInfoList, edbDataListMap, barChartInfoDateList, regionType, baseEdbInfoMapping.EndDate) if len(barChartInfoConf.XDataList) > 0 { xDataList = barChartInfoConf.XDataList } else { for _, v := range edbInfoMappingList { xDataList = append(xDataList, data_manage.XData{ Name: v.EdbName, NameEn: v.EdbNameEn, IsHide: 0, }) } } //yDataList =make([]data_manage.YData,0) //data_manage.YData{ // Date: "", // Color: "", // Name: "", // NameEn: "", // Value: nil, // NoDataEdbList: nil, // XEdbInfoIdList: nil, //} futureGoodEdbInfoIndexMap := make(map[int]int) for index, v := range futureGoodEdbInfoList { futureGoodEdbInfoIndexMap[v.FutureGoodEdbInfoId] = index } nMap := make(map[int]int) maxIndex := 0 // 最大x轴的下标 for k, tmpYData := range yDataList { yDataMap := tmpYData.EdbValMap edbInfoIdList := make([]int, 0) noDataEdbInfoIdList := make([]int, 0) valueList := make([]float64, 0) noDataEdbIdMap := make(map[int]int) // 所有的N值 for _, n := range tmpYData.M { nMap[n] = n } // 基础指标 baseEdbIds := make([]int, 0) for _, tmp := range edbInfoMappingList { edbInfoIdList = append(edbInfoIdList, tmp.EdbInfoId) baseEdbIds = append(baseEdbIds, tmp.EdbInfoId) tmpVal, ok := yDataMap[tmp.EdbInfoId] valueList = append(valueList, tmpVal) if !ok || tmpVal == 0 { noDataEdbInfoIdList = append(noDataEdbInfoIdList, tmp.EdbInfoId) noDataEdbIdMap[tmp.EdbInfoId] = tmp.EdbInfoId } } for _, futureGoodEdbInfo := range futureGoodEdbInfoList { tmpEdbInfId := futureGoodEdbInfo.FutureGoodEdbInfoId edbInfoIdList = append(edbInfoIdList, tmpEdbInfId) tmpVal, ok := yDataMap[tmpEdbInfId] valueList = append(valueList, tmpVal) if !ok || tmpVal == 0 { noDataEdbInfoIdList = append(noDataEdbInfoIdList, tmpEdbInfId) noDataEdbIdMap[tmpEdbInfId] = tmpEdbInfId } } //tmpYData.Value = valueList tmpYData.NoDataEdbList = noDataEdbInfoIdList yDataList[k] = tmpYData lenEdbId := len(edbInfoIdList) tmpMaxIndex := lenEdbId - 1 // 当前数据的最大x轴的下标 for i := lenEdbId - 1; i >= 0; i-- { // 如果没有在无数据的指标列表中找到,那么就找到了最大x轴的下标 if _, ok := noDataEdbIdMap[edbInfoIdList[i]]; !ok || utils.InArrayByInt(baseEdbIds, edbInfoIdList[i]) { //以往的逻辑是碰到第一个无数据的期货指标,那后续的月份都是无数据的,因此需要特殊处理,改成多个现货指标之后需要排除无值的现货指标 // 如果最大x轴的下标 小于 当前下标,那么就重新赋值, if maxIndex < i-1 { maxIndex = i - 1 } break } tmpMaxIndex = i - 1 } // 如果最大x轴的下标 小于 当前下标,那么就重新赋值 if maxIndex < tmpMaxIndex { maxIndex = tmpMaxIndex } } //xEdbIdValue = xEdbIdValue[0:maxIndex] // 找出所有的N值,并进行正序排列 nList := make([]int, 0) for _, n := range nMap { nList = append(nList, n) } sort.Slice(nList, func(i, j int) bool { return nList[i] < nList[j] }) for k, v := range yDataList { if len(v.XEdbInfoIdList) >= maxIndex+1 { yDataList[k].XEdbInfoIdList = v.XEdbInfoIdList[0 : maxIndex+1] } if len(v.Value) >= maxIndex+1 { yDataList[k].Value = v.Value[0 : maxIndex+1] } } baseEdbLen := len(edbInfoMappingList) tmpXDataList, newYDataList, err := handleResultData(regionType, futureGoodEdbType, baseEdbLen, yDataList, futureGoodEdbInfoList, maxIndex) if err != nil { return } if len(barChartInfoConf.XDataList) == 0 { xDataList = append(xDataList, tmpXDataList...) } yDataList = newYDataList return } // BarChartData 获取数据 func BarChartData(baseEdbInfoMapping *data_manage.ChartEdbInfoMapping, edbInfoMappingList []*data_manage.ChartEdbInfoMapping, futureGoodMappingList []*future_good2.FutureGoodEdbInfo, edbDataListMap map[int][]*data_manage.EdbDataList, barChartInfoDateList []data_manage.BarChartInfoDateReq, regionType, latestDate string) (edbIdList []int, yDataList []data_manage.YData, err error) { // 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3}) // 现货指标数据map baseEdbDataMap := make(map[int]map[string]float64) edbInfoMappingMap := make(map[int]struct{}) for _, v := range edbInfoMappingList { edbInfoMappingMap[v.EdbInfoId] = struct{}{} } for edbInfoId, edbDataList := range edbDataListMap { if _, ok1 := edbInfoMappingMap[edbInfoId]; ok1 { edbDateData := make(map[string]float64) for _, edbData := range edbDataList { edbDateData[edbData.DataTime] = edbData.Value } baseEdbDataMap[edbInfoId] = edbDateData } } edbDataMap := make(map[int]map[string]float64) for edbInfoId, edbDataList := range edbDataListMap { if _, ok := edbInfoMappingMap[edbInfoId]; ok { continue } edbDateData := make(map[string]float64) for _, edbData := range edbDataList { edbDateData[edbData.DataTime] = edbData.Value } edbDataMap[edbInfoId] = edbDateData } // edbIdList 指标展示顺序;x轴的指标顺序 edbIdList = make([]int, 0) for _, v := range edbInfoMappingList { edbIdList = append(edbIdList, v.EdbInfoId) } for _, v := range futureGoodMappingList { edbIdList = append(edbIdList, v.FutureGoodEdbInfoId) } latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local) yDataList = make([]data_manage.YData, 0) //y轴的数据列表 for _, barChartInfoDate := range barChartInfoDateList { yDataMap := make(map[int]float64) var maxDate time.Time var findDateTime time.Time switch barChartInfoDate.Type { case 1: //最新值 findDateTime = latestDateTime case 2: //近期几天 findDateTime = latestDateTime.AddDate(0, 0, -barChartInfoDate.Value) case 3: // 固定日期 //寻找固定日期的数据 tmpFindDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local) if tmpErr != nil { err = tmpErr return } findDateTime = tmpFindDateTime default: err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type)) return } if findDateTime.IsZero() { err = errors.New("错误的日期") return } findDataList := make([]float64, 0) // 当前日期的数据值 noDataIdList := make([]int, 0) // 没有数据的指标id noDataIdMap := make(map[int]int, 0) // 没有数据的指标map xEdbInfoIdList := make([]int, 0) // 当前数据的指标id列表 // 先找到基准日期 var realDateTime time.Time realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[baseEdbInfoMapping.EdbInfoId], baseEdbDataMap[baseEdbInfoMapping.EdbInfoId], edbDataMap) if tmpErr != nil { err = tmpErr return } // 处理其余现货指标 for _, v := range edbInfoMappingList { if v.EdbInfoId == baseEdbInfoMapping.EdbInfoId { findDataList = append(findDataList, findDataValue) yDataMap[baseEdbInfoMapping.EdbInfoId] = findDataValue if isFind { maxDate = realDateTime } else { noDataIdList = append(noDataIdList, baseEdbInfoMapping.EdbInfoId) noDataIdMap[baseEdbInfoMapping.EdbInfoId] = baseEdbInfoMapping.EdbInfoId } xEdbInfoIdList = append(xEdbInfoIdList, v.EdbInfoId) continue } findDataValueTmp, isFindTmp := baseEdbDataMap[v.EdbInfoId][realDateTime.Format(utils.FormatDate)] findDataList = append(findDataList, findDataValueTmp) yDataMap[v.EdbInfoId] = findDataValueTmp if !isFindTmp { noDataIdList = append(noDataIdList, v.EdbInfoId) noDataIdMap[v.EdbInfoId] = v.EdbInfoId } xEdbInfoIdList = append(xEdbInfoIdList, v.EdbInfoId) } //currMonth := findDateTime.Month() // 当前月份 //currYear := findDateTime.Year() // 当前年份 // 用实际日期的月份作为基准,往前推12个月(2024-5-13 16:26:43修改) currMonth := realDateTime.Month() // 当前月份 currYear := realDateTime.Year() // 当前年份 mList := make([]int, 0) // 间隔月份 indexList := make([]int, 0) if regionType == `国内` { for i := currMonth + 1; i <= 12; i++ { indexList = append(indexList, int(i)) mList = append(mList, int(i-currMonth)) } for i := 1; i < int(currMonth); i++ { indexList = append(indexList, i) mList = append(mList, 12+i-int(currMonth)) } } else { for i, v := range futureGoodMappingList { if v.FutureGoodEdbType == 2 { if i == 0 { continue } indexList = append(indexList, i) mList = append(mList, v.Month) } else { if v.Year > currYear || (v.Year == currYear && v.Month > int(currMonth)) { indexList = append(indexList, i) mList = append(mList, (v.Year-currYear)*12+v.Month-int(currMonth)) } } } } for _, i := range indexList { futureGoodMapping := futureGoodMappingList[i] // 当前的期货指标 //tmpRealDateTime, tmpFindDataValue, tmpIsFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[futureGoodMapping.FutureGoodEdbInfoId], edbDataMap[futureGoodMapping.FutureGoodEdbInfoId]) //if tmpErr != nil { // err = tmpErr // return //} //tmpRealDateTime := findDateTime // 按照配置找到的日期 tmpRealDateTime := realDateTime // 实际现货的日期 tmpFindDataValue, tmpIsFind := edbDataMap[futureGoodMapping.FutureGoodEdbInfoId][tmpRealDateTime.Format(utils.FormatDate)] yDataMap[futureGoodMapping.FutureGoodEdbInfoId] = tmpFindDataValue findDataList = append(findDataList, tmpFindDataValue) if tmpIsFind { if maxDate.IsZero() || maxDate.Before(tmpRealDateTime) { maxDate = tmpRealDateTime } } else { noDataIdList = append(noDataIdList, futureGoodMapping.FutureGoodEdbInfoId) noDataIdMap[futureGoodMapping.FutureGoodEdbInfoId] = futureGoodMapping.FutureGoodEdbInfoId } // 当前期货合约的指标 xEdbInfoIdList = append(xEdbInfoIdList, futureGoodMapping.FutureGoodEdbInfoId) } yName := barChartInfoDate.Name yNameEn := barChartInfoDate.Name if yName == `` { if barChartInfoDate.Type == 2 { yName = strconv.Itoa(barChartInfoDate.Value) + "天前" if barChartInfoDate.Value == 1 { yNameEn = strconv.Itoa(barChartInfoDate.Value) + "day ago" } else { yNameEn = strconv.Itoa(barChartInfoDate.Value) + " days ago" } } else { yName = maxDate.Format(utils.FormatDate) yNameEn = maxDate.Format(utils.FormatDate) } } yDate := "0000-00-00" if !maxDate.IsZero() { yDate = maxDate.Format(utils.FormatDate) } // 数据处理,将没有数据的下标,赋值平均值 { hasDataIndexList := make([]int, 0) for dataK, edbInfoId := range xEdbInfoIdList { if _, ok := noDataIdMap[edbInfoId]; !ok { // 如果是没有数据的指标id hasDataIndexList = append(hasDataIndexList, dataK) } } lenHasDataIndex := len(hasDataIndexList) if lenHasDataIndex > 0 { for lenHasDataI := 1; lenHasDataI < lenHasDataIndex; lenHasDataI++ { perK := hasDataIndexList[lenHasDataI-1] //上一个有数据的指标下标 currK := hasDataIndexList[lenHasDataI] //当前有数据的指标下标 preVal := findDataList[perK] //上一个有数据的坐标的值 currVal := findDataList[currK] //当前有数据的指标的值 // 环差值 hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(currK - perK))) var tmpI int64 // 将两个中间的数据做平均值补全 for hcI := perK + 1; hcI < currK; hcI++ { tmpI++ findDataList[hcI], _ = decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(tmpI))).RoundCeil(4).Float64() } } } } yDataList = append(yDataList, data_manage.YData{ Date: yDate, ConfigDate: realDateTime, Value: findDataList, NoDataEdbList: noDataIdList, XEdbInfoIdList: xEdbInfoIdList, Color: barChartInfoDate.Color, Name: yName, NameEn: yNameEn, EdbValMap: yDataMap, M: mList, }) } return } // handleResultData 处理成最终的结果数据 func handleResultData(regionType string, futureGoodEdbType, baseEdbLen int, yDataList []data_manage.YData, futureGoodEdbInfoList []*future_good2.FutureGoodEdbInfo, maxIndex int) (xDataList []data_manage.XData, newYDataList []data_manage.YData, err error) { xDataList = make([]data_manage.XData, 0) newYDataList = yDataList if regionType == `国内` { for i := 1; i < 12; i++ { if i > maxIndex { break } xDataList = append(xDataList, data_manage.XData{ Name: fmt.Sprint("M+", i), NameEn: fmt.Sprint("M+", i), }) } return } futureGoodEdbInfoMap := make(map[int]*future_good2.FutureGoodEdbInfo) for _, v := range futureGoodEdbInfoList { futureGoodEdbInfoMap[v.FutureGoodEdbInfoId] = v } if futureGoodEdbType == 2 { // FutureGoodEdbType int `description:"指标类型,1:年月是固定的合约;2:只有M+N期的合约,未固定年月"` nList := []int{3, 15, 27} for _, i := range nList { xDataList = append(xDataList, data_manage.XData{ Name: fmt.Sprint("M+", i), NameEn: fmt.Sprint("M+", i), }) } for yIndex, yData := range yDataList { newYDataList[yIndex].XEdbInfoIdList = []int{} newYDataList[yIndex].Value = []float64{} tmpNList := nList //当前的主力合约 newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, yData.XEdbInfoIdList[0:baseEdbLen]...) newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[0:baseEdbLen]...) xEdbInfoIdList := yData.XEdbInfoIdList[baseEdbLen:] valIndex := baseEdbLen needNum := 0 for _, n := range tmpNList { if len(xEdbInfoIdList) > 0 { edbInfoId := xEdbInfoIdList[0] futureGoodEdbInfo, ok := futureGoodEdbInfoMap[edbInfoId] if !ok { err = errors.New("找不到指标") return } // 当前距离最早的日期相差的N数 if futureGoodEdbInfo.Month == n { if needNum > 0 { currVal := yData.Value[valIndex] preVal := yData.Value[valIndex-1] hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(needNum + 1))) for tmpNum := 0; tmpNum < needNum; tmpNum++ { newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, 0) // 赋值平均值 tmpVal, _ := decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(int64(tmpNum + 1)))).RoundCeil(4).Float64() newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, tmpVal) } } newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, edbInfoId) newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[valIndex]) valIndex++ needNum = 0 if len(xEdbInfoIdList) > 0 { xEdbInfoIdList = xEdbInfoIdList[1:] } } else { needNum++ } } } } maxI := 0 for _, yData := range newYDataList { lenEdb := len(yData.XEdbInfoIdList) for i := 0; i < lenEdb; i++ { if yData.XEdbInfoIdList[i] != 0 && !utils.InArrayByInt(yData.NoDataEdbList, yData.XEdbInfoIdList[i]) { if maxI < i { maxI = i } } } } xDataList = xDataList[0:maxI] for yIndex, yData := range newYDataList { if len(yData.XEdbInfoIdList) > maxI+1 { newYDataList[yIndex].XEdbInfoIdList = yData.XEdbInfoIdList[0 : maxI+1] } if len(yData.Value) > maxI+1 { newYDataList[yIndex].Value = yData.Value[0 : maxI+1] } } return } nMap := make(map[int]int) for _, v := range yDataList { findDateTime := v.ConfigDate currMonth := findDateTime.Month() // 当前月份 currYear := findDateTime.Year() // 当前年份 //v.XEdbInfoIdList for edbInfoIndex, edbInfoId := range v.XEdbInfoIdList { // 现货指标不处理 if edbInfoIndex <= baseEdbLen-1 { continue } futureGoodEdbInfo, ok := futureGoodEdbInfoMap[edbInfoId] if !ok { err = errors.New("找不到指标") return } n := (futureGoodEdbInfo.Year-currYear)*12 + futureGoodEdbInfo.Month - int(currMonth) nMap[n] = n } } // 找出所有的N值,并进行正序排列 nList := make([]int, 0) for _, n := range nMap { nList = append(nList, n) } sort.Slice(nList, func(i, j int) bool { return nList[i] < nList[j] }) //prevMonth := 1 for _, n := range nList { xDataList = append(xDataList, data_manage.XData{ Name: fmt.Sprint("M+", n), NameEn: fmt.Sprint("M+", n), }) } for yIndex, yData := range yDataList { newYDataList[yIndex].XEdbInfoIdList = []int{} newYDataList[yIndex].Value = []float64{} tmpNList := nList //当前的主力合约 newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, yData.XEdbInfoIdList[0:baseEdbLen]...) newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[0:baseEdbLen]...) xEdbInfoIdList := yData.XEdbInfoIdList[baseEdbLen:] currDataTime := yData.ConfigDate valIndex := baseEdbLen needNum := 0 for _, n := range tmpNList { if len(xEdbInfoIdList) > 0 { edbInfoId := xEdbInfoIdList[0] futureGoodEdbInfo, ok := futureGoodEdbInfoMap[edbInfoId] if !ok { err = errors.New("找不到指标") return } // 当前距离最早的日期相差的N数 divMonth := (futureGoodEdbInfo.Year-currDataTime.Year())*12 + (futureGoodEdbInfo.Month - int(currDataTime.Month())) if divMonth == n { if needNum > 0 { currVal := yData.Value[valIndex] preVal := yData.Value[valIndex-1] hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(needNum + 1))) for tmpNum := 0; tmpNum < needNum; tmpNum++ { newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, 0) // 赋值平均值 tmpVal, _ := decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(int64(tmpNum + 1)))).RoundCeil(4).Float64() newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, tmpVal) } } newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, edbInfoId) newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[valIndex]) valIndex++ needNum = 0 if len(xEdbInfoIdList) > 0 { xEdbInfoIdList = xEdbInfoIdList[1:] } } else { needNum++ } } } } maxI := 0 for _, yData := range newYDataList { lenEdb := len(yData.XEdbInfoIdList) for i := 0; i < lenEdb; i++ { if yData.XEdbInfoIdList[i] != 0 && !utils.InArrayByInt(yData.NoDataEdbList, yData.XEdbInfoIdList[i]) { if maxI < i { maxI = i } } } } xDataList = xDataList[0:maxI] for yIndex, yData := range newYDataList { if len(yData.XEdbInfoIdList) > maxI+1 { newYDataList[yIndex].XEdbInfoIdList = yData.XEdbInfoIdList[0 : maxI+1] } if len(yData.Value) > maxI+1 { newYDataList[yIndex].Value = yData.Value[0 : maxI+1] } } return } // getFutureGoodEdbInfoList 获取适用的指标列表 func getFutureGoodEdbInfoList(latestDateTime time.Time, tmpFutureGoodEdbInfoList []*future_good2.FutureGoodEdbInfo, barChartInfoDateList []data_manage.BarChartInfoDateReq) (earliestDateTime time.Time, futureGoodEdbInfoList []*future_good2.FutureGoodEdbInfo, err error) { maxM := 36 //最大36期合约 futureGoodEdbInfoList = make([]*future_good2.FutureGoodEdbInfo, 0) earliestDateTime = latestDateTime // 数据的最早日期,目的是为了找出最早的合约 for _, barChartInfoDate := range barChartInfoDateList { var findDateTime time.Time switch barChartInfoDate.Type { case 1: //最新值 findDateTime = latestDateTime case 2: //近期几天 findDateTime = latestDateTime.AddDate(0, 0, -barChartInfoDate.Value) case 3: // 固定日期 //寻找固定日期的数据 tmpFindDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local) if tmpErr != nil { err = tmpErr return } findDateTime = tmpFindDateTime default: err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type)) return } if findDateTime.IsZero() { err = errors.New("错误的日期") return } if findDateTime.Before(earliestDateTime) { earliestDateTime = findDateTime } } for _, v := range tmpFutureGoodEdbInfoList { if v.RegionType == `国内` { futureGoodEdbInfoList = append(futureGoodEdbInfoList, v) continue } //海外的连续日期,目前 if v.FutureGoodEdbType == 2 { if v.Month <= maxM { //addMonth := int(earliestDateTime.Month()) + v.Month //v.Year = earliestDateTime.Year() + addMonth/12 //realMonth := addMonth % 12 //if realMonth == 0 { // realMonth = 12 //} //v.Month = realMonth futureGoodEdbInfoList = append(futureGoodEdbInfoList, v) } continue } if v.Year < earliestDateTime.Year() { continue } // 小于等于当前年,那么就肯定是ok的 if v.Year <= earliestDateTime.Year() { futureGoodEdbInfoList = append(futureGoodEdbInfoList, v) continue } // 如果(当前年-最新日期的年份) * 12个月 + (当前月-最新日期的月份) 小于总月份 if (v.Year-earliestDateTime.Year())*12+(v.Month-int(earliestDateTime.Month())) <= maxM { futureGoodEdbInfoList = append(futureGoodEdbInfoList, v) continue } } return } // GetNeedDateData 获取合约内需要的日期数据 func GetNeedDateData(needDateTime time.Time, dataList []*data_manage.EdbDataList, edbDataMap map[string]float64, allEdbDataMap map[int]map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) { //dataList := edbDataListMap[edbInfoId] //指标的所有数据值 if len(dataList) <= 0 { // 没有数据的指标id return } //最早的日期 minDateTime, err := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local) if err != nil { return } // 该日期存在数据的期货指标的最小数量,目前是现货和期货各1个,总共2个 maxCount := 1 for tmpDateTime := needDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) { tmpDate := tmpDateTime.Format(utils.FormatDate) tmpValue, ok := edbDataMap[tmpDate] if !ok { continue } // 该日期存在数据的指标数量 count := 0 for _, currEdbDataMap := range allEdbDataMap { _, tmpIsFind := currEdbDataMap[tmpDate] if tmpIsFind { count++ if count >= maxCount { continue } } } // 该日期存在数据的期货指标数量小于2个,那么要继续往前找 if count < maxCount { continue } //如果能找到数据,那么就返回 // 数据为0,也直接返回,做无值处理 if tmpValue == 0 { return } findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local) findDataValue = tmpValue isFind = true return } return } // FutureGoodChartInfoRefresh // @author Roc // @datetime 2023-2-2 18:44:46 // @description 商品价格曲线图表刷新 func FutureGoodChartInfoRefresh(chartInfoId int) (err error) { var errMsg string defer func() { if err != nil { go alarm_msg.SendAlarmMsg("ChartInfoRefresh:"+errMsg, 3) fmt.Println("ChartInfoRefresh Err:" + errMsg) } }() edbInfoMappingList, err := data_manage.GetEtaEdbChartEdbMappingList(chartInfoId) if err != nil { errMsg = "获取需要刷新的ETA指标失败:Err:" + err.Error() return } edbInfoIds := make([]int, 0) for _, edbInfoMapping := range edbInfoMappingList { edbInfoIds = append(edbInfoIds, edbInfoMapping.EdbInfoId) } // 获取期货指标 futureGoodEdbInfoMapping, err := data_manage.GetFutureGoodEdbChartEdbMapping(chartInfoId) if err != nil { errMsg = "获取需要刷新的商品期货指标失败:Err:" + err.Error() return } // 获取期货指标以及期货数据 futureGoodEdbInfoList, err := future_good2.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId) if err != nil { return } // 批量刷新ETA指标 err, _ = data.EdbInfoRefreshAllFromBaseV3(edbInfoIds, false, true, false) if err != nil { return } // 批量刷新期货指标 err = FutureGoodEdbInfoRefreshAllFromBase(futureGoodEdbInfoList, false) if err != nil { return } resp, err := RefreshEdbRelation(chartInfoId) if err != nil { return } if resp.Ret != 200 { err = fmt.Errorf("刷新利润曲线图表数据失败:Err:%s", resp.Msg) return } return }