trade_analysis_table.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. package trade_analysis
  2. import (
  3. tradeAnalysisModel "eta/eta_api/models/data_manage/trade_analysis"
  4. "eta/eta_api/utils"
  5. "fmt"
  6. "math"
  7. "time"
  8. )
  9. // CheckAnalysisTableExtraConfig 校验表格配置
  10. func CheckAnalysisTableExtraConfig(extraConfig tradeAnalysisModel.TableExtraConfig) (pass bool, tips string) {
  11. if extraConfig.CompanyName == "" {
  12. tips = "请选择期货公司"
  13. return
  14. }
  15. if len(extraConfig.ClassifyList) == 0 {
  16. tips = "请选择品种"
  17. return
  18. }
  19. var classifyTotal int
  20. for _, v := range extraConfig.ClassifyList {
  21. if v.Exchange == "" {
  22. tips = "请选择交易所"
  23. return
  24. }
  25. if len(v.ClassifyNames) == 0 {
  26. tips = "请选择品种"
  27. return
  28. }
  29. classifyTotal += len(v.ClassifyNames)
  30. }
  31. // TODO:品种选择上限
  32. if classifyTotal > 5 {
  33. tips = "选择品种不超过5个"
  34. return
  35. }
  36. typeArr := []int{tradeAnalysisModel.ContractQueryTypeTop, tradeAnalysisModel.ContractQueryTypeTop2, tradeAnalysisModel.ContractQueryTypeTop3, tradeAnalysisModel.ContractQueryTypeAll, tradeAnalysisModel.ContractQueryTypeTotal}
  37. if !utils.InArrayByInt(typeArr, extraConfig.ContractType) {
  38. tips = "请选择正确的合约"
  39. return
  40. }
  41. if extraConfig.DateType == 1 && extraConfig.FixedDate == "" {
  42. tips = "请选择固定日期"
  43. return
  44. }
  45. if extraConfig.FixedDate != "" {
  46. _, e := time.Parse(utils.FormatDate, extraConfig.FixedDate)
  47. if e != nil {
  48. tips = "固定日期格式有误"
  49. return
  50. }
  51. }
  52. if extraConfig.PredictRatio < 0 || extraConfig.PredictRatio > 1 {
  53. tips = "请输入正确的估计参数"
  54. return
  55. }
  56. pass = true
  57. return
  58. }
  59. // GetAnalysisTableBaseDate 根据配置获取基准交易日期
  60. func GetAnalysisTableBaseDate(dateType, intervalMove int, fixedDate string) (baseDate time.Time, err error) {
  61. if dateType == 1 {
  62. // 固定日期
  63. t, _ := time.ParseInLocation(utils.FormatDate, fixedDate, time.Local)
  64. baseDate = t
  65. } else {
  66. // 最新交易日
  67. st := time.Now().AddDate(0, 0, -7) // 默认前移7天, 在开始结束区间内取出指定交易日
  68. if intervalMove > 0 {
  69. period := intervalMove * 7
  70. st = st.AddDate(0, 0, -period)
  71. }
  72. tradeDates := utils.GetTradingDays(st, time.Now())
  73. dateLen := len(tradeDates)
  74. if dateLen == 0 {
  75. err = fmt.Errorf("交易日序列异常")
  76. return
  77. }
  78. index := dateLen - 1
  79. if intervalMove > 0 {
  80. index -= intervalMove
  81. }
  82. if index < 0 || index > dateLen {
  83. err = fmt.Errorf("交易日序列异常")
  84. return
  85. }
  86. baseDate = tradeDates[index]
  87. }
  88. return
  89. }
  90. // CalculateTableRowData 计算表格行数据
  91. func CalculateTableRowData(exchange string, baseDate time.Time, topData []*tradeAnalysisModel.ContractTopRankData, contractsData []*tradeAnalysisModel.ContractCompanyTradeData) (rows []*tradeAnalysisModel.TableRowData, err error) {
  92. contractTopData := make(map[string]*tradeAnalysisModel.ContractTopRankData)
  93. for _, v := range topData {
  94. contractTopData[v.ClassifyType] = v
  95. }
  96. rows = make([]*tradeAnalysisModel.TableRowData, 0)
  97. for _, v := range contractsData {
  98. // 取出基准日期的数据
  99. cd := new(tradeAnalysisModel.ContractCompanyTradeDataList)
  100. for _, d := range v.DataList {
  101. if d.Date.Equal(baseDate) {
  102. cd = d
  103. break
  104. }
  105. }
  106. // 合约基准日期无数据
  107. if cd.Date.IsZero() {
  108. continue
  109. }
  110. td, ok := contractTopData[v.ClassifyType]
  111. if !ok {
  112. // 无前20数据
  113. continue
  114. }
  115. row := new(tradeAnalysisModel.TableRowData)
  116. row.Exchange = exchange
  117. row.ClassifyName = td.ClassifyName
  118. row.ClassifyType = v.ClassifyType
  119. row.BuyValue = cd.BuyVal
  120. row.BuyChange = cd.BuyChange
  121. row.SoldValue = cd.SoldVal
  122. row.SoldChange = cd.SoldChange
  123. row.PureBuyVal = cd.PureBuyVal
  124. row.PureBuyChange = cd.PureBuyChange
  125. row.TopBuyValue = td.BuyValue
  126. row.TopSoldValue = td.SoldValue
  127. row.TopBuyChange = td.BuyChange
  128. row.TopSoldChange = td.SoldChange
  129. // 计算值
  130. row.BuySoldRatio = math.Round(float64(cd.BuyVal)/float64(cd.BuyVal+cd.SoldVal)*100) / 100
  131. row.BuyTopRatio = math.Round(float64(cd.BuyVal)/float64(td.BuyValue)*100) / 100
  132. row.SoldTopRatio = math.Round(float64(cd.SoldVal)/float64(td.SoldValue)*100) / 100
  133. row.TopPureBuy = td.BuyValue - td.SoldValue
  134. row.TopPureBuyChange = int(math.Abs(float64(td.BuyChange))) + int(math.Abs(float64(td.SoldChange))) // 净多变化=Abs(多单变化)+Abs(空单变化)
  135. row.TopBuySoldRatio = math.Round(float64(td.BuyValue)/float64(td.BuyValue+td.SoldValue)*100) / 100
  136. rows = append(rows, row)
  137. }
  138. return
  139. }
  140. // GetTableRowsDataByConfig 根据配置获取表格行数据
  141. func GetTableRowsDataByConfig(tableConfig tradeAnalysisModel.TableExtraConfig) (tableRows []*tradeAnalysisModel.TableRowData, err error) {
  142. // 基准日期
  143. baseDate, e := GetAnalysisTableBaseDate(tableConfig.DateType, tableConfig.IntervalMove, tableConfig.FixedDate)
  144. if e != nil {
  145. err = fmt.Errorf("获取基准日期失败, %v", e)
  146. return
  147. }
  148. // 查询基准日期TOP20合约排名, 根据类型取出合约数
  149. exchangeContracts := make(map[string][]*tradeAnalysisModel.ContractTopRankData) // 交易所最终取的合约
  150. var contractMax int // 需要取出的品种对应的最大合约数
  151. classifyMax := make(map[string]int) // 品种对应的合约数
  152. switch tableConfig.ContractType {
  153. case tradeAnalysisModel.ContractQueryTypeTop:
  154. contractMax = 1
  155. case tradeAnalysisModel.ContractQueryTypeTop2:
  156. contractMax = 2
  157. case tradeAnalysisModel.ContractQueryTypeTop3:
  158. contractMax = 3
  159. case tradeAnalysisModel.ContractQueryTypeAll, tradeAnalysisModel.ContractQueryTypeTotal:
  160. contractMax = 999
  161. }
  162. // 遍历交易所, 查询各品种下的合约排名情况及TOP当日的多空单数据
  163. var sortContract []string
  164. for _, v := range tableConfig.ClassifyList {
  165. contractRanks, e := GetTopContractRank(v.Exchange, v.ClassifyNames, baseDate)
  166. if e != nil {
  167. err = fmt.Errorf("获取基准日期合约排名失败, %v", e)
  168. return
  169. }
  170. if len(contractRanks) == 0 {
  171. continue
  172. }
  173. // ps.正常来讲这里查出来的合约是唯一的, 根据品种分组, 取出ContractType所需的合约数
  174. for _, rd := range contractRanks {
  175. if classifyMax[rd.ClassifyName] >= contractMax {
  176. continue
  177. }
  178. classifyMax[rd.ClassifyName] += 1
  179. if exchangeContracts[rd.Exchange] == nil {
  180. exchangeContracts[rd.Exchange] = make([]*tradeAnalysisModel.ContractTopRankData, 0)
  181. }
  182. exchangeContracts[rd.Exchange] = append(exchangeContracts[rd.Exchange], rd)
  183. sortContract = append(sortContract, rd.ClassifyType)
  184. }
  185. }
  186. // 查询对应品种与合约一周前后的多空单,填充预估值
  187. mussyRows := make([]*tradeAnalysisModel.TableRowData, 0)
  188. for exchange, contracts := range exchangeContracts {
  189. var classifyNames, classifyTypes []string
  190. for _, v := range contracts {
  191. if !utils.InArrayByStr(classifyNames, v.ClassifyName) {
  192. classifyNames = append(classifyNames, v.ClassifyName)
  193. }
  194. if !utils.InArrayByStr(classifyTypes, v.ClassifyType) {
  195. classifyTypes = append(classifyTypes, v.ClassifyType)
  196. }
  197. }
  198. contractRowData, e := GetTableTradeData(exchange, classifyNames, classifyTypes, []string{tableConfig.CompanyName}, tableConfig.PredictRatio, baseDate.AddDate(0, 0, -5), baseDate.AddDate(0, 0, 5), tableConfig.ContractType)
  199. if e != nil {
  200. err = fmt.Errorf("获取公司合约多空单数据失败, %v", e)
  201. return
  202. }
  203. if len(contractRowData) == 0 {
  204. continue
  205. }
  206. // 计算行数据
  207. rows, e := CalculateTableRowData(exchange, baseDate, contracts, contractRowData)
  208. if e != nil {
  209. err = fmt.Errorf("计算合约数据失败, %v", e)
  210. return
  211. }
  212. mussyRows = append(mussyRows, rows...)
  213. }
  214. // 排序
  215. tableRows = make([]*tradeAnalysisModel.TableRowData, 0)
  216. contractRow := make(map[string]*tradeAnalysisModel.TableRowData)
  217. for _, v := range mussyRows {
  218. contractRow[v.ClassifyType] = v
  219. }
  220. for _, v := range sortContract {
  221. t := contractRow[v]
  222. if t != nil {
  223. tableRows = append(tableRows, t)
  224. }
  225. }
  226. return
  227. }