|
@@ -0,0 +1,1811 @@
|
|
|
+package models
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "eta/eta_index_lib/utils"
|
|
|
+ "fmt"
|
|
|
+ "github.com/shopspring/decimal"
|
|
|
+ "sort"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+// EdbInfoData
|
|
|
+// @Description: 指标数据
|
|
|
+type EdbInfoData struct {
|
|
|
+ EdbDataId int `description:"数据ID"`
|
|
|
+ DataTime time.Time `description:"数据日期"`
|
|
|
+ Value float64 `description:"数据"`
|
|
|
+}
|
|
|
+
|
|
|
+// BaseCalculateBySearchData
|
|
|
+// @Description: 基础的计算公式
|
|
|
+type BaseCalculateBySearchData struct {
|
|
|
+ DataList []*EdbInfoSearchData
|
|
|
+ Frequency string `description:"需要转换的频度"`
|
|
|
+ Formula interface{}
|
|
|
+ Calendar string `description:"公历/农历"`
|
|
|
+ MoveType int `description:"移动方式:1:领先(默认),2:滞后"`
|
|
|
+ MoveFrequency string `description:"移动频度"`
|
|
|
+ FromFrequency string `description:"来源的频度"`
|
|
|
+ Source int `description:"1:累计值转月;2:累计值转季;3:同比值;4:同差值;5:N数值移动平均数计算;6:环比值;7:环差值;8:升频;9:降频;10:时间移位;11:超季节性;12:年化;13:累计值;14:累计值年初至今;15:指数修匀;16:日均值"`
|
|
|
+}
|
|
|
+
|
|
|
+// BaseCalculate
|
|
|
+// @Description: 基础的计算公式
|
|
|
+type BaseCalculate struct {
|
|
|
+ DataList []*EdbInfoData
|
|
|
+ Frequency string `description:"需要转换的频度"`
|
|
|
+ Formula interface{}
|
|
|
+ Calendar string `description:"公历/农历"`
|
|
|
+ MoveType int `description:"移动方式:1:领先(默认),2:滞后"`
|
|
|
+ MoveFrequency string `description:"移动频度"`
|
|
|
+ FromFrequency string `description:"来源的频度"`
|
|
|
+ Source int `description:"1:累计值转月;2:累计值转季;3:同比值;4:同差值;5:N数值移动平均数计算;6:环比值;7:环差值;8:升频;9:降频;10:时间移位;11:超季节性;12:年化;13:累计值;14:累计值年初至今;15:指数修匀;16:日均值"`
|
|
|
+}
|
|
|
+
|
|
|
+type BaseCalculateResp struct {
|
|
|
+ DataMap map[string]float64
|
|
|
+ DateList []string
|
|
|
+}
|
|
|
+
|
|
|
+// Ljzzy
|
|
|
+// @Description: 累计值转月
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:05:19
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Ljzzy() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+
|
|
|
+ dataList := obj.DataList // 升序
|
|
|
+ // 数据处理
|
|
|
+ yearMap := make(map[int]map[int]*EdbInfoData)
|
|
|
+ dataLen := len(dataList)
|
|
|
+ for i := 0; i < dataLen; i++ {
|
|
|
+ item := dataList[i]
|
|
|
+ //日其中获取年
|
|
|
+ itemDate := item.DataTime
|
|
|
+ year := itemDate.Year()
|
|
|
+ month := int(itemDate.Month())
|
|
|
+ if monthMap, yok := yearMap[year]; yok {
|
|
|
+ monthMap[month] = item
|
|
|
+ yearMap[year] = monthMap
|
|
|
+ } else {
|
|
|
+ monthMap = make(map[int]*EdbInfoData)
|
|
|
+ monthMap[month] = item
|
|
|
+ yearMap[year] = monthMap
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始计算
|
|
|
+ for yk, yv := range yearMap {
|
|
|
+ _, oneMonthOk := yv[1]
|
|
|
+ _, twoMonthOk := yv[2]
|
|
|
+ if !oneMonthOk && !twoMonthOk {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ for i := 1; i <= 12; i++ {
|
|
|
+ //fmt.Println(yk, i, yv[i])
|
|
|
+ dataCurrentItem := yv[i]
|
|
|
+ if dataCurrentItem == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ var date time.Time
|
|
|
+ var val float64
|
|
|
+
|
|
|
+ // 一二月单独处理
|
|
|
+ if i == 1 || i == 2 {
|
|
|
+ if _, mok := yv[1]; mok { //1月有值
|
|
|
+ if i == 1 {
|
|
|
+ date = dataCurrentItem.DataTime
|
|
|
+ val, _ = decimal.NewFromFloat(dataCurrentItem.Value).Float64() //a.Div(b).Float64()
|
|
|
+ }
|
|
|
+ if i == 2 {
|
|
|
+ dataOneItem := yv[1]
|
|
|
+ date = dataCurrentItem.DataTime
|
|
|
+ twoMonth := decimal.NewFromFloat(dataCurrentItem.Value)
|
|
|
+ oneMonth := decimal.NewFromFloat(dataOneItem.Value)
|
|
|
+ val, _ = twoMonth.Sub(oneMonth).Float64()
|
|
|
+ }
|
|
|
+ } else { //1月无值
|
|
|
+ dataTwoItem := yv[2]
|
|
|
+ if i == 1 {
|
|
|
+ dateStr := strconv.Itoa(yk) + "-01-31"
|
|
|
+ a := decimal.NewFromFloat(dataTwoItem.Value)
|
|
|
+ b := decimal.NewFromFloat(2.0)
|
|
|
+ val, _ = a.Div(b).Float64()
|
|
|
+
|
|
|
+ date, err = time.ParseInLocation(utils.FormatDate, dateStr, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ if i == 2 {
|
|
|
+ //1月无值:1月=2月/2 (不管怎样,都要给1月赋值)
|
|
|
+ {
|
|
|
+ dateStr := strconv.Itoa(yk) + "-01-31"
|
|
|
+ a := decimal.NewFromFloat(dataTwoItem.Value)
|
|
|
+ b := decimal.NewFromFloat(2.0)
|
|
|
+ val, _ = a.Div(b).Float64()
|
|
|
+ date, err = time.ParseInLocation(utils.FormatDate, dateStr, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ dateDataMap[date] = val
|
|
|
+ }
|
|
|
+ //end 1月无值
|
|
|
+
|
|
|
+ // 这是正常二月份的值
|
|
|
+ date = dataCurrentItem.DataTime
|
|
|
+ a := decimal.NewFromFloat(dataTwoItem.Value)
|
|
|
+ b := decimal.NewFromFloat(2.0)
|
|
|
+ val, _ = a.Div(b).Float64()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ dataPreItem := yv[i-1]
|
|
|
+ if dataCurrentItem != nil && dataPreItem != nil {
|
|
|
+ date = dataCurrentItem.DataTime
|
|
|
+ //val = dataCurrentItem.Value - dataPreItem.Value
|
|
|
+ a := decimal.NewFromFloat(dataCurrentItem.Value)
|
|
|
+ b := decimal.NewFromFloat(dataPreItem.Value)
|
|
|
+ val, _ = a.Sub(b).Float64()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有日期,那么就退出当前循环,进入下一个循环
|
|
|
+ if date.IsZero() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[date] = val
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Ljzzj
|
|
|
+// @Description: 累计值转季度
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:05:05
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Ljzzj() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList // 升序
|
|
|
+ // 数据处理
|
|
|
+ yearMap := make(map[int]map[int]*EdbInfoData)
|
|
|
+ dataLen := len(dataList)
|
|
|
+ for i := 0; i < dataLen; i++ {
|
|
|
+ item := dataList[i]
|
|
|
+ //日其中获取年
|
|
|
+ itemDate := item.DataTime
|
|
|
+ year := itemDate.Year()
|
|
|
+ quarter := utils.MonthQuarterMap[int(itemDate.Month())]
|
|
|
+ if quarterMap, yok := yearMap[year]; yok {
|
|
|
+ quarterMap[quarter] = item
|
|
|
+ yearMap[year] = quarterMap
|
|
|
+ } else {
|
|
|
+ quarterMap = make(map[int]*EdbInfoData)
|
|
|
+ quarterMap[quarter] = item
|
|
|
+ yearMap[year] = quarterMap
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始计算
|
|
|
+ for yk, yv := range yearMap {
|
|
|
+ _, oneQuarterOk := yv[1]
|
|
|
+ _, twoQuarterOk := yv[2]
|
|
|
+ if !oneQuarterOk && !twoQuarterOk {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ for i := 1; i <= 4; i++ {
|
|
|
+ //fmt.Println(yk, i, yv[i])
|
|
|
+ dataCurrentItem := yv[i]
|
|
|
+ if dataCurrentItem == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ var date time.Time
|
|
|
+ var val float64
|
|
|
+
|
|
|
+ // 一二季度单独处理
|
|
|
+ if i == 1 || i == 2 {
|
|
|
+ if _, mok := yv[1]; mok { //第1个季度有值
|
|
|
+ if i == 1 {
|
|
|
+ date = dataCurrentItem.DataTime
|
|
|
+ val, _ = decimal.NewFromFloat(dataCurrentItem.Value).Float64() //a.Div(b).Float64()
|
|
|
+ }
|
|
|
+ if i == 2 {
|
|
|
+ dataOneItem := yv[1]
|
|
|
+ date = dataCurrentItem.DataTime
|
|
|
+ twoQuarter := decimal.NewFromFloat(dataCurrentItem.Value)
|
|
|
+ oneQuarter := decimal.NewFromFloat(dataOneItem.Value)
|
|
|
+ val, _ = twoQuarter.Sub(oneQuarter).Float64()
|
|
|
+ }
|
|
|
+ } else { //第1个季度无值
|
|
|
+ dataTwoItem := yv[2]
|
|
|
+ if i == 1 {
|
|
|
+ dateStr := strconv.Itoa(yk) + "-03-31"
|
|
|
+ a := decimal.NewFromFloat(dataTwoItem.Value)
|
|
|
+ b := decimal.NewFromFloat(2.0)
|
|
|
+ val, _ = a.Div(b).Float64()
|
|
|
+ date, err = time.ParseInLocation(utils.FormatDate, dateStr, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if i == 2 {
|
|
|
+ //第1个季度无值:第1个季度=第2个季度/2 (不管怎样,都要给1季度赋值)
|
|
|
+ {
|
|
|
+ dateStr := strconv.Itoa(yk) + "-03-31"
|
|
|
+ a := decimal.NewFromFloat(dataTwoItem.Value)
|
|
|
+ b := decimal.NewFromFloat(2.0)
|
|
|
+ val, _ = a.Div(b).Float64()
|
|
|
+ date, err = time.ParseInLocation(utils.FormatDate, dateStr, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[date] = val
|
|
|
+ }
|
|
|
+ //end 第1个季度无值
|
|
|
+
|
|
|
+ date = dataCurrentItem.DataTime
|
|
|
+ a := decimal.NewFromFloat(dataTwoItem.Value)
|
|
|
+ b := decimal.NewFromFloat(2.0)
|
|
|
+ val, _ = a.Div(b).Float64()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ dataPreItem := yv[i-1]
|
|
|
+ if dataCurrentItem != nil && dataPreItem != nil {
|
|
|
+ date = dataCurrentItem.DataTime
|
|
|
+ //val = dataCurrentItem.Value - dataPreItem.Value
|
|
|
+ a := decimal.NewFromFloat(dataCurrentItem.Value)
|
|
|
+ b := decimal.NewFromFloat(dataPreItem.Value)
|
|
|
+ val, _ = a.Sub(b).Float64()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有日期,那么就退出当前循环,进入下一个循环
|
|
|
+ if date.IsZero() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[date] = val
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Tbz
|
|
|
+// @Description: 同比值计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:04:59
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Tbz() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+ frequency := obj.FromFrequency
|
|
|
+
|
|
|
+ //数据处理
|
|
|
+ // 数据降序
|
|
|
+ dataList = reverseSliceByDesc(dataList)
|
|
|
+
|
|
|
+ var dateArr []time.Time
|
|
|
+ dataMap := make(map[string]*EdbInfoData) // 避免因为时间戳导致的日期不对,还是用string来表示比较合适
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ dataMap[v.DataTime.Format(utils.FormatDate)] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始计算
|
|
|
+ for _, currentDate := range dateArr {
|
|
|
+ //当前日期
|
|
|
+ currentDateStr := currentDate.Format(utils.FormatDate)
|
|
|
+ currentItem, ok := dataMap[currentDateStr]
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 找到的数据
|
|
|
+ var findItem *EdbInfoData
|
|
|
+
|
|
|
+ //上一年的日期
|
|
|
+ preDate := currentDate.AddDate(-1, 0, 0)
|
|
|
+ preDateStr := preDate.Format(utils.FormatDate)
|
|
|
+ if findItem, ok = dataMap[preDateStr]; !ok { //上一年同期没找到
|
|
|
+ if frequency == "月度" { //向上和向下,各找一个月
|
|
|
+ for i := 0; i <= 35; i++ {
|
|
|
+ nextDateDay := preDate.AddDate(0, 0, i)
|
|
|
+ nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+ if findItem, ok = dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
|
|
|
+ break
|
|
|
+ } else {
|
|
|
+ preDateDay := preDate.AddDate(0, 0, -i)
|
|
|
+ preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+ if findItem, ok = dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if frequency == "季度" || frequency == "年度" {
|
|
|
+ if findItem, ok = dataMap[preDateStr]; ok { //上一年同期->下一个月找到
|
|
|
+ break
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ nextDateDay := preDate.AddDate(0, 0, 1)
|
|
|
+ nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+
|
|
|
+ preDateDay := preDate.AddDate(0, 0, -1)
|
|
|
+ preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+
|
|
|
+ for i := 0; i < 35; i++ {
|
|
|
+ if i >= 1 {
|
|
|
+ nextDateDay = nextDateDay.AddDate(0, 0, i)
|
|
|
+ nextDateDayStr = nextDateDay.Format(utils.FormatDate)
|
|
|
+ }
|
|
|
+ if findItem, ok = dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
|
|
|
+ break
|
|
|
+ } else {
|
|
|
+ if i >= 1 {
|
|
|
+ preDateDay = preDateDay.AddDate(0, 0, -i)
|
|
|
+ preDateDayStr = preDateDay.Format(utils.FormatDate)
|
|
|
+ }
|
|
|
+ if findItem, ok = dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没找到数据
|
|
|
+ if findItem == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[currentDate] = tbzDiv(currentItem.Value, findItem.Value)
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// tbzDiv
|
|
|
+// @Description: 同比值计算
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-02 16:29:14
|
|
|
+// @param a float64
|
|
|
+// @param b float64
|
|
|
+// @return float64
|
|
|
+func tbzDiv(a, b float64) float64 {
|
|
|
+ var val float64
|
|
|
+ if b != 0 {
|
|
|
+ af := decimal.NewFromFloat(a)
|
|
|
+ bf := decimal.NewFromFloat(b)
|
|
|
+ val, _ = af.Div(bf).Sub(decimal.NewFromFloat(1)).RoundCeil(4).Float64()
|
|
|
+ }
|
|
|
+ return val
|
|
|
+}
|
|
|
+
|
|
|
+// Tcz
|
|
|
+// @Description: 计算同差值
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:04:51
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Tcz() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList // 降序
|
|
|
+ frequency := obj.FromFrequency
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ // 数据降序
|
|
|
+ dataList = reverseSliceByDesc(dataList)
|
|
|
+ var dateArr []time.Time
|
|
|
+ dataMap := make(map[string]*EdbInfoData)
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ dataMap[v.DataTime.Format(utils.FormatDate)] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始计算
|
|
|
+ for _, currentDate := range dateArr {
|
|
|
+ //当前日期
|
|
|
+ currentItem, ok := dataMap[currentDate.Format(utils.FormatDate)]
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 找到的数据
|
|
|
+ var findItem *EdbInfoData
|
|
|
+
|
|
|
+ //上一年的日期
|
|
|
+ preDate := currentDate.AddDate(-1, 0, 0)
|
|
|
+ preDateStr := preDate.Format(utils.FormatDate)
|
|
|
+ if findItem, ok = dataMap[preDateStr]; !ok {
|
|
|
+ //上一年同期没找到
|
|
|
+ if frequency == "月度" { //向上和向下,各找一个月
|
|
|
+ for i := 0; i <= 35; i++ {
|
|
|
+ nextDateDay := preDate.AddDate(0, 0, i)
|
|
|
+ nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+ if findItem, ok = dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
|
|
|
+ break
|
|
|
+ } else {
|
|
|
+ preDateDay := preDate.AddDate(0, 0, -i)
|
|
|
+ preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+ if findItem, ok = dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if frequency == "季度" || frequency == "年度" {
|
|
|
+ if findItem, ok = dataMap[preDateStr]; ok { //上一年同期->下一个月找到
|
|
|
+ break
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for i := 0; i < 35; i++ {
|
|
|
+ nextDateDay := preDate.AddDate(0, 0, i)
|
|
|
+ nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+ if findItem, ok = dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
|
|
|
+ break
|
|
|
+ } else {
|
|
|
+ preDateDay := preDate.AddDate(0, 0, -i)
|
|
|
+ preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+ if findItem, ok = dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没找到数据
|
|
|
+ if findItem == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[currentDate] = tczSub(currentItem.Value, findItem.Value)
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// tczSub
|
|
|
+// @Description: 计算同差值
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-02 18:01:46
|
|
|
+// @param a float64
|
|
|
+// @param b float64
|
|
|
+// @return float64
|
|
|
+func tczSub(a, b float64) float64 {
|
|
|
+ af := decimal.NewFromFloat(a)
|
|
|
+ bf := decimal.NewFromFloat(b)
|
|
|
+ val, _ := af.Sub(bf).RoundCeil(4).Float64()
|
|
|
+ return val
|
|
|
+}
|
|
|
+
|
|
|
+// Nszydpjjs
|
|
|
+// @Description: N数值移动平均数计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:17:38
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Nszydpjjs() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ fromDataList := obj.DataList
|
|
|
+ nVal := fmt.Sprint(obj.Formula)
|
|
|
+ formulaInt, err := strconv.Atoi(nVal)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+
|
|
|
+ // 数据降序
|
|
|
+ fromDataList = reverseSliceByDesc(fromDataList)
|
|
|
+
|
|
|
+ var fromDateArr []time.Time
|
|
|
+ fromDataMap := make(map[time.Time]*EdbInfoData)
|
|
|
+ for _, v := range fromDataList {
|
|
|
+ fromDateArr = append(fromDateArr, v.DataTime)
|
|
|
+ fromDataMap[v.DataTime] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ arrLen := len(fromDateArr)
|
|
|
+ for ak, currentDate := range fromDateArr {
|
|
|
+ //处理第一个值
|
|
|
+ var valArr []float64
|
|
|
+ if findItem, ok := fromDataMap[currentDate]; ok {
|
|
|
+ valArr = append(valArr, findItem.Value)
|
|
|
+ } else {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if ak+1 != arrLen {
|
|
|
+ //处理除第一个值之外的N-1个值
|
|
|
+ for i := 1; i < formulaInt; i++ {
|
|
|
+ arrIndex := ak + i
|
|
|
+ if arrIndex >= arrLen {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ arrVal := fromDateArr[arrIndex]
|
|
|
+ if findItem, ok := fromDataMap[arrVal]; ok {
|
|
|
+ valArr = append(valArr, findItem.Value)
|
|
|
+ } else {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ valArrLen := len(valArr)
|
|
|
+ //var totalVal float64
|
|
|
+ totalVal := decimal.NewFromFloat(0.00)
|
|
|
+ for _, v := range valArr {
|
|
|
+ newDecimal := decimal.NewFromFloat(v)
|
|
|
+ totalVal = totalVal.Add(newDecimal)
|
|
|
+ }
|
|
|
+ af := totalVal //decimal.NewFromFloat(totalVal)
|
|
|
+ bf := decimal.NewFromFloat(float64(valArrLen))
|
|
|
+ val, _ := af.Div(bf).RoundCeil(4).Float64()
|
|
|
+
|
|
|
+ dateDataMap[currentDate] = val
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Hbz
|
|
|
+// @Description: 环比值计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:28:24
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Hbz() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+ nVal := fmt.Sprint(obj.Formula)
|
|
|
+ formulaInt, err := strconv.Atoi(nVal)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ // 数据降序
|
|
|
+ dataList = reverseSliceByDesc(dataList)
|
|
|
+
|
|
|
+ var dateArr []time.Time
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ dataLen := len(dataList)
|
|
|
+ //fmt.Println("dataLen:", dataLen)
|
|
|
+ for i := 0; i < dataLen; i++ {
|
|
|
+ j := i + formulaInt
|
|
|
+ if j < dataLen {
|
|
|
+ //当期
|
|
|
+ currentItem := dataList[i]
|
|
|
+ preItem := dataList[j]
|
|
|
+
|
|
|
+ // 当期和上期没有数据
|
|
|
+ if currentItem == nil || preItem == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始计算
|
|
|
+ val, ok := hbzDiv(currentItem.Value, preItem.Value)
|
|
|
+ // 计算失败
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[currentItem.DataTime] = val
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// hbzDiv
|
|
|
+// @Description: 环比值计算,current:当期,pre:上期 公式: (当期-上期)/上期
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-02 18:20:11
|
|
|
+// @param current float64
|
|
|
+// @param pre float64
|
|
|
+// @return val float64
|
|
|
+// @return ok bool
|
|
|
+func hbzDiv(current, pre float64) (val float64, ok bool) {
|
|
|
+ if pre == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ currentVal := decimal.NewFromFloat(current)
|
|
|
+ preVal := decimal.NewFromFloat(pre)
|
|
|
+ val, _ = currentVal.Sub(preVal).Div(preVal).RoundCeil(4).Float64()
|
|
|
+ //valStr := decimal.NewFromFloat(val).RoundCeil(4).String() //utils.SubFloatToString(val, 4)
|
|
|
+ ok = true
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Hcz
|
|
|
+// @Description: 计算环差值数据
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:33:20
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Hcz() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+ nVal := fmt.Sprint(obj.Formula)
|
|
|
+ formulaInt, err := strconv.Atoi(nVal)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ // 数据降序
|
|
|
+ dataList = reverseSliceByDesc(dataList)
|
|
|
+
|
|
|
+ var dateArr []time.Time
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ }
|
|
|
+
|
|
|
+ dataLen := len(dataList)
|
|
|
+ fmt.Println("dataLen:", dataLen)
|
|
|
+ for i := 0; i < dataLen; i++ {
|
|
|
+ j := i + formulaInt
|
|
|
+ if j < dataLen {
|
|
|
+ //当期
|
|
|
+ currentItem := dataList[i]
|
|
|
+ preItem := dataList[j]
|
|
|
+
|
|
|
+ // 当期和上期没有数据
|
|
|
+ if currentItem == nil || preItem == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始计算
|
|
|
+ val := hczDiv(currentItem.Value, preItem.Value)
|
|
|
+
|
|
|
+ dateDataMap[currentItem.DataTime] = val
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// hczDiv
|
|
|
+// @Description: 环差值计算,current:当期,pre:上期 公式:当期-上期
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-02 18:33:07
|
|
|
+// @param current float64
|
|
|
+// @param pre float64
|
|
|
+// @return float64
|
|
|
+func hczDiv(current, pre float64) float64 {
|
|
|
+ currentVal := decimal.NewFromFloat(current)
|
|
|
+ preVal := decimal.NewFromFloat(pre)
|
|
|
+ val, _ := currentVal.Sub(preVal).RoundCeil(4).Float64()
|
|
|
+ //valStr := decimal.NewFromFloat(val).RoundCeil(4).String() //utils.SubFloatToString(val, 4)
|
|
|
+
|
|
|
+ return val
|
|
|
+}
|
|
|
+
|
|
|
+// UpFrequency
|
|
|
+// @Description: 升频计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:43:03
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) UpFrequency() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ var dateArr []time.Time
|
|
|
+ dataMap := make(map[time.Time]*EdbInfoData)
|
|
|
+ fromDataMap := make(map[time.Time]float64)
|
|
|
+ //来源指指标数据
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ dataMap[v.DataTime] = v
|
|
|
+ fromDataMap[v.DataTime] = v.Value
|
|
|
+ }
|
|
|
+
|
|
|
+ if obj.FromFrequency == `日度` {
|
|
|
+ errMsg = `不能选择日度指标`
|
|
|
+ err = errors.New(errMsg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ dataLen := len(dataList)
|
|
|
+ for i := 0; i < dataLen; i++ {
|
|
|
+ //当期
|
|
|
+ currentItem := dataList[i]
|
|
|
+ currentDate := currentItem.DataTime
|
|
|
+ var day int
|
|
|
+ var preItem *EdbInfoData
|
|
|
+ var preDate time.Time
|
|
|
+ if i == 0 {
|
|
|
+ day = int(time.Now().Sub(currentDate).Hours() / float64(24))
|
|
|
+ preDate = time.Now()
|
|
|
+ } else {
|
|
|
+ j := i - 1
|
|
|
+ if j < dataLen {
|
|
|
+ preItem = dataList[j]
|
|
|
+ day = int(preItem.DataTime.Sub(currentDate).Hours() / float64(24))
|
|
|
+ utils.FileLog.Info("preItem.DataTime:" + preItem.DataTime.Format(utils.FormatDate) + ";currentItem.DataTime" + currentItem.DataTime.Format(utils.FormatDate))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for k := 0; k <= day; k++ {
|
|
|
+ needDay := preDate.AddDate(0, 0, -k)
|
|
|
+ dateDataMap[needDay] = currentItem.Value
|
|
|
+ }
|
|
|
+ dateDataMap[currentItem.DataTime] = currentItem.Value
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// DownFrequency
|
|
|
+// @Description: 降频计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-02 18:51:26
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) DownFrequency() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+ edbFrequency := obj.Frequency
|
|
|
+ formula := obj.Formula.(string)
|
|
|
+
|
|
|
+ if !CheckFrequency(obj.FromFrequency, obj.Frequency) {
|
|
|
+ errMsg = "频度异常,不允许低频降频到高频"
|
|
|
+ err = errors.New(errMsg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ var dateArr []time.Time
|
|
|
+ dataMap := make(map[time.Time]*EdbInfoData)
|
|
|
+ fromDataMap := make(map[time.Time]float64)
|
|
|
+ //来源指指标数据
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ dataMap[v.DataTime] = v
|
|
|
+ fromDataMap[v.DataTime] = v.Value
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ dataLen := len(dataList)
|
|
|
+ if dataLen <= 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ startDataTime := dataList[0].DataTime
|
|
|
+ endDataTime := dataList[dataLen-1].DataTime
|
|
|
+
|
|
|
+ var lastValue float64 // 最近的值
|
|
|
+ var nextEndDate time.Time // 下一个节点的日期
|
|
|
+ weekDayDataList := make([]float64, 0)
|
|
|
+ for tmpStartDataTime := startDataTime; !tmpStartDataTime.After(endDataTime); tmpStartDataTime = tmpStartDataTime.AddDate(0, 0, 1) {
|
|
|
+ // 将当前数据加入到 weekDayDataList
|
|
|
+ if tmpData, ok := dataMap[tmpStartDataTime]; ok {
|
|
|
+ tmpValue := decimal.NewFromFloat(tmpData.Value)
|
|
|
+ tmpValueFloat, _ := tmpValue.Round(4).Float64()
|
|
|
+ weekDayDataList = append(weekDayDataList, tmpValueFloat)
|
|
|
+ }
|
|
|
+ // 如果下个节点的日期不存在,那么就先给赋值(兼容时间区间内只有一组数据的情况)
|
|
|
+ if nextEndDate.IsZero() {
|
|
|
+ nextEndDate = utils.GetFrequencyEndDay(tmpStartDataTime, edbFrequency)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 日期处理过滤
|
|
|
+ switch edbFrequency {
|
|
|
+ case "周度":
|
|
|
+ if tmpStartDataTime.Weekday() != 0 {
|
|
|
+ //不是周日,代表需要进入下一个循环获取数据并计算
|
|
|
+ continue
|
|
|
+ } else {
|
|
|
+ //记录下一个结束节点的日期
|
|
|
+ nextEndDate = tmpStartDataTime.AddDate(0, 0, 7)
|
|
|
+ }
|
|
|
+ case "旬度":
|
|
|
+ nextDay := tmpStartDataTime.AddDate(0, 0, 1)
|
|
|
+ if nextDay.Day() != 1 && nextDay.Day() != 11 && nextDay.Day() != 21 {
|
|
|
+ //不是每月10、20、最后一天,代表需要进入下一个循环获取数据并计算
|
|
|
+ continue
|
|
|
+ } else {
|
|
|
+ //记录下一个结束节点的日期
|
|
|
+ if nextDay.Day() == 1 || nextDay.Day() == 11 {
|
|
|
+ //月初或者月末的时候,加10天就好了
|
|
|
+ nextEndDate = nextDay.AddDate(0, 0, 9)
|
|
|
+ } else {
|
|
|
+ tmpNextMonth := nextDay.AddDate(0, 1, 0)
|
|
|
+ nextEndDate = time.Date(tmpNextMonth.Year(), tmpNextMonth.Month(), 1, 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case "月度":
|
|
|
+ nextDay := tmpStartDataTime.AddDate(0, 0, 1)
|
|
|
+ if nextDay.Day() != 1 {
|
|
|
+ //不是每月最后一天,代表需要进入下一个循环获取数据并计算
|
|
|
+ continue
|
|
|
+ } else {
|
|
|
+ //记录下一个结束节点的日期
|
|
|
+ nextEndDate = nextDay.AddDate(0, 1, -1)
|
|
|
+ }
|
|
|
+ case "季度":
|
|
|
+ nextDay := tmpStartDataTime.AddDate(0, 0, 1)
|
|
|
+ if (nextDay.Month() == 1 || nextDay.Month() == 4 || nextDay.Month() == 7 || nextDay.Month() == 10) && nextDay.Day() == 1 {
|
|
|
+ //记录下一个结束节点的日期
|
|
|
+ nextEndDate = nextDay.AddDate(0, 3, -1)
|
|
|
+ } else {
|
|
|
+ //不是3,6,9,12 月份的最后一天,代表需要进入下一个循环获取数据并计算
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ case "年度":
|
|
|
+ if tmpStartDataTime.Month() == 12 && tmpStartDataTime.Day() == 31 {
|
|
|
+ //记录下一个结束节点的日期
|
|
|
+ nextEndDate = tmpStartDataTime.AddDate(1, 0, 0)
|
|
|
+ } else {
|
|
|
+ //不是每年的12-31日,代表需要进入下一个循环获取数据并计算
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ err = errors.New("错误的频度:" + edbFrequency)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 当前时间段内的数据计算,得出实际值
|
|
|
+ var currVal float64
|
|
|
+ lenWeekDayDataList := len(weekDayDataList)
|
|
|
+ // 如果这个时间区间内没有数据,那么就采用上一个时间区间的值
|
|
|
+ if len(weekDayDataList) <= 0 {
|
|
|
+ currVal = lastValue
|
|
|
+ } else {
|
|
|
+ if formula == "期末值" {
|
|
|
+ currVal = weekDayDataList[lenWeekDayDataList-1]
|
|
|
+ } else {
|
|
|
+ // 平均值
|
|
|
+ sumValDeci := decimal.NewFromFloat(0)
|
|
|
+ for _, v := range weekDayDataList {
|
|
|
+ tmpValDeci := decimal.NewFromFloat(v)
|
|
|
+ sumValDeci = sumValDeci.Add(tmpValDeci)
|
|
|
+ }
|
|
|
+ lenDeci := decimal.NewFromInt(int64(lenWeekDayDataList))
|
|
|
+ currVal, _ = sumValDeci.Div(lenDeci).Round(4).Float64()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 赋值
|
|
|
+ dateDataMap[tmpStartDataTime] = currVal
|
|
|
+
|
|
|
+ // 一轮结束后,数据清空
|
|
|
+ weekDayDataList = make([]float64, 0)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 最后已有的日期处理完成后,需要对剩余不在时间段内的数据做处理
|
|
|
+ if len(weekDayDataList) > 0 {
|
|
|
+ // 当前时间段内的数据计算,得出实际值
|
|
|
+ var currVal float64
|
|
|
+ lenWeekDayDataList := len(weekDayDataList)
|
|
|
+ // 如果这个时间区间内没有数据,那么就采用上一个时间区间的值
|
|
|
+ if len(weekDayDataList) < 0 {
|
|
|
+ currVal = lastValue
|
|
|
+ } else {
|
|
|
+ if formula == "期末值" {
|
|
|
+ currVal = weekDayDataList[lenWeekDayDataList-1]
|
|
|
+ } else {
|
|
|
+ // 平均值
|
|
|
+ sumValDeci := decimal.NewFromFloat(0)
|
|
|
+ for _, v := range weekDayDataList {
|
|
|
+ tmpValDeci := decimal.NewFromFloat(v)
|
|
|
+ sumValDeci = sumValDeci.Add(tmpValDeci)
|
|
|
+ }
|
|
|
+ lenDeci := decimal.NewFromInt(int64(lenWeekDayDataList))
|
|
|
+ currVal, _ = sumValDeci.Div(lenDeci).Round(4).Float64()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 赋值
|
|
|
+ dateDataMap[nextEndDate] = currVal
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// TimeShift
|
|
|
+// @Description: 时间移位计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-03 13:19:07
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) TimeShift() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+
|
|
|
+ nVal := fmt.Sprint(obj.Formula)
|
|
|
+ formulaInt, err := strconv.Atoi(nVal)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ moveType := obj.MoveType
|
|
|
+ moveFrequency := obj.MoveFrequency
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ var dateArr []time.Time
|
|
|
+ dataMap := make(map[time.Time]*EdbInfoData)
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ dataMap[v.DataTime] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ var shiftDay int
|
|
|
+ switch moveFrequency {
|
|
|
+ case "天":
|
|
|
+ shiftDay = formulaInt
|
|
|
+ case "周":
|
|
|
+ shiftDay = formulaInt * 7
|
|
|
+ case "月":
|
|
|
+ shiftDay = formulaInt * 30
|
|
|
+ case "季":
|
|
|
+ shiftDay = formulaInt * 90
|
|
|
+ case "年":
|
|
|
+ shiftDay = formulaInt * 365
|
|
|
+ default:
|
|
|
+ shiftDay = formulaInt
|
|
|
+ }
|
|
|
+
|
|
|
+ if moveType == 2 {
|
|
|
+ shiftDay = -shiftDay
|
|
|
+ }
|
|
|
+
|
|
|
+ dataLen := len(dataList)
|
|
|
+ for i := 0; i < dataLen; i++ {
|
|
|
+ //当期
|
|
|
+ currentItem := dataList[i]
|
|
|
+ currentDate := currentItem.DataTime
|
|
|
+
|
|
|
+ newDate := currentDate.AddDate(0, 0, shiftDay)
|
|
|
+
|
|
|
+ val, _ := decimal.NewFromFloat(currentItem.Value).RoundCeil(4).Float64()
|
|
|
+
|
|
|
+ dateDataMap[newDate] = val
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Cjjx
|
|
|
+// @Description: 超季节性计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-03 13:28:23
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Cjjx() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+
|
|
|
+ nVal := fmt.Sprint(obj.Formula)
|
|
|
+ formulaInt, err := strconv.Atoi(nVal)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ calendar := obj.Calendar
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ var dateArr []time.Time
|
|
|
+ dataMap := make(map[time.Time]*EdbInfoData)
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ dataMap[v.DataTime] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ // 通过插值法补全所有数据(包含周末)
|
|
|
+ handleDataMap := make(map[time.Time]float64)
|
|
|
+ _, err = HandleDataByLinearRegressionByTime(dataList, handleDataMap)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 每个年份的日期数据需要平移的天数
|
|
|
+ moveDayMap := make(map[int]int, 0) // 每个年份的春节公历
|
|
|
+ var lastDataDay time.Time
|
|
|
+ if len(dataList) > 0 {
|
|
|
+ lastDataDay = dataList[0].DataTime
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ for _, currentDate := range dateArr {
|
|
|
+ // 如果遇到闰二月,如2.29,去掉该天数据
|
|
|
+ if strings.Contains(currentDate.Format(utils.FormatDate), "02-29") {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ //农历的超季节性运算,只计算11月--次年5月,分段计算,与数据区间和N数值有关
|
|
|
+ if calendar == "农历" && currentDate.Month() > 5 && currentDate.Month() < 11 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ currentItem, ok := dataMap[currentDate]
|
|
|
+ // 找不到数据就退出当前循环,进入下一循环
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ pastValueList := make([]float64, 0) // 过去几期的数据
|
|
|
+ pastValueList = append(pastValueList, currentItem.Value) //当前日期
|
|
|
+
|
|
|
+ for i := 1; i < formulaInt; i++ {
|
|
|
+ //前几年当天公历的日期
|
|
|
+ historyPreDate := currentDate.AddDate(-i, 0, 0)
|
|
|
+ moveDay := 0
|
|
|
+ if calendar == "农历" {
|
|
|
+ if tmpMoveDay, ok := moveDayMap[historyPreDate.Year()]; !ok {
|
|
|
+ moveDay, err = getMoveDay(lastDataDay, historyPreDate)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ moveDay = tmpMoveDay
|
|
|
+ }
|
|
|
+
|
|
|
+ // 移动天数到对应农历 的 公历 日期
|
|
|
+ historyPreDate = historyPreDate.AddDate(0, 0, moveDay)
|
|
|
+ }
|
|
|
+
|
|
|
+ if tmpValue, ok := handleDataMap[historyPreDate]; ok { //上一年同期找到
|
|
|
+ pastValueList = append(pastValueList, tmpValue)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(pastValueList) == formulaInt {
|
|
|
+ val, ok := cjjxSub(currentItem.Value, pastValueList)
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ dateDataMap[currentDate] = val
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// cjjxSub
|
|
|
+// @Description: 超季节性计算
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-03 13:25:49
|
|
|
+// @param currValue float64
|
|
|
+// @param pastValue []float64
|
|
|
+// @return value float64
|
|
|
+// @return ok bool
|
|
|
+func cjjxSub(currValue float64, pastValue []float64) (value float64, ok bool) {
|
|
|
+ num := len(pastValue)
|
|
|
+ if num == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ numDecimal := decimal.NewFromInt(int64(num))
|
|
|
+
|
|
|
+ af := decimal.NewFromFloat(currValue)
|
|
|
+ bf := decimal.NewFromFloat(pastValue[0])
|
|
|
+
|
|
|
+ for k := 1; k < num; k++ {
|
|
|
+ tmpVal := decimal.NewFromFloat(pastValue[k])
|
|
|
+ bf = bf.Add(tmpVal)
|
|
|
+ }
|
|
|
+ value, _ = af.Sub(bf.Div(numDecimal)).RoundCeil(4).Float64()
|
|
|
+ ok = true
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Annualized
|
|
|
+// @Description: 年化计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-03 13:34:32
|
|
|
+// @param to orm.TxOrmer
|
|
|
+// @param edbInfoId int
|
|
|
+// @param source int
|
|
|
+// @param fromEdbInfo *EdbInfo
|
|
|
+// @param edbCode string
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Annualized() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ fromDataList := obj.DataList
|
|
|
+ lenFromDataList := len(fromDataList)
|
|
|
+ // 如果来源指标没有数据,那么就直接返回得了
|
|
|
+ if lenFromDataList <= 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ // 插值法数据处理
|
|
|
+ handleDataMap := make(map[time.Time]float64)
|
|
|
+ _, err = HandleDataByLinearRegressionByTime(fromDataList, handleDataMap)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 每年的最后一天的数据值
|
|
|
+ yearLastValMap := make(map[int]float64)
|
|
|
+ startDataTime := fromDataList[0].DataTime
|
|
|
+ endDataTime := fromDataList[lenFromDataList-1].DataTime
|
|
|
+ for i := startDataTime.Year(); i <= endDataTime.Year(); i++ {
|
|
|
+ tmpDate := time.Date(i, 12, 31, startDataTime.Hour(), startDataTime.Minute(), startDataTime.Second(), startDataTime.Nanosecond(), time.Local)
|
|
|
+ if tmpVal, ok := handleDataMap[tmpDate]; ok {
|
|
|
+ yearLastValMap[i] = tmpVal
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ // 遍历来源指标数据
|
|
|
+ for _, v := range fromDataList {
|
|
|
+ currDate := v.DataTime
|
|
|
+
|
|
|
+ perValMap := make(map[time.Time]float64)
|
|
|
+ //前3年当日的数据
|
|
|
+ for i := 1; i <= 3; i++ {
|
|
|
+ tmpDateTime := currDate.AddDate(-i, 0, 0)
|
|
|
+ if tmpVal, ok := handleDataMap[tmpDateTime]; ok {
|
|
|
+ perValMap[tmpDateTime] = tmpVal
|
|
|
+ }
|
|
|
+ }
|
|
|
+ lenPerValMap := len(perValMap)
|
|
|
+ // 如果数据少于2年,那么就不参与计算,结束当前循环,进入下一个循环
|
|
|
+ if lenPerValMap < 2 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // N年 当前值占全年比重 的值列表
|
|
|
+ divValList := make([]decimal.Decimal, 0)
|
|
|
+ for tmpDateTime, tmpVal := range perValMap {
|
|
|
+ yearLastVal, ok2 := yearLastValMap[tmpDateTime.Year()]
|
|
|
+ // 如果当年最后一天没有数据
|
|
|
+ if !ok2 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 当前值占全年比重
|
|
|
+ tmpYearLastVal := decimal.NewFromFloat(yearLastVal)
|
|
|
+ if tmpYearLastVal.IsZero() { //如果是0,那么就退出当前循环,进入下一个循环
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ divVal := decimal.NewFromFloat(tmpVal).Div(tmpYearLastVal)
|
|
|
+ divValList = append(divValList, divVal)
|
|
|
+ }
|
|
|
+
|
|
|
+ lenDivValList := len(divValList)
|
|
|
+ // 如果 N年 当前值占全年比重 的值 小于 2个,那么就不参与计算,结束当前循环,进入下一个循环
|
|
|
+ if lenDivValList < 2 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ divValSum := decimal.NewFromFloat(0)
|
|
|
+ for _, divVal := range divValList {
|
|
|
+ divValSum = divValSum.Add(divVal)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 当前计算出来的结果
|
|
|
+ tmpDivVal := divValSum.Div(decimal.NewFromInt(int64(lenDivValList)))
|
|
|
+ if tmpDivVal.IsZero() { //如果是0,那么就退出当前循环,进入下一个循环
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ currVal, _ := decimal.NewFromFloat(v.Value).Div(tmpDivVal).Round(4).Float64()
|
|
|
+
|
|
|
+ dateDataMap[currDate] = currVal
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Ljz
|
|
|
+// @Description: 累计值
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-03 13:49:17
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Ljz() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+ frequency := obj.Frequency //需要变更的频度
|
|
|
+ fromFrequency := obj.FromFrequency //来源的频度
|
|
|
+ // 数据处理
|
|
|
+ var isWeekData bool // 是否周度数据,如果是周度数据的话,是需要变频的,最后结果还需要除以7
|
|
|
+ // 周度数据需要先变成日度的
|
|
|
+ if fromFrequency == `周度` {
|
|
|
+ isWeekData = true
|
|
|
+ }
|
|
|
+
|
|
|
+ fromEdbDataMap := make(map[time.Time]float64)
|
|
|
+ if isWeekData {
|
|
|
+ dataList, err = HandleDataByLinearRegressionByTime(dataList, fromEdbDataMap)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //日度转周度:日期选周五,计算上周六到本周五的日度值的加总,最新日期为最新值对应的周五。
|
|
|
+ //日度转月度:日期选每个月最后一天,计算当月所有日度值的加总,最新日期为最新值对应当月最后一天。
|
|
|
+ //日度转季度、年度:方法类似转月度。
|
|
|
+ //周度转月度/季度/年度:将周度值转成日度,空值用插值法插值,计算当月/当季/当年所有值的加总,然后除以7。
|
|
|
+ //月度转季度/年度: 当季/当年月度值相加。
|
|
|
+
|
|
|
+ dateList := make([]time.Time, 0)
|
|
|
+ valueMap := make(map[time.Time]float64)
|
|
|
+ switch frequency {
|
|
|
+ case "年度":
|
|
|
+ yearMap := make(map[int]float64)
|
|
|
+ yearList := make([]int, 0)
|
|
|
+ for _, item := range dataList {
|
|
|
+ year := item.DataTime.Year()
|
|
|
+ yearVal, ok := yearMap[year]
|
|
|
+ if ok {
|
|
|
+ yearMap[year] = item.Value + yearVal
|
|
|
+ } else {
|
|
|
+ yearList = append(yearList, year)
|
|
|
+ yearMap[year] = item.Value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, v := range yearList {
|
|
|
+ currTime := time.Date(v, 12, 31, 0, 0, 0, 0, time.Local)
|
|
|
+ dateList = append(dateList, currTime)
|
|
|
+ valueMap[currTime] = yearMap[v]
|
|
|
+ }
|
|
|
+ case "半年度":
|
|
|
+ yearMonthMap := make(map[string]float64)
|
|
|
+ yearMonthList := make([]string, 0)
|
|
|
+ for _, item := range dataList {
|
|
|
+ itemDate := item.DataTime
|
|
|
+ year := itemDate.Year()
|
|
|
+ var tmpK string
|
|
|
+ if itemDate.Month() <= 6 {
|
|
|
+ tmpK = fmt.Sprint(year, "06")
|
|
|
+ } else {
|
|
|
+ tmpK = fmt.Sprint(year, "12")
|
|
|
+ }
|
|
|
+
|
|
|
+ yearVal, ok := yearMonthMap[tmpK]
|
|
|
+ if ok {
|
|
|
+ yearMonthMap[tmpK] = item.Value + yearVal
|
|
|
+ } else {
|
|
|
+ yearMonthList = append(yearMonthList, tmpK)
|
|
|
+ yearMonthMap[tmpK] = item.Value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, v := range yearMonthList {
|
|
|
+ currTime, tmpErr := time.ParseInLocation(utils.FormatYearMonthUnSpace, v, time.Local)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ currTime = currTime.AddDate(0, 1, -1)
|
|
|
+ dateList = append(dateList, currTime)
|
|
|
+ valueMap[currTime] = yearMonthMap[v]
|
|
|
+ }
|
|
|
+ case "季度":
|
|
|
+ yearMonthMap := make(map[string]float64)
|
|
|
+ yearMonthList := make([]string, 0)
|
|
|
+ for _, item := range dataList {
|
|
|
+ itemDate := item.DataTime
|
|
|
+ year := itemDate.Year()
|
|
|
+ var tmpK string
|
|
|
+ if itemDate.Month() <= 3 {
|
|
|
+ tmpK = fmt.Sprint(year, "03")
|
|
|
+ } else if itemDate.Month() <= 6 {
|
|
|
+ tmpK = fmt.Sprint(year, "06")
|
|
|
+ } else if itemDate.Month() <= 9 {
|
|
|
+ tmpK = fmt.Sprint(year, "09")
|
|
|
+ } else {
|
|
|
+ tmpK = fmt.Sprint(year, "12")
|
|
|
+ }
|
|
|
+
|
|
|
+ yearVal, ok := yearMonthMap[tmpK]
|
|
|
+ if ok {
|
|
|
+ yearMonthMap[tmpK] = item.Value + yearVal
|
|
|
+ } else {
|
|
|
+ yearMonthList = append(yearMonthList, tmpK)
|
|
|
+ yearMonthMap[tmpK] = item.Value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, v := range yearMonthList {
|
|
|
+ currTime, tmpErr := time.ParseInLocation(utils.FormatYearMonthUnSpace, v, time.Local)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ currTime = currTime.AddDate(0, 1, -1)
|
|
|
+ dateList = append(dateList, currTime)
|
|
|
+ valueMap[currTime] = yearMonthMap[v]
|
|
|
+ }
|
|
|
+ case "月度":
|
|
|
+ yearMonthMap := make(map[string]float64)
|
|
|
+ yearMonthList := make([]string, 0)
|
|
|
+ for _, item := range dataList {
|
|
|
+ itemDate := item.DataTime
|
|
|
+ year := itemDate.Year()
|
|
|
+ var tmpK string
|
|
|
+ tmpK = fmt.Sprint(year*100 + int(itemDate.Month()))
|
|
|
+
|
|
|
+ yearVal, ok := yearMonthMap[tmpK]
|
|
|
+ if ok {
|
|
|
+ yearMonthMap[tmpK] = item.Value + yearVal
|
|
|
+ } else {
|
|
|
+ yearMonthList = append(yearMonthList, tmpK)
|
|
|
+ yearMonthMap[tmpK] = item.Value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, v := range yearMonthList {
|
|
|
+ currTime, tmpErr := time.ParseInLocation(utils.FormatYearMonthUnSpace, v, time.Local)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ currTime = currTime.AddDate(0, 1, -1)
|
|
|
+ dateList = append(dateList, currTime)
|
|
|
+ valueMap[currTime] = yearMonthMap[v]
|
|
|
+ }
|
|
|
+ case "旬度":
|
|
|
+ tmpDateDataMap := make(map[time.Time]float64)
|
|
|
+ tmpDateList := make([]time.Time, 0)
|
|
|
+ for _, item := range dataList {
|
|
|
+ itemDate := item.DataTime
|
|
|
+ dayInt := itemDate.Year()*100 + int(itemDate.Month())
|
|
|
+ var currTime time.Time
|
|
|
+ if itemDate.Month() <= 10 {
|
|
|
+ tmpK := fmt.Sprint(dayInt*100, "10")
|
|
|
+ currTime, err = time.ParseInLocation(utils.FormatDateUnSpace, tmpK, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if itemDate.Month() <= 20 {
|
|
|
+ tmpK := fmt.Sprint(dayInt*100, "20")
|
|
|
+ currTime, err = time.ParseInLocation(utils.FormatDateUnSpace, tmpK, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ currTime, err = time.ParseInLocation(utils.FormatYearMonthUnSpace, fmt.Sprint(dayInt), time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ currTime = currTime.AddDate(0, 1, -1)
|
|
|
+ }
|
|
|
+
|
|
|
+ yearVal, ok := tmpDateDataMap[currTime]
|
|
|
+ if ok {
|
|
|
+ tmpDateDataMap[currTime] = item.Value + yearVal
|
|
|
+ } else {
|
|
|
+ tmpDateList = append(tmpDateList, currTime)
|
|
|
+ tmpDateDataMap[currTime] = item.Value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, currTime := range tmpDateList {
|
|
|
+ dateList = append(dateList, currTime)
|
|
|
+ valueMap[currTime] = tmpDateDataMap[currTime]
|
|
|
+ }
|
|
|
+ case "周度":
|
|
|
+ tmpDateDataMap := make(map[time.Time]float64)
|
|
|
+ tmpDateList := make([]time.Time, 0)
|
|
|
+ for _, item := range dataList {
|
|
|
+ itemDate := item.DataTime
|
|
|
+ var currTime time.Time
|
|
|
+ // 周六周日,这是下一个周五的数据
|
|
|
+ if itemDate.Weekday() == 0 {
|
|
|
+ currTime = itemDate.AddDate(0, 0, 5)
|
|
|
+ } else if itemDate.Weekday() == 6 {
|
|
|
+ currTime = itemDate.AddDate(0, 0, 6)
|
|
|
+ } else {
|
|
|
+ currTime = itemDate.AddDate(0, 0, 5-int(itemDate.Weekday()))
|
|
|
+ }
|
|
|
+
|
|
|
+ yearVal, ok := tmpDateDataMap[currTime]
|
|
|
+ if ok {
|
|
|
+ tmpDateDataMap[currTime] = item.Value + yearVal
|
|
|
+ } else {
|
|
|
+ tmpDateList = append(tmpDateList, currTime)
|
|
|
+ tmpDateDataMap[currTime] = item.Value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, currTime := range tmpDateList {
|
|
|
+ dateList = append(dateList, currTime)
|
|
|
+ valueMap[currTime] = tmpDateDataMap[currTime]
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ err = errors.New("错误的频度")
|
|
|
+ return
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ for _, currTime := range dateList {
|
|
|
+ tmpVal, ok2 := valueMap[currTime]
|
|
|
+ if !ok2 {
|
|
|
+ err = errors.New("数据异常,date:" + currTime.Format(utils.FormatDate))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var saveValue float64
|
|
|
+ if isWeekData { //周度指标转的话,最后结果要除以7
|
|
|
+ saveValue, _ = decimal.NewFromFloat(tmpVal).Div(decimal.NewFromInt(7)).Round(4).Float64()
|
|
|
+ } else {
|
|
|
+ saveValue, _ = decimal.NewFromFloat(tmpVal).Round(4).Float64()
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[currTime] = saveValue
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// LjzNczj
|
|
|
+// @Description:年初至今累计值计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-03 13:55:44
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) LjzNczj() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+ frequency := obj.Frequency //需要变更的频度
|
|
|
+ fromFrequency := obj.FromFrequency //来源的频度
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+ var isWeekData bool // 是否周度数据,如果是周度数据的话,是需要变频的,最后结果还需要除以7
|
|
|
+ // 周度数据需要先变成日度的
|
|
|
+ if fromFrequency == `周度` {
|
|
|
+ isWeekData = true
|
|
|
+ }
|
|
|
+
|
|
|
+ fromEdbDataMap := make(map[time.Time]float64)
|
|
|
+ if isWeekData {
|
|
|
+ dataList, err = HandleDataByLinearRegressionByTime(dataList, fromEdbDataMap)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //日度数据年初至今:日期同原日度数据。将每年1月1日(含)到日度数据所在日期含间的日度值,进行加总。
|
|
|
+ //周度数据年初至今:日期同原周度数据。将周度值转成日度频率,空值用插值法插值,然后算法同日度年度至今,再除以7
|
|
|
+ //月度/季度数据年初至今:日期同原月度/季度数据,将每年1月1日(含)到月度数据所在日期(含)之间的月度/季度值,进行加总
|
|
|
+ //以此类推
|
|
|
+
|
|
|
+ dateList := make([]time.Time, 0)
|
|
|
+ valueMap := make(map[time.Time]float64)
|
|
|
+ yearMap := make(map[int]float64)
|
|
|
+ switch frequency {
|
|
|
+ case "周度":
|
|
|
+ tmpDateDataMap := make(map[time.Time]float64)
|
|
|
+ tmpDateList := make([]time.Time, 0)
|
|
|
+ for _, item := range dataList {
|
|
|
+ itemDate := item.DataTime
|
|
|
+ var currTime time.Time
|
|
|
+ // 周六周日,这是下一个周五的数据
|
|
|
+ if itemDate.Weekday() == 0 {
|
|
|
+ currTime = itemDate.AddDate(0, 0, 5)
|
|
|
+ } else if itemDate.Weekday() == 6 {
|
|
|
+ currTime = itemDate.AddDate(0, 0, 6)
|
|
|
+ } else {
|
|
|
+ currTime = itemDate.AddDate(0, 0, 5-int(itemDate.Weekday()))
|
|
|
+ }
|
|
|
+
|
|
|
+ year := itemDate.Year()
|
|
|
+ yearVal, ok := yearMap[year]
|
|
|
+ if ok {
|
|
|
+ yearMap[year] = item.Value + yearVal
|
|
|
+ } else {
|
|
|
+ yearMap[year] = item.Value
|
|
|
+ }
|
|
|
+
|
|
|
+ if itemDate.Equal(currTime) {
|
|
|
+ tmpDateDataMap[itemDate] = yearMap[year]
|
|
|
+ tmpDateList = append(tmpDateList, itemDate)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, currTime := range tmpDateList {
|
|
|
+ dateList = append(dateList, currTime)
|
|
|
+ valueMap[currTime] = tmpDateDataMap[currTime]
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ for _, item := range dataList {
|
|
|
+ itemDate := item.DataTime
|
|
|
+ year := itemDate.Year()
|
|
|
+ yearVal, ok := yearMap[year]
|
|
|
+ if ok {
|
|
|
+ yearMap[year] = item.Value + yearVal
|
|
|
+ } else {
|
|
|
+ yearMap[year] = item.Value
|
|
|
+ }
|
|
|
+ valueMap[itemDate] = yearMap[year]
|
|
|
+ dateList = append(dateList, itemDate)
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ for _, currTime := range dateList {
|
|
|
+ tmpVal, ok2 := valueMap[currTime]
|
|
|
+ if !ok2 {
|
|
|
+ err = errors.New("数据异常,date:" + currTime.Format(utils.FormatDate))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var saveValue float64
|
|
|
+ if isWeekData { //周度指标转的话,最后结果要除以7
|
|
|
+ saveValue, _ = decimal.NewFromFloat(tmpVal).Div(decimal.NewFromInt(7)).Round(4).Float64()
|
|
|
+ } else {
|
|
|
+ saveValue, _ = decimal.NewFromFloat(tmpVal).Round(4).Float64()
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[currTime] = saveValue
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// ExponentialSmoothing
|
|
|
+// @Description: 指数修匀计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-03 14:07:47
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) ExponentialSmoothing() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+ formula := obj.Formula.(string) // alpha值
|
|
|
+
|
|
|
+ alpha, _ := strconv.ParseFloat(formula, 64)
|
|
|
+ if alpha <= 0 || alpha >= 1 {
|
|
|
+ err = fmt.Errorf("alpha值有误: %v", alpha)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取标准差图表的指标数据
|
|
|
+ fromDataList, err := calculateExponentialSmoothingData(dataList, alpha)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ for _, tmpData := range fromDataList {
|
|
|
+ if tmpData.DataTime.IsZero() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ // 当前的实际值
|
|
|
+ saveValue, _ := decimal.NewFromFloat(tmpData.Value).Round(4).Float64()
|
|
|
+
|
|
|
+ dateDataMap[tmpData.DataTime] = saveValue
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// calculateExponentialSmoothingData
|
|
|
+// @Description: 计算指数修匀
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-03 14:05:41
|
|
|
+// @param dataList []*EdbInfoData 时间基准指标在时间区间内的值
|
|
|
+// @param strAlpha float64
|
|
|
+// @return newDataList []EdbInfoData
|
|
|
+// @return err error
|
|
|
+func calculateExponentialSmoothingData(dataList []*EdbInfoData, alpha float64) (newDataList []EdbInfoData, err error) {
|
|
|
+ if alpha <= 0 || alpha >= 1 {
|
|
|
+ err = fmt.Errorf("alpha值有误: %v", alpha)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var preVal float64
|
|
|
+ alphaDecimal := decimal.NewFromFloat(alpha)
|
|
|
+ subAlpha := decimal.NewFromFloat(1).Sub(alphaDecimal)
|
|
|
+ for k, d := range dataList {
|
|
|
+ // 首期的值以原始值作为指数修匀的计算值
|
|
|
+ if k == 0 {
|
|
|
+ newDataList = append(newDataList, EdbInfoData{
|
|
|
+ EdbDataId: k,
|
|
|
+ DataTime: dataList[k].DataTime,
|
|
|
+ Value: d.Value,
|
|
|
+ })
|
|
|
+ preVal = d.Value
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 上一期的值参与计算
|
|
|
+ preDecimal := decimal.NewFromFloat(preVal)
|
|
|
+ valDecimal := decimal.NewFromFloat(d.Value)
|
|
|
+
|
|
|
+ partA := alphaDecimal.Mul(valDecimal)
|
|
|
+ partB := subAlpha.Mul(preDecimal)
|
|
|
+ res, _ := (partA.Add(partB)).Float64()
|
|
|
+ preVal = res
|
|
|
+ newDataList = append(newDataList, EdbInfoData{
|
|
|
+ EdbDataId: k,
|
|
|
+ DataTime: dataList[k].DataTime,
|
|
|
+ Value: res,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Rjz
|
|
|
+// @Description: 日均值计算
|
|
|
+// @author: Roc
|
|
|
+// @receiver obj
|
|
|
+// @datetime2023-11-03 14:47:47
|
|
|
+// @return dateDataMap map[time.Time]float64
|
|
|
+// @return err error
|
|
|
+func (obj BaseCalculate) Rjz() (dateDataMap map[time.Time]float64, err error, errMsg string) {
|
|
|
+ dateDataMap = make(map[time.Time]float64)
|
|
|
+ dataList := obj.DataList
|
|
|
+
|
|
|
+ fromFrequency := obj.FromFrequency
|
|
|
+ if fromFrequency == `` {
|
|
|
+ errMsg = "原指标的频度不能为空"
|
|
|
+ err = errors.New(errMsg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if obj.FromFrequency == "日度" {
|
|
|
+ errMsg = "日度指标无需进行日均值计算"
|
|
|
+ err = errors.New(errMsg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据处理
|
|
|
+
|
|
|
+ // 数据降序
|
|
|
+ dataList = reverseSliceByDesc(dataList)
|
|
|
+
|
|
|
+ var dateArr []time.Time
|
|
|
+ dataMap := make(map[time.Time]*EdbInfoData)
|
|
|
+ for _, v := range dataList {
|
|
|
+ dateArr = append(dateArr, v.DataTime)
|
|
|
+ dataMap[v.DataTime] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据计算
|
|
|
+ for _, currentDate := range dateArr {
|
|
|
+ //当前日期
|
|
|
+ currentItem, ok := dataMap[currentDate]
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ //根据频度计算需要均分的天数
|
|
|
+ days := GetRjzFrequencyDays(currentDate, fromFrequency)
|
|
|
+ val, ok := rjzDivV2(currentItem.Value, days)
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ dateDataMap[currentDate] = val
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// rjzDivV2
|
|
|
+// @Description: 日均值计算
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-03 14:47:36
|
|
|
+// @param a float64
|
|
|
+// @param b int
|
|
|
+// @return val float64
|
|
|
+// @return ok bool
|
|
|
+func rjzDivV2(a float64, b int) (val float64, ok bool) {
|
|
|
+ if b == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ af := decimal.NewFromFloat(a)
|
|
|
+ bf := decimal.NewFromFloat(float64(b))
|
|
|
+ val, _ = af.Div(bf).Round(4).Float64()
|
|
|
+ ok = true
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// reverseSliceByDesc
|
|
|
+// @Description: 倒转切片
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-06 14:08:25
|
|
|
+// @param slice []*EdbInfoData
|
|
|
+// @return []*EdbInfoData
|
|
|
+func reverseSliceByDesc(slice []*EdbInfoData) (newSlice []*EdbInfoData) {
|
|
|
+ // 只有一个数据的话,那么就直接返回
|
|
|
+ if len(slice) <= 1 {
|
|
|
+ newSlice = slice
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if !slice[1].DataTime.After(slice[0].DataTime) {
|
|
|
+ newSlice = slice
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ newSlice = make([]*EdbInfoData, len(slice))
|
|
|
+ for i, j := 0, len(slice)-1; i < len(slice); i, j = i+1, j-1 {
|
|
|
+ newSlice[i] = slice[j]
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// EdbInfoSearchDataToData
|
|
|
+// @Description: 将EdbInfoSearchData转成EdbInfoData
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-09 11:11:31
|
|
|
+// @param dataList []*EdbInfoSearchData
|
|
|
+// @return newDateDataList []*EdbInfoData
|
|
|
+// @return err error
|
|
|
+func EdbInfoSearchDataToData(dataList []*EdbInfoSearchData) (newDateDataList []*EdbInfoData, err error) {
|
|
|
+ newDateDataList = make([]*EdbInfoData, 0)
|
|
|
+
|
|
|
+ for _, data := range dataList {
|
|
|
+ dateTime, tmpErr := time.ParseInLocation(utils.FormatDate, data.DataTime, time.Local)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ newDateDataList = append(newDateDataList, &EdbInfoData{
|
|
|
+ EdbDataId: data.EdbDataId,
|
|
|
+ DataTime: dateTime,
|
|
|
+ Value: data.Value,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetDateDataAndDateList
|
|
|
+// @Description: 通过时间数据map 获取 时间字符串数据map和日期字符串切片
|
|
|
+// @author: Roc
|
|
|
+// @datetime2023-11-09 13:10:38
|
|
|
+// @param dateDataMap map[time.Time]float64
|
|
|
+// @return dateStrDataMap map[string]float64
|
|
|
+// @return dateStrList []string
|
|
|
+func GetDateDataAndDateList(dateDataMap map[time.Time]float64) (dateStrDataMap map[string]float64, dateStrList []string) {
|
|
|
+ dateStrDataMap = make(map[string]float64)
|
|
|
+ dateStrList = make([]string, 0)
|
|
|
+ dateList := make([]time.Time, 0)
|
|
|
+ for date, val := range dateDataMap {
|
|
|
+ dateStr := date.Format(utils.FormatDate)
|
|
|
+ dateStrDataMap[dateStr] = val
|
|
|
+ dateList = append(dateList, date)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用 sort.Slice 对日期切片进行排序
|
|
|
+ sort.Slice(dateList, func(i, j int) bool {
|
|
|
+ return dateList[i].Before(dateList[j])
|
|
|
+ })
|
|
|
+
|
|
|
+ // 将日期排序后返回日期字符串切片
|
|
|
+ for _, v := range dateList {
|
|
|
+ dateStrList = append(dateStrList, v.Format(utils.FormatDate))
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|