predict_edb_info_rule.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. package data
  2. import (
  3. "github.com/shopspring/decimal"
  4. "hongze/hongze_chart_lib/models"
  5. "hongze/hongze_chart_lib/models/data_manage"
  6. "hongze/hongze_chart_lib/utils"
  7. "time"
  8. )
  9. // GetChartPredictEdbInfoDataListByRule1 根据规则1获取预测数据
  10. func GetChartPredictEdbInfoDataListByRule1(edbInfoId int, dataValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList) {
  11. newPredictEdbInfoData = predictEdbInfoData
  12. //获取后面的预测数据
  13. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  14. predictEdbInfoData = make([]*models.EdbDataList, 0)
  15. for k, v := range dayList {
  16. newPredictEdbInfoData = append(newPredictEdbInfoData, &models.EdbDataList{
  17. EdbDataId: edbInfoId + 10000000000 + k,
  18. EdbInfoId: edbInfoId,
  19. DataTime: v.Format(utils.FormatDate),
  20. Value: dataValue,
  21. DataTimestamp: (v.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
  22. })
  23. existMap[v.Format(utils.FormatDate)] = dataValue
  24. }
  25. return
  26. }
  27. // GetChartPredictEdbInfoDataListByRuleTb 根据同比值规则获取预测数据
  28. // 2.1 同比: 在未来某一个时间段内,给定一个固定的同比增速a,用去年同期值X乘以同比增速(1+a),得到预测值Y=X(1+a)
  29. // 例: 今年1-3月值,100,100,120。给定同比增速a=0.1,则明年1-3月预测值为: 100*1.1=110,100*1.1=110,120*1.1=132。
  30. func GetChartPredictEdbInfoDataListByRuleTb(edbInfoId int, tbValue float64, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
  31. allDataList := make([]*models.EdbDataList, 0)
  32. allDataList = append(allDataList, realPredictEdbInfoData...)
  33. allDataList = append(allDataList, predictEdbInfoData...)
  34. newPredictEdbInfoData = predictEdbInfoData
  35. index := len(allDataList)
  36. //获取后面的预测数据
  37. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  38. predictEdbInfoData = make([]*models.EdbDataList, 0)
  39. for k, currentDate := range dayList {
  40. tmpData := &models.EdbDataList{
  41. EdbDataId: edbInfoId + 10000000000 + index + k,
  42. EdbInfoId: edbInfoId,
  43. DataTime: currentDate.Format(utils.FormatDate),
  44. //Value: dataValue,
  45. DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
  46. }
  47. var val float64
  48. var calculateStatus bool //计算结果
  49. //currentItem := existMap[av]
  50. //上一年的日期
  51. preDate := currentDate.AddDate(-1, 0, 0)
  52. preDateStr := preDate.Format(utils.FormatDate)
  53. if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到
  54. val = TbzDiv(preValue, tbValue)
  55. calculateStatus = true
  56. } else {
  57. switch frequency {
  58. case "月度":
  59. //向上和向下,各找一个月
  60. nextDateDay := preDate
  61. preDateDay := preDate
  62. for i := 0; i <= 35; i++ {
  63. nextDateDayStr := nextDateDay.Format(utils.FormatDate)
  64. if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
  65. val = TbzDiv(preValue, tbValue)
  66. calculateStatus = true
  67. break
  68. } else {
  69. preDateDayStr := preDateDay.Format(utils.FormatDate)
  70. if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
  71. val = TbzDiv(preValue, tbValue)
  72. calculateStatus = true
  73. break
  74. }
  75. }
  76. nextDateDay = nextDateDay.AddDate(0, 0, 1)
  77. preDateDay = preDateDay.AddDate(0, 0, -1)
  78. }
  79. case "季度", "年度":
  80. if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到
  81. val = TbzDiv(preValue, tbValue)
  82. calculateStatus = true
  83. break
  84. }
  85. default:
  86. nextDateDay := preDate
  87. preDateDay := preDate
  88. for i := 0; i < 35; i++ {
  89. nextDateDayStr := nextDateDay.Format(utils.FormatDate)
  90. if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
  91. val = TbzDiv(preValue, tbValue)
  92. calculateStatus = true
  93. break
  94. } else {
  95. preDateDayStr := preDateDay.Format(utils.FormatDate)
  96. if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
  97. val = TbzDiv(preValue, tbValue)
  98. calculateStatus = true
  99. break
  100. } else {
  101. //fmt.Println("pre not find:", preDateStr, "i:", i)
  102. }
  103. }
  104. nextDateDay = nextDateDay.AddDate(0, 0, 1)
  105. preDateDay = preDateDay.AddDate(0, 0, -1)
  106. }
  107. }
  108. }
  109. if calculateStatus {
  110. tmpData.Value = val
  111. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  112. allDataList = append(allDataList, tmpData)
  113. existMap[tmpData.DataTime] = val
  114. // 最大最小值
  115. if val < minValue {
  116. minValue = val
  117. }
  118. if val > maxValue {
  119. maxValue = val
  120. }
  121. }
  122. }
  123. return
  124. }
  125. // TbzDiv 同比值计算
  126. // @params a float64 去年同期值
  127. // @params b float64 固定同比增速
  128. func TbzDiv(a, b float64) (result float64) {
  129. if b != 0 {
  130. // 去年同期值
  131. af := decimal.NewFromFloat(a)
  132. // 同比增速
  133. bf := decimal.NewFromFloat(b)
  134. // 默认1
  135. cf := decimal.NewFromFloat(1)
  136. // 总增速
  137. val := bf.Add(cf)
  138. // 计算
  139. result, _ = val.Mul(af).RoundCeil(4).Float64()
  140. } else {
  141. result = 0
  142. }
  143. return
  144. }
  145. // GetChartPredictEdbInfoDataListByRuleTc 根据同差值规则获取预测数据
  146. // 2.2 同差: 在未来某一个时间段内,给定一个固定的同比增加值a,用去年同期值X加上同比增加值A,得到预测值Y=X+a
  147. // 例: 今年1-3月值,100,100,120。给定同比增加值a=10,则明年1-3月预测值为: 100+10=110,100+10=110,120+10=130
  148. func GetChartPredictEdbInfoDataListByRuleTc(edbInfoId int, tcValue float64, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
  149. allDataList := make([]*models.EdbDataList, 0)
  150. allDataList = append(allDataList, realPredictEdbInfoData...)
  151. allDataList = append(allDataList, predictEdbInfoData...)
  152. newPredictEdbInfoData = predictEdbInfoData
  153. index := len(allDataList)
  154. //获取后面的预测数据
  155. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  156. predictEdbInfoData = make([]*models.EdbDataList, 0)
  157. for k, currentDate := range dayList {
  158. tmpData := &models.EdbDataList{
  159. EdbDataId: edbInfoId + 10000000000 + index + k,
  160. EdbInfoId: edbInfoId,
  161. DataTime: currentDate.Format(utils.FormatDate),
  162. //Value: dataValue,
  163. DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
  164. }
  165. var val float64
  166. var calculateStatus bool //计算结果
  167. //currentItem := existMap[av]
  168. //上一年的日期
  169. preDate := currentDate.AddDate(-1, 0, 0)
  170. preDateStr := preDate.Format(utils.FormatDate)
  171. if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到
  172. val = TczDiv(preValue, tcValue)
  173. calculateStatus = true
  174. } else {
  175. switch frequency {
  176. case "月度":
  177. //向上和向下,各找一个月
  178. nextDateDay := preDate
  179. preDateDay := preDate
  180. for i := 0; i <= 35; i++ {
  181. nextDateDayStr := nextDateDay.Format(utils.FormatDate)
  182. if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
  183. val = TczDiv(preValue, tcValue)
  184. calculateStatus = true
  185. break
  186. } else {
  187. preDateDayStr := preDateDay.Format(utils.FormatDate)
  188. if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
  189. val = TczDiv(preValue, tcValue)
  190. calculateStatus = true
  191. break
  192. }
  193. }
  194. nextDateDay = nextDateDay.AddDate(0, 0, 1)
  195. preDateDay = preDateDay.AddDate(0, 0, -1)
  196. }
  197. case "季度", "年度":
  198. if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到
  199. val = TczDiv(preValue, tcValue)
  200. calculateStatus = true
  201. break
  202. }
  203. default:
  204. nextDateDay := preDate
  205. preDateDay := preDate
  206. for i := 0; i < 35; i++ {
  207. nextDateDayStr := nextDateDay.Format(utils.FormatDate)
  208. if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
  209. val = TczDiv(preValue, tcValue)
  210. calculateStatus = true
  211. break
  212. } else {
  213. preDateDayStr := preDateDay.Format(utils.FormatDate)
  214. if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
  215. val = TczDiv(preValue, tcValue)
  216. calculateStatus = true
  217. break
  218. } else {
  219. //fmt.Println("pre not find:", preDateStr, "i:", i)
  220. }
  221. }
  222. nextDateDay = nextDateDay.AddDate(0, 0, 1)
  223. preDateDay = preDateDay.AddDate(0, 0, -1)
  224. }
  225. }
  226. }
  227. if calculateStatus {
  228. tmpData.Value = val
  229. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  230. allDataList = append(allDataList, tmpData)
  231. existMap[tmpData.DataTime] = val
  232. // 最大最小值
  233. if val < minValue {
  234. minValue = val
  235. }
  236. if val > maxValue {
  237. maxValue = val
  238. }
  239. }
  240. }
  241. return
  242. }
  243. // TczDiv 环差值计算
  244. // @params a float64 上一期值
  245. // @params b float64 固定的环比增加值
  246. func TczDiv(a, b float64) (result float64) {
  247. if b != 0 {
  248. // 上一期值
  249. af := decimal.NewFromFloat(a)
  250. // 固定的环比增加值
  251. bf := decimal.NewFromFloat(b)
  252. // 计算
  253. result, _ = af.Add(bf).RoundCeil(4).Float64()
  254. } else {
  255. result = 0
  256. }
  257. return
  258. }
  259. // GetChartPredictEdbInfoDataListByRuleHb 根据环比值规则获取预测数据
  260. // 环比:在未来某一个时间段内,给定一个固定的环比增速a,用上一期值X乘以环比增速(1+a),得到预测值Y=X(1+a)
  261. // 例: 最近1期值为100,给定环比增速a=0.2,则未来3期预测值为: 100*1.2=120,120*1.2=144,144*1.2=172.8
  262. func GetChartPredictEdbInfoDataListByRuleHb(edbInfoId int, hbValue float64, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
  263. allDataList := make([]*models.EdbDataList, 0)
  264. allDataList = append(allDataList, realPredictEdbInfoData...)
  265. allDataList = append(allDataList, predictEdbInfoData...)
  266. newPredictEdbInfoData = predictEdbInfoData
  267. index := len(allDataList)
  268. //获取后面的预测数据
  269. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  270. for k, currentDate := range dayList {
  271. tmpK := index + k - 1 //上1期的值
  272. // 环比值计算
  273. val := HbzDiv(allDataList[tmpK].Value, hbValue)
  274. currentDateStr := currentDate.Format(utils.FormatDate)
  275. tmpData := &models.EdbDataList{
  276. EdbDataId: edbInfoId + 10000000000 + index + k,
  277. EdbInfoId: edbInfoId,
  278. DataTime: currentDateStr,
  279. Value: val,
  280. DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
  281. }
  282. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  283. allDataList = append(allDataList, tmpData)
  284. existMap[currentDateStr] = val
  285. // 最大最小值
  286. if val < minValue {
  287. minValue = val
  288. }
  289. if val > maxValue {
  290. maxValue = val
  291. }
  292. }
  293. return
  294. }
  295. // HbzDiv 环比值计算
  296. // @params a float64 上一期值
  297. // @params b float64 固定的环比增速
  298. func HbzDiv(a, b float64) (result float64) {
  299. if b != 0 {
  300. // 上一期值
  301. af := decimal.NewFromFloat(a)
  302. // 固定的环比增速
  303. bf := decimal.NewFromFloat(b)
  304. // 默认1
  305. cf := decimal.NewFromFloat(1)
  306. // 总增速
  307. val := bf.Add(cf)
  308. // 计算
  309. result, _ = val.Mul(af).RoundCeil(4).Float64()
  310. } else {
  311. result = 0
  312. }
  313. return
  314. }
  315. // GetChartPredictEdbInfoDataListByRuleHc 根据环差值规则获取预测数据
  316. // 2.4 环差:在未来某一个时间段内,给定一个固定的环比增加值a,用上一期值X加上环比增加值a,得到预测值Y=X+a
  317. // 例: 最近1期值为100,给定环比增加值a=10,则未来3期预测值为: 100+10=110,110+10=120,120+10=130
  318. func GetChartPredictEdbInfoDataListByRuleHc(edbInfoId int, hcValue float64, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
  319. allDataList := make([]*models.EdbDataList, 0)
  320. allDataList = append(allDataList, realPredictEdbInfoData...)
  321. allDataList = append(allDataList, predictEdbInfoData...)
  322. newPredictEdbInfoData = predictEdbInfoData
  323. index := len(allDataList)
  324. //获取后面的预测数据
  325. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  326. for k, currentDate := range dayList {
  327. tmpK := index + k - 1 //上1期的值
  328. // 环差别值计算
  329. val := HczDiv(allDataList[tmpK].Value, hcValue)
  330. currentDateStr := currentDate.Format(utils.FormatDate)
  331. tmpData := &models.EdbDataList{
  332. EdbDataId: edbInfoId + 10000000000 + index + k,
  333. EdbInfoId: edbInfoId,
  334. DataTime: currentDateStr,
  335. Value: val,
  336. DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
  337. }
  338. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  339. allDataList = append(allDataList, tmpData)
  340. existMap[currentDateStr] = val
  341. // 最大最小值
  342. if val < minValue {
  343. minValue = val
  344. }
  345. if val > maxValue {
  346. maxValue = val
  347. }
  348. }
  349. return
  350. }
  351. // HczDiv 环差值计算
  352. // @params a float64 上一期值
  353. // @params b float64 固定的环比增加值
  354. func HczDiv(a, b float64) (result float64) {
  355. if b != 0 {
  356. // 上一期值
  357. af := decimal.NewFromFloat(a)
  358. // 固定的环比增加值
  359. bf := decimal.NewFromFloat(b)
  360. // 计算
  361. result, _ = af.Add(bf).RoundCeil(4).Float64()
  362. } else {
  363. result = 0
  364. }
  365. return
  366. }
  367. // GetChartPredictEdbInfoDataListByRuleNMoveMeanValue 根据N期移动均值规则获取预测数据
  368. // 2.5 N期移动均值:在未来某一个时间段内,下一期值等于过去N期值得平均值。
  369. // 例:最近3期值(N=3),为95,98,105则未来第1期值为 1/3*(95+98+105)=99.33, 未来第2期值为 1/3*(98+105+99.33)=100.78依次类推。
  370. func GetChartPredictEdbInfoDataListByRuleNMoveMeanValue(edbInfoId int, nValue int, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
  371. allDataList := make([]*models.EdbDataList, 0)
  372. allDataList = append(allDataList, realPredictEdbInfoData...)
  373. allDataList = append(allDataList, predictEdbInfoData...)
  374. newPredictEdbInfoData = predictEdbInfoData
  375. lenAllData := len(allDataList)
  376. if lenAllData < nValue || lenAllData <= 0 {
  377. return
  378. }
  379. if nValue <= 0 {
  380. return
  381. }
  382. // 分母
  383. decimalN := decimal.NewFromInt(int64(nValue))
  384. //获取后面的预测数据
  385. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  386. for k, currentDate := range dayList {
  387. tmpIndex := lenAllData + k - 1 //上1期的值
  388. // 数据集合中的最后一个数据
  389. tmpDecimalVal := decimal.NewFromFloat(allDataList[tmpIndex].Value)
  390. for tmpK := 2; tmpK <= nValue; tmpK++ {
  391. tmpIndex2 := tmpIndex - tmpK //上N期的值
  392. tmpDecimalVal2 := decimal.NewFromFloat(allDataList[tmpIndex2].Value)
  393. tmpDecimalVal = tmpDecimalVal.Add(tmpDecimalVal2)
  394. }
  395. // N期移动均值计算
  396. val, _ := tmpDecimalVal.Div(decimalN).RoundCeil(4).Float64()
  397. currentDateStr := currentDate.Format(utils.FormatDate)
  398. tmpData := &models.EdbDataList{
  399. EdbDataId: edbInfoId + 10000000000 + lenAllData + k,
  400. EdbInfoId: edbInfoId,
  401. DataTime: currentDateStr,
  402. Value: val,
  403. DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
  404. }
  405. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  406. allDataList = append(allDataList, tmpData)
  407. existMap[currentDateStr] = val
  408. // 最大最小值
  409. if val < minValue {
  410. minValue = val
  411. }
  412. if val > maxValue {
  413. maxValue = val
  414. }
  415. }
  416. return
  417. }
  418. // GetChartPredictEdbInfoDataListByRuleNLinearRegression 根据N期移动均值规则获取预测数据
  419. // 2.6N期段线性外推值:给出过去N期值所确定的线性回归方程(Y=aX+b)在未来一段时间内的推算值。回归方程虽然比较复杂,但各种编程语言应该都有现成的模块或函数,应该无需自己编写。
  420. // 例1:过去5期值(N=5)分别为:3,5,7,9,11(每两期值之间的时间间隔相等)。那么按照线性回归方程推算,未来三期的预测值是:13,15,17。
  421. //
  422. // 例2:过去6期值(N=6)分别为:3,3,5,7,9,11(每两期值之间的时间间隔相等)。那么按照线性回归方程推算,未来三期的预测值是:12.33,14.05,15.76。例1和例2的区别在于,多加了一期数据,导致回归方程发生改变,从而预测值不同。
  423. func GetChartPredictEdbInfoDataListByRuleNLinearRegression(edbInfoId int, nValue int, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
  424. //var errMsg string
  425. //defer func() {
  426. // if errMsg != `` {
  427. // go alarm_msg.SendAlarmMsg("更新上海的token失败;ERR:"+err.Error(), 3)
  428. // }
  429. //}()
  430. allDataList := make([]*models.EdbDataList, 0)
  431. allDataList = append(allDataList, realPredictEdbInfoData...)
  432. allDataList = append(allDataList, predictEdbInfoData...)
  433. newPredictEdbInfoData = predictEdbInfoData
  434. lenAllData := len(allDataList)
  435. if lenAllData < nValue || lenAllData <= 0 {
  436. return
  437. }
  438. if nValue <= 1 {
  439. return
  440. }
  441. //获取后面的预测数据
  442. // 获取线性方程公式的a、b的值
  443. coordinateData := make([]Coordinate, 0)
  444. for tmpK := nValue; tmpK > 0; tmpK-- {
  445. tmpIndex2 := lenAllData - tmpK //上N期的值
  446. tmpCoordinate := Coordinate{
  447. X: float64(nValue - tmpK + 1),
  448. Y: allDataList[tmpIndex2].Value,
  449. }
  450. coordinateData = append(coordinateData, tmpCoordinate)
  451. }
  452. a, b := getLinearResult(coordinateData)
  453. //fmt.Println("a:", a, ";======b:", b)
  454. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  455. for k, currentDate := range dayList {
  456. tmpK := nValue + k + 1
  457. aDecimal := decimal.NewFromFloat(a)
  458. xDecimal := decimal.NewFromInt(int64(tmpK))
  459. bDecimal := decimal.NewFromFloat(b)
  460. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).RoundCeil(4).Float64()
  461. currentDateStr := currentDate.Format(utils.FormatDate)
  462. tmpData := &models.EdbDataList{
  463. EdbDataId: edbInfoId + 10000000000 + lenAllData + k,
  464. EdbInfoId: edbInfoId,
  465. DataTime: currentDateStr,
  466. Value: val,
  467. DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
  468. }
  469. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  470. allDataList = append(allDataList, tmpData)
  471. existMap[currentDateStr] = val
  472. // 最大最小值
  473. if val < minValue {
  474. minValue = val
  475. }
  476. if val > maxValue {
  477. maxValue = val
  478. }
  479. }
  480. return
  481. }
  482. // Series is a container for a series of data
  483. type Series []Coordinate
  484. // Coordinate holds the data in a series
  485. type Coordinate struct {
  486. X, Y float64
  487. }
  488. func getLinearResult(s []Coordinate) (gradient, intercept float64) {
  489. if len(s) <= 1 {
  490. return
  491. }
  492. // Placeholder for the math to be done
  493. var sum [5]float64
  494. // Loop over data keeping index in place
  495. i := 0
  496. for ; i < len(s); i++ {
  497. sum[0] += s[i].X
  498. sum[1] += s[i].Y
  499. sum[2] += s[i].X * s[i].X
  500. sum[3] += s[i].X * s[i].Y
  501. sum[4] += s[i].Y * s[i].Y
  502. }
  503. // Find gradient and intercept
  504. f := float64(i)
  505. gradient = (f*sum[3] - sum[0]*sum[1]) / (f*sum[2] - sum[0]*sum[0])
  506. intercept = (sum[1] / f) - (gradient * sum[0] / f)
  507. //fmt.Println("gradient:", gradient, ";intercept:", intercept)
  508. // Create the new regression series
  509. //for j := 0; j < len(s); j++ {
  510. // regressions = append(regressions, Coordinate{
  511. // X: s[j].X,
  512. // Y: s[j].X*gradient + intercept,
  513. // })
  514. //}
  515. return
  516. }
  517. // GetChartPredictEdbInfoDataListByRuleTrendsHC 根据动态环比增加值的计算规则获取预测数据
  518. // 研究员有对预测指标进行动态环差计算的需求,即预测指标使用环差规则进行预测时,环比增加值不是固定值,而是由几个预测指标计算得出的动态变化的值;
  519. //需求说明:
  520. //1、增加“动态环差”预测规则;
  521. //2、环比增加值在弹窗设置;
  522. //3、动态环差预测举例:
  523. //指标A实际最新数据为2022-10-27(100);
  524. //预测指标B预测数据为2022-10-28(240)、2022-10-29(300);
  525. //预测指标C预测数据为2022-10-28(260)、2022-10-29(310);
  526. //计算公式为B-C;
  527. //则指标A至2022-10-29的预测值为2022-10-28(100+(240-260)=80)、2022-10-29(80+(300-310)=90);
  528. //注:动态环比增加值的计算遵从计算指标的计算规则,即用于计算的指标若有部分指标缺少部分日期数据,则这部分日期数据不做计算,为空;若动态环比增加值某一天为空,则往前追溯最近一期有值的环比增加值作为该天的数值参与计算;
  529. func GetChartPredictEdbInfoDataListByRuleTrendsHC(edbInfoId, configId int, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
  530. allDataList := make([]*models.EdbDataList, 0)
  531. allDataList = append(allDataList, realPredictEdbInfoData...)
  532. allDataList = append(allDataList, predictEdbInfoData...)
  533. newPredictEdbInfoData = predictEdbInfoData
  534. lenAllData := len(allDataList)
  535. if lenAllData <= 0 {
  536. return
  537. }
  538. hcDataMap := make(map[string]float64) //规则计算的环差值map
  539. //已经生成的动态数据
  540. tmpPredictEdbRuleDataList, err := data_manage.GetPredictEdbRuleDataList(edbInfoId, configId, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
  541. if err != nil {
  542. return
  543. }
  544. for _, v := range tmpPredictEdbRuleDataList {
  545. hcDataMap[v.DataTime] = v.Value
  546. }
  547. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  548. for k, currentDate := range dayList {
  549. // 最近一条数据
  550. tmpLenAllDataList := len(allDataList)
  551. lastValue := allDataList[tmpLenAllDataList-1].Value
  552. // 动态环差值数据
  553. currentDateStr := currentDate.Format(utils.FormatDate)
  554. hcVal, ok := hcDataMap[currentDateStr]
  555. if !ok {
  556. continue
  557. }
  558. lastValueDecimal := decimal.NewFromFloat(lastValue)
  559. hcValDecimal := decimal.NewFromFloat(hcVal)
  560. val, _ := lastValueDecimal.Add(hcValDecimal).RoundCeil(4).Float64()
  561. tmpData := &models.EdbDataList{
  562. EdbDataId: edbInfoId + 10000000000 + lenAllData + k,
  563. EdbInfoId: edbInfoId,
  564. DataTime: currentDateStr,
  565. Value: val,
  566. DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
  567. }
  568. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  569. allDataList = append(allDataList, tmpData)
  570. existMap[currentDateStr] = val
  571. // 最大最小值
  572. if val < minValue {
  573. minValue = val
  574. }
  575. if val > maxValue {
  576. maxValue = val
  577. }
  578. }
  579. return
  580. }