profit_chart_info.go 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988
  1. package logic
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "eta/eta_index_lib/models"
  6. "eta/eta_index_lib/models/future_good"
  7. "eta/eta_index_lib/utils"
  8. "fmt"
  9. "github.com/dengsgo/math-engine/engine"
  10. "github.com/shopspring/decimal"
  11. "sort"
  12. "strconv"
  13. "strings"
  14. "time"
  15. )
  16. // ChartInfoDateReq 图表的日期数据(日期相关)
  17. type ChartInfoDateReq struct {
  18. Type int `description:"配置类型"`
  19. Date string `description:"固定日期"`
  20. Value int `description:"N天的值"`
  21. Color string `description:"颜色"`
  22. Name string `description:"别名"`
  23. }
  24. // SectionScatterReq 截面散点请求
  25. type SectionScatterReq struct {
  26. XName string `description:"x轴名称"`
  27. XNameEn string `description:"x轴名称(英文)"`
  28. XUnitName string `description:"x轴单位名称"`
  29. XUnitNameEn string `description:"x轴单位名称(英文)"`
  30. YName string `description:"y轴名称"`
  31. YNameEn string `description:"y轴名称(英文)"`
  32. YUnitName string `description:"y轴单位名称"`
  33. YUnitNameEn string `description:"y轴单位名称(英文)"`
  34. XMinValue string `description:"X轴的最小值"`
  35. XMaxValue string `description:"X轴的最大值"`
  36. YMinValue string `description:"Y轴的最小值"`
  37. YMaxValue string `description:"Y轴的最大值"`
  38. //EdbList []SectionScatterEdbItemReq `description:"指标数据"`
  39. SeriesList []SectionScatterSeriesItemReq `description:"系列数据"`
  40. }
  41. // SectionScatterSeriesItemReq 系列的请求
  42. type SectionScatterSeriesItemReq struct {
  43. Name string `description:"系列名"`
  44. NameEn string `description:"系列名(英文名)"`
  45. Color string `description:"颜色"`
  46. EdbInfoList []SectionScatterEdbItemReq
  47. ShowTrendLine bool `description:"是否展示趋势线"`
  48. ShowFitEquation bool `description:"是否展示方程式"`
  49. ShowRSquare bool `description:"是否展示R平方"`
  50. }
  51. // SectionScatterEdbItemReq 截面散点请求的指标
  52. type SectionScatterEdbItemReq struct {
  53. XEdbInfoId int `description:"X轴的指标ID"`
  54. YEdbInfoId int `description:"Y轴的指标ID"`
  55. Name string `description:"别名"`
  56. NameEn string `description:"英文别名"`
  57. XDateType int `description:"X轴的日期配置类型"`
  58. XDate string `description:"X轴的日期固定日期"`
  59. XDateValue int `description:"X轴的日期N天的值"`
  60. YDateType int `description:"Y轴的日期配置类型"`
  61. YDate string `description:"Y轴的日期固定日期"`
  62. YDateValue int `description:"Y轴的日期N天的值"`
  63. IsShow bool `description:"是否展示"`
  64. }
  65. // XData 商品价格曲线的的x轴数据
  66. type XData struct {
  67. Name string `description:"别名"`
  68. NameEn string `description:"英文别名"`
  69. }
  70. // YData 柱方图的y轴数据
  71. type YData struct {
  72. Date string `description:"数据日期"`
  73. ConfigDate time.Time `description:"配置的日期" json:"-"`
  74. Color string `description:"数据颜色"`
  75. Name string `description:"别名"`
  76. NameEn string `description:"英文别名"`
  77. Value []float64 `description:"每个指标的值"`
  78. NoDataEdbList []int `description:"没有数据的指标列表"`
  79. XEdbInfoIdList []int `description:"对应X轴的指标id列表"`
  80. NameList []string `description:"每个值对应的名称"`
  81. EnNameList []string `description:"每个值对应的英文名称"`
  82. EdbValMap map[int]float64 `description:"指标与值的对应" json:"-"`
  83. M []int `description:"对应开始日期的间隔值" json:"-"`
  84. }
  85. // BarChartInfoEdbItemReq 柱方图预览请求数据(指标相关)
  86. type BarChartInfoEdbItemReq struct {
  87. EdbInfoId int `description:"指标ID"`
  88. Name string `description:"别名"`
  89. NameEn string `description:"英文别名"`
  90. Source int `description:"1:ETA图库;2:商品价格"`
  91. }
  92. // ChartInfoReq 图表预览请求数据
  93. type ChartInfoReq struct {
  94. FutureGoodEdbInfoIdList []models.EdbInfoFromTag `description:"指标信息"`
  95. CalculateFormula string `description:"计算公式"`
  96. BaseEdbInfoId int `description:"基础的指标id"`
  97. DateList []ChartInfoDateReq `description:"日期配置"`
  98. ProfitNameEn string `description:"利润英文名称"`
  99. EdbInfoIdList []int `description:"现货指标ID列表"`
  100. XDataList []XData `description:"横轴配置"`
  101. }
  102. // RefreshByChartId 根据图表id刷新图表
  103. func RefreshByChartId(chartInfoId int) (err error, errMsg string) {
  104. // 查找图表
  105. chartInfo, err := models.GetChartInfoById(chartInfoId)
  106. if err != nil {
  107. if err.Error() == utils.ErrNoRow() {
  108. err = nil
  109. }
  110. return
  111. }
  112. if chartInfo.Source != utils.CHART_SOURCE_FUTURE_GOOD_PROFIT {
  113. return
  114. }
  115. var extraConf ChartInfoReq
  116. err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &extraConf)
  117. if err != nil {
  118. errMsg = "商品利润曲线图配置异常"
  119. return
  120. }
  121. // 查找商品利润图表的扩展信息
  122. chartInfoFutureGoodProfit := new(future_good.ChartInfoFutureGoodProfit)
  123. if err = chartInfoFutureGoodProfit.GetItemById(chartInfoId); err != nil {
  124. errMsg = "获取失败"
  125. if err.Error() == utils.ErrNoRow() {
  126. err = nil
  127. }
  128. return
  129. }
  130. if len(extraConf.EdbInfoIdList) == 0 {
  131. extraConf.EdbInfoIdList = append(extraConf.EdbInfoIdList, extraConf.BaseEdbInfoId)
  132. }
  133. baseEdbInfo := new(models.EdbInfo)
  134. // ETA指标
  135. edbInfoListTmp, err := models.GetEdbInfoByIdList(extraConf.EdbInfoIdList)
  136. if err != nil {
  137. errMsg = "获取失败"
  138. return
  139. }
  140. //按照请求顺序排序
  141. edbInfoMap := make(map[int]*models.EdbInfo)
  142. for _, v := range edbInfoListTmp {
  143. edbInfoMap[v.EdbInfoId] = v
  144. }
  145. edbInfoList := make([]*models.EdbInfo, 0)
  146. for _, v := range extraConf.EdbInfoIdList {
  147. edbInfoList = append(edbInfoList, edbInfoMap[v])
  148. }
  149. edbInfoListMap := make(map[int]*models.EdbInfo)
  150. for k, v := range edbInfoList {
  151. edbInfoList[k].EdbNameSource = v.EdbName
  152. edbInfoListMap[v.EdbInfoId] = v
  153. if v.EdbInfoId == extraConf.BaseEdbInfoId {
  154. baseEdbInfo = v
  155. }
  156. }
  157. // 商品数据库指标
  158. futureGoodEdbInfoMap := make(map[int]*future_good.FutureGoodEdbInfo)
  159. zlFutureGoodEdbInfoList := make([]*future_good.FutureGoodEdbInfo, 0)
  160. for _, v := range extraConf.FutureGoodEdbInfoIdList {
  161. if _, ok := futureGoodEdbInfoMap[v.EdbInfoId]; ok {
  162. continue
  163. }
  164. zlFutureGoodEdbInfo, tmpErr := future_good.GetFutureGoodEdbInfo(v.EdbInfoId)
  165. if tmpErr != nil {
  166. err = tmpErr
  167. errMsg = "获取失败"
  168. return
  169. }
  170. futureGoodEdbInfoMap[v.EdbInfoId] = zlFutureGoodEdbInfo
  171. zlFutureGoodEdbInfoList = append(zlFutureGoodEdbInfoList, zlFutureGoodEdbInfo)
  172. }
  173. xDataList, yDataList, err := GetProfitChartEdbData(baseEdbInfo, edbInfoList, zlFutureGoodEdbInfoList, extraConf.DateList, extraConf.CalculateFormula, extraConf.FutureGoodEdbInfoIdList, extraConf.XDataList)
  174. xDataListByte, err := json.Marshal(xDataList)
  175. if err != nil {
  176. errMsg = "保存失败"
  177. err = errors.New("X轴数据转换失败,ERR:" + err.Error())
  178. return
  179. }
  180. yDataListByte, err := json.Marshal(yDataList)
  181. if err != nil {
  182. errMsg = "保存失败"
  183. err = errors.New("Y轴数据转换失败,ERR:" + err.Error())
  184. return
  185. }
  186. extraUpdateCol := make([]string, 0)
  187. chartInfoFutureGoodProfit.XValue = string(xDataListByte)
  188. chartInfoFutureGoodProfit.YValue = string(yDataListByte)
  189. //chartInfoFutureGoodProfit.ProfitName = zlFutureGoodEdbInfoList[0].FutureGoodEdbName + "盘面利润"
  190. chartInfoFutureGoodProfit.ModifyTime = time.Now()
  191. extraUpdateCol = []string{"XValue", "YValue", "ProfitName", "ModifyTime"}
  192. err = chartInfoFutureGoodProfit.Update(extraUpdateCol)
  193. return
  194. }
  195. // GetProfitChartEdbData 获取利润图表的指标数据
  196. func GetProfitChartEdbData(baseEdbInfo *models.EdbInfo, edbInfoList []*models.EdbInfo, zlFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, chartInfoDateList []ChartInfoDateReq, formulaStr string, edbInfoFromTagList []models.EdbInfoFromTag, reqXDataList []XData) (xDataList []XData, yDataList []YData, err error) {
  197. if baseEdbInfo == nil {
  198. err = errors.New("ETA指标未选取")
  199. return
  200. }
  201. if len(edbInfoList) == 0 {
  202. edbInfoList = append(edbInfoList, baseEdbInfo)
  203. }
  204. if len(zlFutureGoodEdbInfoList) <= 0 {
  205. err = errors.New("商品指标未选取")
  206. return
  207. }
  208. // 标签与期货商品指标的关联关系
  209. tagEdbIdMap := make(map[string]int)
  210. // 有效的期货商品指标
  211. futureGoodEdbInfoIdMap := make(map[int]int)
  212. {
  213. tmpTagEdbIdMap := make(map[string]int)
  214. for _, v := range edbInfoFromTagList {
  215. tmpTagEdbIdMap[v.FromTag] = v.EdbInfoId
  216. }
  217. formulaMap := CheckFormula(formulaStr)
  218. for _, tag := range formulaMap {
  219. tagEdbIdMap[tag] = tmpTagEdbIdMap[tag]
  220. futureGoodEdbInfoIdMap[tmpTagEdbIdMap[tag]] = tmpTagEdbIdMap[tag]
  221. }
  222. }
  223. // 指标对应的所有数据
  224. //edbDataListMap := make(map[int][]*models.EdbDataList)
  225. // 普通的指标数据
  226. baseDataListMap := make(map[int][]*models.EdbDataList)
  227. for _, v := range edbInfoList {
  228. baseDataList := make([]*models.EdbDataList, 0)
  229. baseDataList, err = models.GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, "", "")
  230. if err != nil {
  231. return
  232. }
  233. baseDataListMap[v.EdbInfoId] = baseDataList
  234. }
  235. latestDate := zlFutureGoodEdbInfoList[0].EndDate
  236. latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local)
  237. earliestDateTime := latestDateTime // 数据的最早日期,目的是为了找出最早的合约
  238. for _, barChartInfoDate := range chartInfoDateList {
  239. var findDateTime time.Time
  240. switch barChartInfoDate.Type {
  241. case 1: //最新值
  242. findDateTime = latestDateTime
  243. case 2: //近期几天
  244. findDateTime = latestDateTime.AddDate(0, 0, -barChartInfoDate.Value)
  245. case 3: // 固定日期
  246. //寻找固定日期的数据
  247. tmpFindDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local)
  248. if tmpErr != nil {
  249. err = tmpErr
  250. return
  251. }
  252. findDateTime = tmpFindDateTime
  253. default:
  254. err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type))
  255. return
  256. }
  257. if findDateTime.IsZero() {
  258. err = errors.New("错误的日期")
  259. return
  260. }
  261. if findDateTime.Before(earliestDateTime) {
  262. earliestDateTime = findDateTime
  263. }
  264. }
  265. monthNum := (latestDateTime.Year()-earliestDateTime.Year())*12 + int(latestDateTime.Month()-earliestDateTime.Month())
  266. // 存储主力合约下的所有月份合约
  267. futureGoodEdbInfoDateMap := make(map[int]map[string]*future_good.FutureGoodEdbInfo)
  268. futureGoodDataListMap := make(map[int][]*models.EdbDataList, 0)
  269. // 特殊的商品期货合约(只有M+N的合约,没有固定日期的合约)
  270. specialFutureGoodEdbInfoMap := make(map[int]map[int]*future_good.FutureGoodEdbInfo, 0)
  271. hasChina := false // 是否包含国内的期货合约
  272. for _, v := range zlFutureGoodEdbInfoList {
  273. if v.RegionType == "国内" {
  274. hasChina = true
  275. break
  276. }
  277. }
  278. nMap := make(map[string]string)
  279. var maxN int // 最大N值
  280. for _, v := range zlFutureGoodEdbInfoList {
  281. // 如果不是有效的商品期货指标,那么就过滤掉,不做数据查询处理,避免没必要的请求
  282. if _, ok := futureGoodEdbInfoIdMap[v.FutureGoodEdbInfoId]; !ok {
  283. continue
  284. }
  285. // 获取期货指标以及期货数据
  286. tmpFutureGoodEdbInfoList, tmpErr := future_good.GetChildFutureGoodEdbInfoListByParentId(v.FutureGoodEdbInfoId)
  287. if tmpErr != nil {
  288. err = tmpErr
  289. return
  290. }
  291. childFutureGoodEdbInfoMap, tmpMaxN, tmpErr := getProfitFutureGoodEdbInfoList(earliestDateTime, v, tmpFutureGoodEdbInfoList, monthNum)
  292. if tmpErr != nil {
  293. err = tmpErr
  294. return
  295. }
  296. if maxN < tmpMaxN {
  297. maxN = tmpMaxN
  298. }
  299. futureGoodEdbInfoDateMap[v.FutureGoodEdbInfoId] = childFutureGoodEdbInfoMap
  300. if v.FutureGoodEdbType == 2 {
  301. specialFutureGoodEdbInfoMap[v.FutureGoodEdbInfoId] = make(map[int]*future_good.FutureGoodEdbInfo)
  302. }
  303. // 获取数据
  304. for date, childFutureGoodEdbInfo := range childFutureGoodEdbInfoMap {
  305. nMap[date] = date
  306. dataList := make([]*models.EdbDataList, 0)
  307. tmpDataList, tmpErr := future_good.GetFutureGoodEdbDataListByDate(childFutureGoodEdbInfo.FutureGoodEdbInfoId, "", "")
  308. if tmpErr != nil {
  309. return
  310. }
  311. for _, tmpData := range tmpDataList {
  312. dataList = append(dataList, &models.EdbDataList{
  313. EdbDataId: tmpData.FutureGoodEdbDataId,
  314. EdbInfoId: tmpData.FutureGoodEdbInfoId,
  315. DataTime: tmpData.DataTime.Format(utils.FormatDate),
  316. DataTimestamp: tmpData.DataTimestamp,
  317. Value: tmpData.Close,
  318. })
  319. }
  320. futureGoodDataListMap[childFutureGoodEdbInfo.FutureGoodEdbInfoId] = dataList
  321. if childFutureGoodEdbInfo.FutureGoodEdbType == 2 {
  322. specialFutureGoodEdbInfoMap[v.FutureGoodEdbInfoId][childFutureGoodEdbInfo.Month] = childFutureGoodEdbInfo
  323. }
  324. }
  325. }
  326. // 需求池604,只要包含了国内合约,最大必须是12期
  327. if hasChina {
  328. maxN = 12
  329. }
  330. // 找出所有的N值,并进行正序排列
  331. dateList := make([]string, 0)
  332. for _, n := range nMap {
  333. dateList = append(dateList, n)
  334. }
  335. sort.Slice(dateList, func(i, j int) bool {
  336. return dateList[i] < dateList[j]
  337. })
  338. var reqEdbInfoIds []int
  339. for _, v := range edbInfoList {
  340. reqEdbInfoIds = append(reqEdbInfoIds, v.EdbInfoId)
  341. tmp := XData{
  342. Name: v.EdbName,
  343. NameEn: v.EdbNameEn,
  344. }
  345. xDataList = append(xDataList, tmp)
  346. }
  347. var edbIdList []int
  348. futureGoodNameMap := make(map[int]map[int]string)
  349. edbIdList, yDataList, futureGoodNameMap, err = ProfitChartChartData(baseEdbInfo, baseDataListMap, futureGoodEdbInfoDateMap, futureGoodDataListMap, chartInfoDateList, baseEdbInfo.EndDate, specialFutureGoodEdbInfoMap, formulaStr, tagEdbIdMap, dateList, maxN, reqEdbInfoIds)
  350. // todo 最后处理数据
  351. tmpXDataList, newYDataList, err := handleProfitResultData(xDataList, futureGoodNameMap, yDataList, earliestDateTime, edbIdList)
  352. if err != nil {
  353. return
  354. }
  355. if len(reqXDataList) == 0 {
  356. xDataList = tmpXDataList
  357. } else {
  358. xDataList = reqXDataList
  359. }
  360. yDataList = newYDataList
  361. return
  362. }
  363. // ProfitChartChartData 获取数据
  364. func ProfitChartChartData(baseEdbInfo *models.EdbInfo, baseDataListMap map[int][]*models.EdbDataList, futureGoodEdbInfoMap map[int]map[string]*future_good.FutureGoodEdbInfo, futureGoodEdbDataListMap map[int][]*models.EdbDataList, chartInfoDateList []ChartInfoDateReq, latestDate string, specialFutureGoodEdbInfoMap map[int]map[int]*future_good.FutureGoodEdbInfo, formulaStr string, tagEdbIdMap map[string]int, dateList []string, maxN int, reqEdbInfoIds []int) (edbIdList []int, yDataList []YData, futureGoodNameMap map[int]map[int]string, err error) {
  365. // 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
  366. //earliestDateTime time.Time
  367. // ETA指标数据
  368. allBaseEdbDateDataMap := make(map[int]map[string]float64)
  369. for edbInfoId, baseDataList := range baseDataListMap {
  370. baseEdbDateData := make(map[string]float64)
  371. for _, edbData := range baseDataList {
  372. baseEdbDateData[edbData.DataTime] = edbData.Value
  373. }
  374. allBaseEdbDateDataMap[edbInfoId] = baseEdbDateData
  375. }
  376. // 商品指标数据
  377. edbDataMap := make(map[int]map[string]float64)
  378. for edbInfoId, edbDataList := range futureGoodEdbDataListMap {
  379. edbDateData := make(map[string]float64)
  380. for _, edbData := range edbDataList {
  381. edbDateData[edbData.DataTime] = edbData.Value
  382. }
  383. edbDataMap[edbInfoId] = edbDateData
  384. }
  385. latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local)
  386. yDataList = make([]YData, 0) //y轴的数据列表
  387. // 将计算公式中的字母转大写
  388. formulaStr = strings.ToUpper(formulaStr)
  389. futureGoodNameMap = make(map[int]map[int]string)
  390. for tmpk, barChartInfoDate := range chartInfoDateList {
  391. yDataMap := make(map[int]float64)
  392. var maxDate time.Time
  393. var findDateTime time.Time
  394. switch barChartInfoDate.Type {
  395. case 1: //最新值
  396. findDateTime = latestDateTime
  397. case 2: //近期几天
  398. findDateTime = latestDateTime.AddDate(0, 0, -barChartInfoDate.Value)
  399. case 3: // 固定日期
  400. //寻找固定日期的数据
  401. tmpFindDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local)
  402. if tmpErr != nil {
  403. err = tmpErr
  404. return
  405. }
  406. findDateTime = tmpFindDateTime
  407. default:
  408. err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type))
  409. return
  410. }
  411. if findDateTime.IsZero() {
  412. err = errors.New("错误的日期")
  413. return
  414. }
  415. findDataList := make([]float64, 0) // 当前日期的数据值
  416. noDataIdList := make([]int, 0) // 没有数据的指标id
  417. noDataIdMap := make(map[int]int, 0) // 没有数据的指标map
  418. xEdbInfoIdList := make([]int, 0) // 当前数据的指标id列表
  419. // 现货指标
  420. index := 0
  421. var realDateTime time.Time
  422. // 现货指标
  423. baseEdbDateData, ok := allBaseEdbDateDataMap[baseEdbInfo.EdbInfoId]
  424. if !ok {
  425. err = fmt.Errorf("指标id: %d 没有数据", baseEdbInfo.EdbInfoId)
  426. return
  427. }
  428. realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, baseDataListMap[baseEdbInfo.EdbInfoId], baseEdbDateData, edbDataMap)
  429. if tmpErr != nil {
  430. err = tmpErr
  431. return
  432. }
  433. if isFind {
  434. maxDate = realDateTime
  435. }
  436. edbIdList = make([]int, 0) //普通指标ID
  437. for _, edbInfoId := range reqEdbInfoIds {
  438. if edbInfoId == baseEdbInfo.EdbInfoId {
  439. findDataList = append(findDataList, findDataValue)
  440. yDataMap[index] = findDataValue
  441. xEdbInfoIdList = append(xEdbInfoIdList, edbInfoId)
  442. edbIdList = append(edbIdList, edbInfoId)
  443. index += 1
  444. continue
  445. }
  446. baseEdbDateDataTmp, ok := allBaseEdbDateDataMap[edbInfoId]
  447. if !ok {
  448. err = fmt.Errorf("指标id: %d 没有数据", edbInfoId)
  449. return
  450. }
  451. findDataValueTmp, isFindTmp := baseEdbDateDataTmp[realDateTime.Format(utils.FormatDate)]
  452. if !isFindTmp {
  453. noDataIdList = append(noDataIdList, edbInfoId)
  454. noDataIdMap[edbInfoId] = edbInfoId
  455. }
  456. findDataList = append(findDataList, findDataValueTmp)
  457. yDataMap[index] = findDataValueTmp
  458. xEdbInfoIdList = append(xEdbInfoIdList, edbInfoId)
  459. edbIdList = append(edbIdList, edbInfoId)
  460. index += 1
  461. }
  462. mList := make([]int, 0) // 间隔月份
  463. tmpNameMap := make(map[int]string)
  464. // 最小开始的n值
  465. //minN := (findDateTime.Year()-earliestDateTime.Year())*12 + int(findDateTime.Month()-earliestDateTime.Month())
  466. for _, date := range dateList {
  467. currDate, _ := time.ParseInLocation(utils.FormatYearMonthDate, date, time.Local)
  468. // 如果当前的n值小于最小开始的n值,那么就不处理
  469. //if n < minN {
  470. // continue
  471. //}
  472. //findDateTime
  473. // 获取当前日期相对开始日期的期数
  474. tmpN := (currDate.Year()-realDateTime.Year())*12 + int(currDate.Month()-realDateTime.Month())
  475. if tmpN <= 0 {
  476. continue
  477. }
  478. // 如果期数大于最大期数,那么就退出当前匹配
  479. if tmpN >= maxN {
  480. break
  481. }
  482. zlAndChildEdbId := make(map[int]int)
  483. childFutureGoodEdbInfoIdList := make([]int, 0)
  484. for zlFutureGoodEdbInfoId, futureGoodEdbInfoList := range futureGoodEdbInfoMap {
  485. // 判断是否特殊合约
  486. if childFutureGoodEdbInfoIdMap, ok := specialFutureGoodEdbInfoMap[zlFutureGoodEdbInfoId]; ok {
  487. if childFutureGoodEdbInfo, ok2 := childFutureGoodEdbInfoIdMap[tmpN]; ok2 {
  488. childFutureGoodEdbInfoIdList = append(childFutureGoodEdbInfoIdList, childFutureGoodEdbInfo.FutureGoodEdbInfoId)
  489. zlAndChildEdbId[zlFutureGoodEdbInfoId] = childFutureGoodEdbInfo.FutureGoodEdbInfoId
  490. }
  491. } else {
  492. if childFutureGoodEdbInfo, ok2 := futureGoodEdbInfoList[date]; ok2 {
  493. childFutureGoodEdbInfoIdList = append(childFutureGoodEdbInfoIdList, childFutureGoodEdbInfo.FutureGoodEdbInfoId)
  494. zlAndChildEdbId[zlFutureGoodEdbInfoId] = childFutureGoodEdbInfo.FutureGoodEdbInfoId
  495. }
  496. }
  497. }
  498. // 合约不全,不参与计算
  499. //if len(childFutureGoodEdbInfoIdList) != lenZlFutureGoodEdbInfo {
  500. // continue
  501. //}
  502. calculateMap := make(map[int]float64)
  503. for _, childFutureGoodEdbInfoId := range childFutureGoodEdbInfoIdList {
  504. tmpFindDataValue, tmpIsFind := edbDataMap[childFutureGoodEdbInfoId][realDateTime.Format(utils.FormatDate)]
  505. if tmpIsFind && tmpFindDataValue != 0 {
  506. calculateMap[childFutureGoodEdbInfoId] = tmpFindDataValue
  507. }
  508. }
  509. // 合约的数据不全,不参与计算
  510. //if len(calculateMap) != lenZlFutureGoodEdbInfo {
  511. // continue
  512. //}
  513. newTagEdbIdMap := make(map[string]int)
  514. for tag, zlEdbId := range tagEdbIdMap {
  515. if tag == "A" {
  516. nameTmp := strings.Split(futureGoodEdbInfoMap[zlEdbId][date].FutureGoodEdbName, "(")
  517. nameTmpEn := strings.Split(futureGoodEdbInfoMap[zlEdbId][date].FutureGoodEdbNameEn, "(")
  518. if len(nameTmp) > 1 && len(nameTmpEn) > 1 {
  519. nameTmp[1] = strings.Trim(nameTmp[1], ")")
  520. nameTmpEn[1] = strings.Trim(nameTmpEn[1], ")")
  521. tmpNameMap[tmpN+1] = nameTmp[1] + "-" + nameTmpEn[1]
  522. }
  523. }
  524. newTagEdbIdMap[tag] = zlAndChildEdbId[zlEdbId]
  525. }
  526. //, formulaStr string, tagEdbIdMap map[string]int
  527. formulaFormStr := ReplaceFormula(newTagEdbIdMap, calculateMap, formulaStr)
  528. //计算公式异常,那么就移除该指标
  529. if formulaFormStr == `` {
  530. //removeDateList = append(removeDateList, sk)
  531. fmt.Println("异常了")
  532. continue
  533. }
  534. calVal, e := engine.ParseAndExec(formulaFormStr)
  535. //calVal, err := calResult.Float64()
  536. if e != nil {
  537. err = errors.New("计算失败:获取计算值失败 Err:" + e.Error() + ";formulaStr:" + formulaFormStr)
  538. fmt.Println(err)
  539. return
  540. }
  541. //yDataMap[n] = calVal
  542. //xEdbInfoIdList = append(xEdbInfoIdList, n)
  543. calVal, _ = decimal.NewFromFloat(calVal).Round(4).Float64()
  544. yDataMap[tmpN] = calVal
  545. xEdbInfoIdList = append(xEdbInfoIdList, tmpN)
  546. findDataList = append(findDataList, calVal)
  547. }
  548. yName := barChartInfoDate.Name
  549. yNameEn := barChartInfoDate.Name
  550. if yName == `` {
  551. if barChartInfoDate.Type == 2 {
  552. yName = strconv.Itoa(barChartInfoDate.Value) + "天前"
  553. if barChartInfoDate.Value == 1 {
  554. yNameEn = strconv.Itoa(barChartInfoDate.Value) + "day ago"
  555. } else {
  556. yNameEn = strconv.Itoa(barChartInfoDate.Value) + " days ago"
  557. }
  558. } else {
  559. yName = maxDate.Format(utils.FormatDate)
  560. yNameEn = maxDate.Format(utils.FormatDate)
  561. }
  562. }
  563. yDate := "0000-00-00"
  564. if !maxDate.IsZero() {
  565. yDate = maxDate.Format(utils.FormatDate)
  566. }
  567. {
  568. hasDataIndexList := make([]int, 0)
  569. for dataK, edbInfoId := range xEdbInfoIdList {
  570. if _, ok := noDataIdMap[edbInfoId]; !ok { // 如果是没有数据的指标id
  571. hasDataIndexList = append(hasDataIndexList, dataK)
  572. }
  573. }
  574. lenHasDataIndex := len(hasDataIndexList)
  575. if lenHasDataIndex > 0 {
  576. for lenHasDataI := 1; lenHasDataI < lenHasDataIndex; lenHasDataI++ {
  577. perK := hasDataIndexList[lenHasDataI-1] //上一个有数据的指标下标
  578. currK := hasDataIndexList[lenHasDataI] //当前有数据的指标下标
  579. preVal := findDataList[perK] //上一个有数据的坐标的值
  580. currVal := findDataList[currK] //当前有数据的指标的值
  581. // 环差值
  582. hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(currK - perK)))
  583. var tmpI int64
  584. // 将两个中间的数据做平均值补全
  585. for hcI := perK + 1; hcI < currK; hcI++ {
  586. tmpI++
  587. findDataList[hcI], _ = decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(tmpI))).RoundCeil(4).Float64()
  588. }
  589. }
  590. }
  591. }
  592. futureGoodNameMap[tmpk] = tmpNameMap
  593. yDataList = append(yDataList, YData{
  594. Date: yDate,
  595. ConfigDate: realDateTime,
  596. Value: findDataList,
  597. NoDataEdbList: noDataIdList,
  598. XEdbInfoIdList: xEdbInfoIdList,
  599. Color: barChartInfoDate.Color,
  600. Name: yName,
  601. NameEn: yNameEn,
  602. EdbValMap: yDataMap,
  603. M: mList,
  604. })
  605. }
  606. return
  607. }
  608. // getFutureGoodEdbInfoList 获取适用的指标列表
  609. func getProfitFutureGoodEdbInfoList(earliestDateTime time.Time, zlFutureGoodEdbInfo *future_good.FutureGoodEdbInfo, tmpFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, monthNum int) (futureGoodEdbInfoDateMap map[string]*future_good.FutureGoodEdbInfo, newMaxN int, err error) {
  610. maxN := 36 //最大36期合约
  611. futureGoodEdbInfoList := make([]*future_good.FutureGoodEdbInfo, 0)
  612. futureGoodEdbInfoDateMap = make(map[string]*future_good.FutureGoodEdbInfo)
  613. earliestDateTime = time.Date(earliestDateTime.Year(), earliestDateTime.Month(), 1, 0, 0, 0, 0, time.Local)
  614. if zlFutureGoodEdbInfo.RegionType == "国内" {
  615. startMonth := int(earliestDateTime.Month())
  616. if startMonth == 1 {
  617. futureGoodEdbInfoList = tmpFutureGoodEdbInfoList
  618. } else {
  619. // 因为是下标,所以对应想下标是需要-1的
  620. index := startMonth - 1
  621. futureGoodEdbInfoList = tmpFutureGoodEdbInfoList[index:]
  622. futureGoodEdbInfoList = append(futureGoodEdbInfoList, tmpFutureGoodEdbInfoList[:index]...)
  623. }
  624. lenFutureGoodEdbInfoList := len(futureGoodEdbInfoList)
  625. //futureGoodEdbInfoList
  626. //if isAllChina {
  627. //}
  628. // 如果全是国内指标,那么只需要拼上多出的几期合约即可
  629. maxN = lenFutureGoodEdbInfoList + monthNum
  630. for i := 1; i < maxN; i++ {
  631. k := i % lenFutureGoodEdbInfoList
  632. futureGoodEdbInfoDateMap[earliestDateTime.AddDate(0, i, 0).Format(utils.FormatYearMonthDate)] = futureGoodEdbInfoList[k]
  633. }
  634. //需求池604,只要是国内合约,最大必须是12期
  635. newMaxN = 12
  636. return
  637. }
  638. for _, v := range tmpFutureGoodEdbInfoList {
  639. //海外的连续日期,目前
  640. if v.FutureGoodEdbType == 2 {
  641. if v.Month <= maxN {
  642. futureGoodEdbInfoDateMap[earliestDateTime.AddDate(0, v.Month, 0).Format(utils.FormatYearMonthDate)] = v
  643. if v.Month > newMaxN {
  644. newMaxN = v.Month
  645. }
  646. }
  647. continue
  648. }
  649. if v.Year < earliestDateTime.Year() {
  650. continue
  651. }
  652. // 小于等于当前年,那么就肯定是ok的
  653. if v.Year == earliestDateTime.Year() && v.Month <= int(earliestDateTime.Month()) {
  654. continue
  655. }
  656. subYear := v.Year - earliestDateTime.Year()
  657. subMonth := v.Month - int(earliestDateTime.Month())
  658. // 如果(当前年-最新日期的年份) * 12个月 + (当前月-最新日期的月份) 小于总月份
  659. tmpN := subYear*12 + subMonth
  660. if tmpN < maxN {
  661. tmpDateTime := time.Date(v.Year, time.Month(v.Month), 0, 0, 0, 0, 0, time.Local)
  662. futureGoodEdbInfoDateMap[tmpDateTime.Format(utils.FormatYearMonthDate)] = v
  663. if tmpN > newMaxN {
  664. newMaxN = tmpN
  665. }
  666. continue
  667. }
  668. }
  669. return
  670. }
  671. // handleProfitResultData 处理成最终的结果数据
  672. func handleProfitResultData(xDataListInit []XData, futureNameMap map[int]map[int]string, yDataList []YData, earliestDateTime time.Time, allEdbInfoIds []int) (xDataList []XData, newYDataList []YData, err error) {
  673. newYDataList = yDataList
  674. xDataList = xDataListInit
  675. nMap := make(map[int]int)
  676. nList := make([]int, 0)
  677. nListEdbMap := make(map[int]struct{})
  678. for _, v := range yDataList {
  679. for _, n := range v.XEdbInfoIdList {
  680. if utils.InArrayByInt(allEdbInfoIds, n) {
  681. if _, ok := nListEdbMap[n]; !ok {
  682. nList = append(nList, n)
  683. nListEdbMap[n] = struct{}{}
  684. }
  685. } else {
  686. nMap[n] = n
  687. }
  688. }
  689. }
  690. // 找出所有的N值,并进行正序排列
  691. nListTmp := make([]int, 0)
  692. for _, n := range nMap {
  693. nListTmp = append(nListTmp, n)
  694. }
  695. sort.Slice(nListTmp, func(i, j int) bool {
  696. return nListTmp[i] < nListTmp[j]
  697. })
  698. nList = append(nList, nListTmp...)
  699. for _, n := range nList {
  700. if utils.InArrayByInt(allEdbInfoIds, n) {
  701. continue
  702. }
  703. xDataList = append(xDataList, XData{
  704. Name: fmt.Sprint("M+", n),
  705. NameEn: fmt.Sprint("M+", n),
  706. })
  707. }
  708. for yIndex, yData := range yDataList {
  709. newYDataList[yIndex].XEdbInfoIdList = []int{}
  710. newYDataList[yIndex].Value = []float64{}
  711. tmpNList := nList
  712. xEdbInfoIdList := yData.XEdbInfoIdList
  713. valIndex := 0
  714. needNum := 0
  715. for _, n := range tmpNList {
  716. if len(xEdbInfoIdList) > 0 {
  717. currN := xEdbInfoIdList[0]
  718. // 当前距离最早的日期相差的N数
  719. if n == currN { // todo 改成所有的基础现货指标
  720. if needNum > 0 {
  721. currVal := yData.Value[valIndex]
  722. preVal := yData.Value[valIndex-1]
  723. hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(needNum + 1)))
  724. for tmpNum := 0; tmpNum < needNum; tmpNum++ {
  725. newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, 0)
  726. // 赋值平均值
  727. tmpVal, _ := decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(int64(tmpNum + 1)))).RoundCeil(4).Float64()
  728. newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, tmpVal)
  729. }
  730. }
  731. if utils.InArrayByInt(allEdbInfoIds, currN) {
  732. newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, currN)
  733. } else {
  734. newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, currN+1)
  735. }
  736. newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[valIndex])
  737. valIndex++
  738. needNum = 0
  739. if len(xEdbInfoIdList) > 0 {
  740. xEdbInfoIdList = xEdbInfoIdList[1:]
  741. }
  742. } else {
  743. needNum++
  744. }
  745. }
  746. }
  747. }
  748. maxI := 0
  749. for _, yData := range newYDataList {
  750. lenEdb := len(yData.XEdbInfoIdList)
  751. for i := 0; i < lenEdb; i++ {
  752. if yData.XEdbInfoIdList[i] != 0 && !utils.InArrayByInt(yData.NoDataEdbList, yData.XEdbInfoIdList[i]) {
  753. if maxI < i {
  754. maxI = i
  755. }
  756. }
  757. }
  758. }
  759. earliestDateTime = time.Date(earliestDateTime.Year(), earliestDateTime.Month(), 1, 0, 0, 0, 0, time.Local)
  760. xDataList = xDataList[0 : maxI+1]
  761. for yIndex, yData := range newYDataList {
  762. if len(yData.XEdbInfoIdList) > maxI+1 {
  763. newYDataList[yIndex].XEdbInfoIdList = yData.XEdbInfoIdList[0 : maxI+1]
  764. }
  765. if len(yData.Value) > maxI+1 {
  766. newYDataList[yIndex].Value = yData.Value[0 : maxI+1]
  767. }
  768. nameList := make([]string, 0)
  769. enNameList := make([]string, 0)
  770. for k1, n := range newYDataList[yIndex].XEdbInfoIdList {
  771. if utils.InArrayByInt(allEdbInfoIds, n) { // 现货价不处理
  772. tmpItem := xDataListInit[k1]
  773. nameList = append(nameList, tmpItem.Name)
  774. enNameList = append(enNameList, tmpItem.NameEn)
  775. continue
  776. }
  777. if n <= 0 {
  778. nameList = append(nameList, `无合约`)
  779. enNameList = append(enNameList, `no contract`)
  780. } else {
  781. nameTmp := futureNameMap[yIndex][n]
  782. nameTmpSlice := strings.Split(nameTmp, "-")
  783. nameList = append(nameList, nameTmpSlice[0])
  784. enNameList = append(enNameList, nameTmpSlice[1])
  785. }
  786. }
  787. newYDataList[yIndex].NameList = nameList
  788. newYDataList[yIndex].EnNameList = enNameList
  789. }
  790. return
  791. }
  792. func CheckFormula(formula string) map[string]string {
  793. mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN"}
  794. str := strings.ToUpper(formula)
  795. for _, v := range mathFormula {
  796. str = strings.Replace(str, v, "", -1)
  797. }
  798. str = strings.Replace(str, "(", "", -1)
  799. str = strings.Replace(str, ")", "", -1)
  800. byteMap := make(map[string]string)
  801. for i := 0; i < len(str); i++ {
  802. byteInt := str[i]
  803. if byteInt >= 65 && byteInt <= 90 {
  804. byteStr := string(byteInt)
  805. if _, ok := byteMap[byteStr]; !ok {
  806. byteMap[byteStr] = byteStr
  807. }
  808. }
  809. }
  810. return byteMap
  811. }
  812. func ReplaceFormula(tagEdbIdMap map[string]int, valArr map[int]float64, formulaStr string) string {
  813. funMap := GetFormulaMap()
  814. for k, v := range funMap {
  815. formulaStr = strings.Replace(formulaStr, k, v, -1)
  816. }
  817. replaceCount := 0
  818. for tag, edbInfoId := range tagEdbIdMap {
  819. if val, valOk := valArr[edbInfoId]; valOk { //值存在
  820. dvStr := fmt.Sprintf("%v", val)
  821. formulaStr = strings.Replace(formulaStr, tag, dvStr, -1)
  822. replaceCount++
  823. }
  824. }
  825. for k, v := range funMap {
  826. formulaStr = strings.Replace(formulaStr, v, k, -1)
  827. }
  828. fmt.Println(formulaStr)
  829. if replaceCount == len(tagEdbIdMap) {
  830. return formulaStr
  831. } else {
  832. return ""
  833. }
  834. }
  835. func GetFormulaMap() map[string]string {
  836. funMap := make(map[string]string)
  837. funMap["MAX"] = "[@@]"
  838. funMap["MIN"] = "[@!]"
  839. funMap["ABS"] = "[@#]"
  840. funMap["CEIL"] = "[@$]"
  841. funMap["COS"] = "[@%]"
  842. funMap["FLOOR"] = "[@^]"
  843. funMap["MOD"] = "[@&]"
  844. funMap["POW"] = "[@*]"
  845. funMap["ROUND"] = "[@(]"
  846. return funMap
  847. }
  848. // GetNeedDateData 获取合约内需要的日期数据
  849. func GetNeedDateData(needDateTime time.Time, dataList []*models.EdbDataList, edbDataMap map[string]float64, allEdbDataMap map[int]map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) {
  850. //dataList := edbDataListMap[edbInfoId] //指标的所有数据值
  851. if len(dataList) <= 0 {
  852. // 没有数据的指标id
  853. return
  854. }
  855. //最早的日期
  856. minDateTime, err := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
  857. if err != nil {
  858. return
  859. }
  860. // 该日期存在数据的期货指标的最小数量,目前是现货和期货各1个,总共2个
  861. maxCount := 1
  862. for tmpDateTime := needDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
  863. tmpDate := tmpDateTime.Format(utils.FormatDate)
  864. tmpValue, ok := edbDataMap[tmpDate]
  865. if !ok {
  866. continue
  867. }
  868. // 该日期存在数据的指标数量
  869. count := 0
  870. for _, currEdbDataMap := range allEdbDataMap {
  871. _, tmpIsFind := currEdbDataMap[tmpDate]
  872. if tmpIsFind {
  873. count++
  874. if count >= maxCount {
  875. continue
  876. }
  877. }
  878. }
  879. // 该日期存在数据的期货指标数量小于2个,那么要继续往前找
  880. if count < maxCount {
  881. continue
  882. }
  883. //如果能找到数据,那么就返回
  884. // 数据为0,也直接返回,做无值处理
  885. if tmpValue == 0 {
  886. return
  887. }
  888. findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
  889. findDataValue = tmpValue
  890. isFind = true
  891. return
  892. }
  893. return
  894. }