package future_good import ( "errors" "fmt" "github.com/shopspring/decimal" "hongze/hongze_yb/models/request" "hongze/hongze_yb/models/response/chart_info" chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping" edbDataModel "hongze/hongze_yb/models/tables/edb_data" "hongze/hongze_yb/models/tables/future_good_edb_data" "hongze/hongze_yb/models/tables/future_good_edb_info" "hongze/hongze_yb/services/alarm_msg" "hongze/hongze_yb/services/chart" "hongze/hongze_yb/utils" "strconv" "time" ) // GetChartEdbData 获取图表的指标数据 func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping, futureGoodEdbInfoMapping *chartEdbMappingModel.ChartEdbInfoMappingList, barChartInfoDateList []request.BarChartInfoDateReq) (barConfigEdbInfoIdList []request.BarChartInfoEdbItemReq, edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, xEdbIdValue []int, xDataList []chart_info.XData, yDataList []chart_info.YData, sourceArr []string, err error) { edbList = make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0) sourceArr = make([]string, 0) if futureGoodEdbInfoMapping == nil { err = errors.New("商品指标未选取") return } if edbInfoMapping == nil { err = errors.New("ETA指标未选取") return } // 指标对应的所有数据 edbDataListMap := make(map[int][]*edbDataModel.EdbDataList) item := new(chartEdbMappingModel.ChartEdbInfoMappingList) edbInfoMapping.FrequencyEn = chart.GetFrequencyEn(edbInfoMapping.Frequency) if edbInfoMapping.Unit == `无` { edbInfoMapping.Unit = `` } if futureGoodEdbInfoMapping.Unit == `无` { futureGoodEdbInfoMapping.Unit = `` } if chartInfoId <= 0 { 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 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 { edbInfoMapping.LeadUnitEn = chart.GetLeadUnitEn(edbInfoMapping.LeadUnit) futureGoodEdbInfoMapping.LeadUnitEn = chart.GetLeadUnitEn(futureGoodEdbInfoMapping.LeadUnit) } // 普通的指标数据 { dataList := make([]*edbDataModel.EdbDataList, 0) dataList, err = edbDataModel.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.EdbInfoId, startDate, endDate) edbDataListMap[edbInfoMapping.EdbInfoId] = dataList item.DataList = dataList edbList = append(edbList, edbInfoMapping) barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, request.BarChartInfoEdbItemReq{ EdbInfoId: edbInfoMapping.EdbInfoId, //Name: edbInfoMapping.EdbName, Name: "现货价", NameEn: "Spot Price", Source: edbInfoMapping.Source, }) if !utils.InArray(edbInfoMapping.Source, utils.SystemSourceList) { //来源于系统的指标,都展示为弘则研究 if !utils.InArray(edbInfoMapping.SourceName, sourceArr) { sourceArr = append(sourceArr, edbInfoMapping.SourceName) } } } // 获取主力合约和最新日期 var zlFutureGoodEdbInfo *future_good_edb_info.FutureGoodEdbInfo var latestDate string // 最新日期是这个 var regionType string // 交易所来源:“国内”,“海外” { // 寻找主力合约 zlFutureGoodEdbInfo, err = future_good_edb_info.GetFutureGoodEdbInfo(futureGoodEdbInfoMapping.EdbInfoId) if err != nil { return } regionType = zlFutureGoodEdbInfo.RegionType // 如果当前合约配置的 "画图时,日期来源的指标id" 并不是自己的话,那么就去查找对应配置的合约 if uint64(zlFutureGoodEdbInfo.DateSourceID) != zlFutureGoodEdbInfo.FutureGoodEdbInfoID { sourceDateFutureGoodEdbInfo, tmpErr := future_good_edb_info.GetFutureGoodEdbInfo(int(zlFutureGoodEdbInfo.DateSourceID)) if tmpErr != nil { err = tmpErr return } latestDate = sourceDateFutureGoodEdbInfo.EndDate.Format(utils.FormatDate) // 最新日期是这个 } else { latestDate = zlFutureGoodEdbInfo.EndDate.Format(utils.FormatDate) // 最新日期是这个 } if latestDate == `0000-00-00` { err = errors.New("日期异常") return } } // 获取期货指标以及期货数据 tmpFutureGoodEdbInfoList, err := future_good_edb_info.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId) if err != nil { return } maxM := 36 futureGoodEdbInfoList := make([]*future_good_edb_info.FutureGoodEdbInfo, 0) latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local) for _, v := range tmpFutureGoodEdbInfoList { if v.RegionType == `国内` { futureGoodEdbInfoList = append(futureGoodEdbInfoList, v) continue } //海外的连续日期,目前 if v.FutureGoodEdbType == 2 { if int(v.Month) <= maxM { addMonth := int(latestDateTime.Month()) + int(v.Month) v.Year = latestDateTime.Year() + addMonth/12 realMonth := addMonth % 12 if realMonth == 0 { realMonth = 12 } v.Month = uint32(realMonth) futureGoodEdbInfoList = append(futureGoodEdbInfoList, v) } continue } // 小于等于当前年,那么就肯定是ok的 if v.Year <= latestDateTime.Year() { futureGoodEdbInfoList = append(futureGoodEdbInfoList, v) continue } // 如果(当前年-最新日期的年份) * 12个月 + (当前月-最新日期的月份) 小于总月份 if (v.Year-latestDateTime.Year())*12+(int(v.Month)-int(latestDateTime.Month())) <= maxM { futureGoodEdbInfoList = append(futureGoodEdbInfoList, v) continue } } futureGoodMappingList := make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0) for k, v := range futureGoodEdbInfoList { newMappingInfo := &chartEdbMappingModel.ChartEdbInfoMappingList{ ChartEdbInfoMapping: chartEdbMappingModel.ChartEdbInfoMapping{ EdbInfoId: int(v.FutureGoodEdbInfoID), SourceName: v.Exchange, Source: utils.CHART_SOURCE_FUTURE_GOOD, EdbCode: v.FutureGoodEdbCode, EdbName: v.FutureGoodEdbName, EdbAliasName: v.FutureGoodEdbName, EdbNameEn: v.FutureGoodEdbNameEn, EdbType: edbInfoMapping.EdbType, Frequency: edbInfoMapping.Frequency, FrequencyEn: edbInfoMapping.FrequencyEn, Unit: edbInfoMapping.Unit, UnitEn: edbInfoMapping.UnitEn, StartDate: v.StartDate.Format(utils.FormatDateTime), EndDate: v.EndDate.Format(utils.FormatDateTime), ModifyTime: v.ModifyTime.Format(utils.FormatDateTime), ChartEdbMappingId: int(v.FutureGoodEdbInfoID), ChartInfoId: edbInfoMapping.ChartInfoId, MaxData: v.MaxValue, MinData: v.MinValue, IsOrder: edbInfoMapping.IsOrder, IsAxis: edbInfoMapping.IsAxis, EdbInfoType: edbInfoMapping.EdbInfoType, EdbInfoCategoryType: edbInfoMapping.EdbInfoCategoryType, LeadValue: edbInfoMapping.LeadValue, LeadUnit: edbInfoMapping.LeadUnit, LeadUnitEn: edbInfoMapping.LeadUnitEn, ChartStyle: edbInfoMapping.ChartStyle, ChartColor: edbInfoMapping.ChartColor, PredictChartColor: edbInfoMapping.PredictChartColor, ChartWidth: edbInfoMapping.ChartWidth, ChartType: edbInfoMapping.ChartType, LatestDate: v.LatestDate, LatestValue: v.LatestValue, UniqueCode: futureGoodEdbInfoMapping.UniqueCode + "1" + strconv.Itoa(k), MinValue: v.MinValue, MaxValue: v.MaxValue, }, DataList: nil, IsNullData: false, } futureGoodMappingList = append(futureGoodMappingList, newMappingInfo) barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, request.BarChartInfoEdbItemReq{ EdbInfoId: newMappingInfo.EdbInfoId, Name: fmt.Sprint("M+", v.Month), NameEn: fmt.Sprint("M+", v.Month), Source: newMappingInfo.Source, }) } // 获取数据 for _, v := range futureGoodMappingList { dataList := make([]*edbDataModel.EdbDataList, 0) tmpDataList, tmpErr := future_good_edb_data.GetFutureGoodEdbDataListByDate(v.EdbInfoId, startDate, endDate) if tmpErr != nil { return } for _, tmpData := range tmpDataList { dataList = append(dataList, &edbDataModel.EdbDataList{ EdbDataId: int(tmpData.FutureGoodEdbDataID), EdbInfoId: int(tmpData.FutureGoodEdbInfoID), DataTime: tmpData.DataTime.Format(utils.FormatDate), DataTimestamp: tmpData.DataTimestamp, Value: tmpData.Close, }) } edbDataListMap[v.EdbInfoId] = dataList v.DataList = dataList } edbList = append(edbList, futureGoodMappingList...) xEdbIdValue, yDataList, err = BarChartData(edbList[0], futureGoodEdbInfoList, edbDataListMap, barChartInfoDateList, regionType, latestDate) xDataList = []chart_info.XData{ { Name: "现货价", NameEn: "Spot Price", }, } if regionType == `国内` { for i := range futureGoodEdbInfoList { xDataList = append(xDataList, chart_info.XData{ Name: fmt.Sprint("M+", i), NameEn: fmt.Sprint("M+ ", i), }) } } else { for _, v := range futureGoodEdbInfoList { divMonth := (v.Year-latestDateTime.Year())*12 + (int(v.Month) - int(latestDateTime.Month())) xDataList = append(xDataList, chart_info.XData{ Name: fmt.Sprint("M+", divMonth), NameEn: fmt.Sprint("M+ ", divMonth), }) } } return } // BarChartData 商品价格曲线的数据处理 func BarChartData(edbInfoMapping *chartEdbMappingModel.ChartEdbInfoMappingList, futureGoodMappingList []*future_good_edb_info.FutureGoodEdbInfo, edbDataListMap map[int][]*edbDataModel.EdbDataList, barChartInfoDateList []request.BarChartInfoDateReq, regionType, latestDate string) (edbIdList []int, yDataList []chart_info.YData, err error) { // 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3}) edbDataMap := make(map[int]map[string]float64) for edbInfoId, edbDataList := range edbDataListMap { edbDateData := make(map[string]float64) for _, edbData := range edbDataList { edbDateData[edbData.DataTime] = edbData.Value } edbDataMap[edbInfoId] = edbDateData } // edbIdList 指标展示顺序;x轴的指标顺序 edbIdList = make([]int, 0) edbIdList = append(edbIdList, edbInfoMapping.EdbInfoId) for _, v := range futureGoodMappingList { edbIdList = append(edbIdList, int(v.FutureGoodEdbInfoID)) } latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local) yDataList = make([]chart_info.YData, 0) //y轴的数据列表 for _, barChartInfoDate := range barChartInfoDateList { 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列表 // 现货指标 realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[edbInfoMapping.EdbInfoId], edbDataMap[edbInfoMapping.EdbInfoId]) if tmpErr != nil { err = tmpErr return } findDataList = append(findDataList, findDataValue) if isFind { maxDate = realDateTime } else { noDataIdList = append(noDataIdList, edbInfoMapping.EdbInfoId) noDataIdMap[edbInfoMapping.EdbInfoId] = edbInfoMapping.EdbInfoId } currMonth := findDateTime.Month() // 当前月份 currYear := findDateTime.Year() // 当前年份 xEdbInfoIdList = append(xEdbInfoIdList, edbInfoMapping.EdbInfoId) indexList := make([]int, 0) if regionType == `国内` { for i := currMonth; i < 12; i++ { indexList = append(indexList, int(i)) } for i := 1; i < int(currMonth); i++ { indexList = append(indexList, i) } } else { for i, v := range futureGoodMappingList { if v.Year > currYear || (v.Year == currYear && int(v.Month) >= int(currMonth)) { indexList = append(indexList, i) } } } for _, i := range indexList { futureGoodMapping := futureGoodMappingList[i] // 当前的期货指标 tmpRealDateTime, tmpFindDataValue, tmpIsFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[int(futureGoodMapping.FutureGoodEdbInfoID)], edbDataMap[int(futureGoodMapping.FutureGoodEdbInfoID)]) if tmpErr != nil { err = tmpErr return } findDataList = append(findDataList, tmpFindDataValue) if tmpIsFind { if maxDate.IsZero() || maxDate.Before(tmpRealDateTime) { maxDate = tmpRealDateTime } } else { noDataIdList = append(noDataIdList, int(futureGoodMapping.FutureGoodEdbInfoID)) noDataIdMap[int(futureGoodMapping.FutureGoodEdbInfoID)] = int(futureGoodMapping.FutureGoodEdbInfoID) } // 当前期货合约的指标 xEdbInfoIdList = append(xEdbInfoIdList, int(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, chart_info.YData{ Date: yDate, Value: findDataList, NoDataEdbList: noDataIdList, XEdbInfoIdList: xEdbInfoIdList, Color: barChartInfoDate.Color, Name: yName, NameEn: yNameEn, }) } return } // GetNeedDateData 获取合约内需要的日期数据 func GetNeedDateData(needDateTime time.Time, dataList []*edbDataModel.EdbDataList, edbDataMap 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 } for tmpDateTime := needDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) { tmpDate := tmpDateTime.Format(utils.FormatDate) if tmpValue, ok := edbDataMap[tmpDate]; ok { //如果能找到数据,那么就返回 // 数据为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) } }() edbInfoMapping, err := chartEdbMappingModel.GetEtaEdbChartEdbMapping(chartInfoId) if err != nil { errMsg = "获取需要刷新的ETA指标失败:Err:" + err.Error() return } // 获取期货指标 futureGoodEdbInfoMapping, err := chartEdbMappingModel.GetFutureGoodEdbChartEdbMapping(chartInfoId) if err != nil { errMsg = "获取需要刷新的商品期货指标失败:Err:" + err.Error() return } // 获取期货指标以及期货数据 futureGoodEdbInfoList, err := future_good_edb_info.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId) if err != nil { return } // 批量刷新ETA指标 err, _ = chart.EdbInfoRefreshAllFromBase([]int{edbInfoMapping.EdbInfoId}, false) if err != nil { return } // 批量刷新期货指标 err = FutureGoodEdbInfoRefreshAllFromBase(futureGoodEdbInfoList, false) if err != nil { return } return }