ai_predict_model_index.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. package services
  2. import (
  3. "encoding/json"
  4. aiPredictModel "eta/eta_api/models/ai_predict_model"
  5. "eta/eta_api/models/data_manage"
  6. "eta/eta_api/services/data"
  7. "eta/eta_api/utils"
  8. "fmt"
  9. "sort"
  10. "strconv"
  11. "time"
  12. )
  13. func ImportAiPredictModelIndexAndData(imports []*aiPredictModel.AiPredictModelImportData, adminId int, adminRealName string) (err error) {
  14. if len(imports) == 0 {
  15. return
  16. }
  17. // 查询已存在的标的
  18. indexOb := new(aiPredictModel.AiPredictModelIndex)
  19. indexNameItem := make(map[string]*aiPredictModel.AiPredictModelIndex)
  20. {
  21. list, e := indexOb.GetItemsByCondition("", make([]interface{}, 0), []string{}, "")
  22. if e != nil {
  23. err = fmt.Errorf("获取标的失败, %v", e)
  24. return
  25. }
  26. for _, v := range list {
  27. indexNameItem[v.IndexName] = v
  28. }
  29. }
  30. updateCols := []string{indexOb.Cols().ClassifyId, indexOb.Cols().ModelFramework, indexOb.Cols().PredictDate, indexOb.Cols().PredictValue, indexOb.Cols().DirectionAccuracy, indexOb.Cols().AbsoluteDeviation, indexOb.Cols().ExtraConfig, indexOb.Cols().SysUserId, indexOb.Cols().SysUserRealName, indexOb.Cols().ModifyTime}
  31. updateIndexes := make([]*aiPredictModel.AiPredictModelImportData, 0)
  32. createIndexes := make([]*aiPredictModel.AiPredictModelImportData, 0)
  33. maxSort, err := indexOb.GetSortMax()
  34. if err != nil {
  35. err = fmt.Errorf("获取标的最大排序失败, %v", err)
  36. return
  37. }
  38. for _, v := range imports {
  39. exist := indexNameItem[v.Index.IndexName]
  40. // 编辑
  41. if exist != nil {
  42. // 图例信息
  43. if exist.ExtraConfig != "" && v.Index.ExtraConfig != "" {
  44. var oldConfig, newConfig aiPredictModel.AiPredictModelIndexExtraConfig
  45. if e := json.Unmarshal([]byte(exist.ExtraConfig), &oldConfig); e != nil {
  46. err = fmt.Errorf("标的原配置解析失败, Config: %s, Err: %v", exist.ExtraConfig, e)
  47. return
  48. }
  49. if e := json.Unmarshal([]byte(v.Index.ExtraConfig), &newConfig); e != nil {
  50. err = fmt.Errorf("标的新配置解析失败, Config: %s, Err: %v", v.Index.ExtraConfig, e)
  51. return
  52. }
  53. oldConfig.DailyChart.PredictLegendName = newConfig.DailyChart.PredictLegendName
  54. b, _ := json.Marshal(oldConfig)
  55. v.Index.ExtraConfig = string(b)
  56. }
  57. v.Index.AiPredictModelIndexId = exist.AiPredictModelIndexId
  58. v.Index.IndexCode = exist.IndexCode
  59. updateIndexes = append(updateIndexes, v)
  60. continue
  61. }
  62. // 新增标的/图表
  63. indexCode, e := utils.GenerateEdbCode(1, "IPM")
  64. if e != nil {
  65. err = fmt.Errorf("生成标的编码失败, %v", e)
  66. return
  67. }
  68. v.Index.IndexCode = indexCode
  69. v.Charts = GetAiPredictCharts(v.Index.IndexName, adminId, adminRealName)
  70. maxSort = maxSort + 1
  71. v.Index.Sort = maxSort
  72. createIndexes = append(createIndexes, v)
  73. }
  74. // 新增/更新指标
  75. chartIds, e := indexOb.ImportIndexAndData(createIndexes, updateIndexes, updateCols)
  76. if e != nil {
  77. err = fmt.Errorf("导入指标失败, %v", e)
  78. return
  79. }
  80. // 更新图表ES
  81. if len(chartIds) == 0 {
  82. return
  83. }
  84. go func() {
  85. for _, v := range chartIds {
  86. data.EsAddOrEditChartInfo(v)
  87. }
  88. }()
  89. return
  90. }
  91. func GetAiPredictChartDetailByData(indexItem *aiPredictModel.AiPredictModelIndex, indexData []*aiPredictModel.AiPredictModelData, source int) (resp *data_manage.ChartInfoDetailResp, err error) {
  92. resp = new(data_manage.ChartInfoDetailResp)
  93. // 标的配置
  94. var extraConfig aiPredictModel.AiPredictModelIndexExtraConfig
  95. if indexItem.ExtraConfig != "" {
  96. if e := json.Unmarshal([]byte(indexItem.ExtraConfig), &extraConfig); e != nil {
  97. err = fmt.Errorf("标的额外配置解析失败, Config: %s, Err: %v", indexItem.ExtraConfig, e)
  98. return
  99. }
  100. }
  101. // 图表信息
  102. var predictLegendName, confLeftMin, confLeftMax, unit string
  103. if source == aiPredictModel.ModelDataSourceDaily {
  104. predictLegendName = extraConfig.DailyChart.PredictLegendName
  105. if predictLegendName == "" {
  106. predictLegendName = "Predicted"
  107. }
  108. unit = extraConfig.DailyChart.Unit
  109. confLeftMin = extraConfig.DailyChart.LeftMin
  110. confLeftMax = extraConfig.DailyChart.LeftMax
  111. }
  112. if source == aiPredictModel.ModelDataSourceMonthly {
  113. predictLegendName = "预测值"
  114. unit = extraConfig.MonthlyChart.Unit
  115. confLeftMin = extraConfig.MonthlyChart.LeftMin
  116. confLeftMax = extraConfig.MonthlyChart.LeftMax
  117. }
  118. // 这里简单兼容下吧,暂时就不修数据了
  119. if confLeftMin == "" {
  120. confLeftMin = indexItem.LeftMin
  121. }
  122. if confLeftMax == "" {
  123. confLeftMax = indexItem.LeftMax
  124. }
  125. // 获取指标对应的图表
  126. chartSourceMapping := map[int]int{
  127. aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY,
  128. aiPredictModel.ModelDataSourceDaily: utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY,
  129. }
  130. chartInfo, e := data_manage.GetAiPredictChartInfoByIndexId(chartSourceMapping[source], indexItem.AiPredictModelIndexId)
  131. if e != nil && !utils.IsErrNoRow(e) {
  132. err = fmt.Errorf("获取标的图表失败, %v", e)
  133. return
  134. }
  135. // 获取曲线图主题样式
  136. chartView := new(data_manage.ChartInfoView)
  137. if chartInfo != nil && chartInfo.ChartInfoId > 0 {
  138. chartView.ChartInfoId = chartInfo.ChartInfoId
  139. chartView.ChartName = chartInfo.ChartName
  140. chartView.ChartNameEn = chartInfo.ChartNameEn
  141. chartView.Source = chartInfo.Source
  142. chartView.ChartImage = chartInfo.ChartImage
  143. chartView.HaveOperaAuth = true
  144. chartView.UniqueCode = chartInfo.UniqueCode
  145. chartView.ChartSource = "AI预测模型"
  146. chartView.ChartSourceEn = "AI预测模型"
  147. chartView.SysUserId = chartInfo.SysUserId
  148. chartView.SysUserRealName = chartInfo.SysUserRealName
  149. } else {
  150. chartView.ChartName = indexItem.IndexName
  151. chartView.ChartNameEn = indexItem.IndexName
  152. }
  153. chartView.ChartType = utils.CHART_SOURCE_DEFAULT
  154. chartTheme, e := data.GetChartThemeConfig(0, chartView.ChartType, utils.CHART_TYPE_CURVE)
  155. if e != nil {
  156. err = fmt.Errorf("获取图表主题样式失败, %v", e)
  157. return
  158. }
  159. chartView.ChartThemeStyle = chartTheme.Config
  160. chartView.ChartThemeId = chartTheme.ChartThemeId
  161. chartView.ChartName = indexItem.IndexName
  162. chartView.ChartNameEn = indexItem.IndexName
  163. chartView.DateType = 3
  164. chartView.Calendar = "公历"
  165. chartView.ChartSource = "AI预测模型"
  166. chartView.ChartSourceEn = "AI预测模型"
  167. chartView.Unit = unit
  168. chartView.UnitEn = unit
  169. // EdbList-固定一条为标的实际值、一条为预测值
  170. edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
  171. edbActual, edbPredict := new(data_manage.ChartEdbInfoMapping), new(data_manage.ChartEdbInfoMapping)
  172. edbActual.EdbName = indexItem.IndexName
  173. edbActual.EdbNameEn = indexItem.IndexName
  174. edbActual.IsAxis = 1
  175. edbActual.Unit = unit
  176. edbActual.UnitEn = unit
  177. edbPredict.EdbName = predictLegendName
  178. edbPredict.EdbNameEn = predictLegendName
  179. edbPredict.IsAxis = 1
  180. edbPredict.Unit = unit
  181. edbPredict.UnitEn = unit
  182. actualData, predictData := make([]*data_manage.EdbDataList, 0), make([]*data_manage.EdbDataList, 0)
  183. var startDate, endDate time.Time
  184. var actualValues, predictValues []float64
  185. var actualNewest, predictNewest bool
  186. var actualLatestTimestamp int64 // 实际值最后一天的时间戳,作为日度图表的分割线
  187. for k, v := range indexData {
  188. // 如果实际值和预测值都是null那么该日期无效直接忽略
  189. if !v.Value.Valid && !v.PredictValue.Valid {
  190. continue
  191. }
  192. // 将有效值加入[]float64,最后取极值
  193. if v.Value.Valid {
  194. actualValues = append(actualValues, v.Value.Float64)
  195. }
  196. if v.PredictValue.Valid {
  197. predictValues = append(predictValues, v.PredictValue.Float64)
  198. }
  199. // 开始结束时间
  200. if k == 0 {
  201. startDate = v.DataTime
  202. endDate = v.CreateTime
  203. }
  204. if v.DataTime.Before(startDate) {
  205. startDate = v.DataTime
  206. }
  207. if v.DataTime.After(endDate) {
  208. endDate = v.DataTime
  209. }
  210. // 指标数据
  211. if v.Value.Valid {
  212. if !actualNewest {
  213. edbActual.LatestDate = v.DataTime.Format(utils.FormatDate)
  214. edbActual.LatestValue = v.Value.Float64
  215. actualLatestTimestamp = v.DataTime.UnixNano() / 1e6
  216. actualNewest = true
  217. }
  218. actualData = append(actualData, &data_manage.EdbDataList{
  219. DataTime: v.DataTime.Format(utils.FormatDate),
  220. Value: v.Value.Float64,
  221. DataTimestamp: v.DataTimestamp,
  222. })
  223. }
  224. if v.PredictValue.Valid {
  225. if !predictNewest {
  226. edbPredict.LatestDate = v.DataTime.Format(utils.FormatDate)
  227. edbPredict.LatestValue = v.Value.Float64
  228. predictNewest = true
  229. }
  230. predictData = append(predictData, &data_manage.EdbDataList{
  231. DataTime: v.DataTime.Format(utils.FormatDate),
  232. Value: v.PredictValue.Float64,
  233. DataTimestamp: v.DataTimestamp,
  234. })
  235. }
  236. }
  237. // 图表数据这里均做一个升序排序
  238. sort.Slice(actualData, func(i, j int) bool {
  239. return actualData[i].DataTimestamp < actualData[j].DataTimestamp
  240. })
  241. sort.Slice(predictData, func(i, j int) bool {
  242. return predictData[i].DataTimestamp < predictData[j].DataTimestamp
  243. })
  244. // 极值
  245. actualMin, actualMax := utils.FindMinMax(actualValues)
  246. predictMin, predictMax := utils.FindMinMax(predictValues)
  247. edbActual.MinData = actualMin
  248. edbActual.MaxData = actualMax
  249. edbPredict.MinData = predictMin
  250. edbPredict.MaxData = predictMax
  251. edbActual.DataList = actualData
  252. edbPredict.DataList = predictData
  253. edbList = append(edbList, edbActual, edbPredict)
  254. // 上下限
  255. if confLeftMin != "" {
  256. chartView.LeftMin = confLeftMin
  257. } else {
  258. leftMin := actualMin
  259. if leftMin > predictMin {
  260. leftMin = predictMin
  261. }
  262. chartView.LeftMin = fmt.Sprint(leftMin)
  263. }
  264. if confLeftMax != "" {
  265. chartView.LeftMax = confLeftMax
  266. } else {
  267. leftMax := actualMax
  268. if leftMax < predictMax {
  269. leftMax = predictMax
  270. }
  271. chartView.LeftMax = fmt.Sprint(leftMax)
  272. }
  273. chartView.StartDate = startDate.Format(utils.FormatDate)
  274. chartView.EndDate = endDate.Format(utils.FormatDate)
  275. // 日度图表的分割线日期
  276. if source == aiPredictModel.ModelDataSourceDaily {
  277. var dataResp struct {
  278. ActualLatestTimestamp int64
  279. }
  280. dataResp.ActualLatestTimestamp = actualLatestTimestamp
  281. resp.DataResp = dataResp
  282. }
  283. resp.ChartInfo = chartView
  284. resp.EdbInfoList = edbList
  285. // 此处返回标的ID,我的图表-编辑按钮需要通过标的ID跳至标的编辑页=_=!
  286. type dataResp struct {
  287. AiPredictModelIndexId int
  288. }
  289. resp.DataResp = &dataResp{AiPredictModelIndexId: indexItem.AiPredictModelIndexId}
  290. return
  291. }
  292. // GetAiPredictCharts 获取AI预测模型图表
  293. func GetAiPredictCharts(indexName string, adminId int, adminRealName string) (charts []*aiPredictModel.AiPredictModelImportCharts) {
  294. charts = make([]*aiPredictModel.AiPredictModelImportCharts, 0)
  295. // 日度/月度图表
  296. frequencyArr := []int{aiPredictModel.ModelDataSourceMonthly, aiPredictModel.ModelDataSourceDaily}
  297. sourceMapping := map[int]int{
  298. aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY,
  299. aiPredictModel.ModelDataSourceDaily: utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY,
  300. }
  301. suffixNameMapping := map[int]string{
  302. aiPredictModel.ModelDataSourceMonthly: "预测模型/回测",
  303. aiPredictModel.ModelDataSourceDaily: "预测模型",
  304. }
  305. for _, v := range frequencyArr {
  306. chartSource := sourceMapping[v]
  307. newChart := new(aiPredictModel.AiPredictModelImportCharts)
  308. // 新增图表
  309. chartName := fmt.Sprintf("%s%s", indexName, suffixNameMapping[v])
  310. chartInfo := new(data_manage.ChartInfo)
  311. chartInfo.ChartName = chartName
  312. chartInfo.ChartNameEn = chartName
  313. chartInfo.ChartType = utils.CHART_TYPE_CURVE
  314. chartInfo.Calendar = "公历"
  315. chartInfo.SysUserId = adminId
  316. chartInfo.SysUserRealName = adminRealName
  317. chartInfo.CreateTime = time.Now()
  318. chartInfo.ModifyTime = time.Now()
  319. chartInfo.Source = chartSource
  320. time.Sleep(time.Microsecond)
  321. chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10))
  322. newChart.ChartInfo = chartInfo
  323. // chart_edb_mapping中edb_info_id为标的ID
  324. edbMapping := new(data_manage.ChartEdbMapping)
  325. //edbMapping.EdbInfoId = indexId
  326. //edbMapping.UniqueCode = utils.MD5(fmt.Sprint(utils.CHART_PREFIX, "_", indexId, "_", strconv.FormatInt(time.Now().UnixNano(), 10)))
  327. edbMapping.Source = chartSource
  328. edbMapping.CreateTime = time.Now().Local()
  329. edbMapping.ModifyTime = time.Now().Local()
  330. newChart.EdbMappings = append(newChart.EdbMappings, edbMapping)
  331. charts = append(charts, newChart)
  332. }
  333. return
  334. }
  335. // FixAiPredictCharts 修复AI预测模型图表
  336. func FixAiPredictCharts() {
  337. var err error
  338. defer func() {
  339. if err != nil {
  340. fmt.Println(err)
  341. }
  342. fmt.Println("修复完成")
  343. }()
  344. fmt.Println("开始修复")
  345. indexOb := new(aiPredictModel.AiPredictModelIndex)
  346. indexes, e := indexOb.GetItemsByCondition("", make([]interface{}, 0), []string{}, "")
  347. if e != nil {
  348. err = fmt.Errorf("获取所有标的失败, %v", e)
  349. return
  350. }
  351. // 日度/月度图表
  352. frequencyArr := []int{aiPredictModel.ModelDataSourceMonthly, aiPredictModel.ModelDataSourceDaily}
  353. sourceMapping := map[int]int{
  354. aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY,
  355. aiPredictModel.ModelDataSourceDaily: utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY,
  356. }
  357. suffixNameMapping := map[int]string{
  358. aiPredictModel.ModelDataSourceMonthly: "预测模型/回测",
  359. aiPredictModel.ModelDataSourceDaily: "预测模型",
  360. }
  361. chartOb := new(data_manage.ChartInfo)
  362. for _, v := range indexes {
  363. for _, fre := range frequencyArr {
  364. chartSource := sourceMapping[fre]
  365. item, e := data_manage.GetAiPredictChartInfoByIndexId(chartSource, v.AiPredictModelIndexId)
  366. if e != nil && !utils.IsErrNoRow(e) {
  367. err = fmt.Errorf("获取AI预测模型图表失败, %v", e)
  368. return
  369. }
  370. // 由于标的名称是固定的所以chart_info没有什么可更新的, 已加入过就忽略
  371. if item != nil && item.ChartInfoId > 0 {
  372. fmt.Printf("标的%d-%d图表已存在, continue\n", v.AiPredictModelIndexId, chartSource)
  373. continue
  374. }
  375. // 新增图表
  376. chartName := fmt.Sprintf("%s%s", v.IndexName, suffixNameMapping[fre])
  377. chartInfo := new(data_manage.ChartInfo)
  378. chartInfo.ChartName = chartName
  379. chartInfo.ChartNameEn = chartName
  380. chartInfo.ChartType = utils.CHART_TYPE_CURVE
  381. chartInfo.Calendar = "公历"
  382. chartInfo.SysUserId = v.SysUserId
  383. chartInfo.SysUserRealName = v.SysUserRealName
  384. chartInfo.CreateTime = time.Now()
  385. chartInfo.ModifyTime = time.Now()
  386. chartInfo.Source = chartSource
  387. time.Sleep(time.Microsecond)
  388. chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10))
  389. // chart_edb_mapping中edb_info_id为标的ID
  390. mappings := make([]*data_manage.ChartEdbMapping, 0)
  391. edbMapping := new(data_manage.ChartEdbMapping)
  392. edbMapping.EdbInfoId = v.AiPredictModelIndexId
  393. edbMapping.UniqueCode = utils.MD5(fmt.Sprint(utils.CHART_PREFIX, "_", v.AiPredictModelIndexId, "_", strconv.FormatInt(time.Now().UnixNano(), 10)))
  394. edbMapping.Source = chartSource
  395. edbMapping.CreateTime = time.Now().Local()
  396. edbMapping.ModifyTime = time.Now().Local()
  397. mappings = append(mappings, edbMapping)
  398. // 新增图表
  399. if e = chartOb.AddChartInfoAndEdbMappings(chartInfo, mappings); e != nil {
  400. err = fmt.Errorf("新增图表及mapping失败, %v", e)
  401. return
  402. }
  403. // 写入ES
  404. if chartInfo.ChartInfoId <= 0 {
  405. err = fmt.Errorf("图表ID有误")
  406. return
  407. }
  408. go data.EsAddOrEditChartInfo(chartInfo.ChartInfoId)
  409. }
  410. }
  411. return
  412. }