trade_analysis_table.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. "strings"
  8. "time"
  9. )
  10. // CheckAnalysisTableExtraConfig 校验表格配置
  11. func CheckAnalysisTableExtraConfig(extraConfig tradeAnalysisModel.TableExtraConfig) (pass bool, tips string) {
  12. if extraConfig.CompanyName == "" {
  13. tips = "请选择期货公司"
  14. return
  15. }
  16. if len(extraConfig.ClassifyList) == 0 {
  17. tips = "请选择品种"
  18. return
  19. }
  20. var classifyTotal int
  21. for _, v := range extraConfig.ClassifyList {
  22. if v.Exchange == "" {
  23. tips = "请选择交易所"
  24. return
  25. }
  26. if len(v.ClassifyNames) == 0 {
  27. tips = "请选择品种"
  28. return
  29. }
  30. classifyTotal += len(v.ClassifyNames)
  31. }
  32. // 品种选择加个上限吧,过多SQL会很慢
  33. if classifyTotal > 20 {
  34. tips = "选择品种不超过20个"
  35. return
  36. }
  37. typeArr := []int{tradeAnalysisModel.ContractQueryTypeTop, tradeAnalysisModel.ContractQueryTypeTop2, tradeAnalysisModel.ContractQueryTypeTop3, tradeAnalysisModel.ContractQueryTypeAll, tradeAnalysisModel.ContractQueryTypeTotal}
  38. if !utils.InArrayByInt(typeArr, extraConfig.ContractType) {
  39. tips = "请选择正确的合约"
  40. return
  41. }
  42. if extraConfig.DateType == 1 && extraConfig.FixedDate == "" {
  43. tips = "请选择固定日期"
  44. return
  45. }
  46. if extraConfig.FixedDate != "" {
  47. _, e := time.Parse(utils.FormatDate, extraConfig.FixedDate)
  48. if e != nil {
  49. tips = "固定日期格式有误"
  50. return
  51. }
  52. }
  53. if extraConfig.PredictRatio < 0 || extraConfig.PredictRatio > 1 {
  54. tips = "请输入正确的估计参数"
  55. return
  56. }
  57. pass = true
  58. return
  59. }
  60. // GetAnalysisTableBaseDate 根据配置获取基准交易日期
  61. func GetAnalysisTableBaseDate(dateType, intervalMove int, fixedDate string) (baseDate time.Time, err error) {
  62. if dateType == 1 {
  63. // 固定日期
  64. t, _ := time.ParseInLocation(utils.FormatDate, fixedDate, time.Local)
  65. baseDate = t
  66. } else {
  67. // 最新交易日
  68. st := time.Now().AddDate(0, 0, -7) // 默认前移7天, 在开始结束区间内取出指定交易日
  69. if intervalMove > 0 {
  70. period := intervalMove * 7
  71. st = st.AddDate(0, 0, -period)
  72. }
  73. tradeDates := utils.GetTradingDays(st, time.Now())
  74. dateLen := len(tradeDates)
  75. if dateLen == 0 {
  76. err = fmt.Errorf("交易日序列异常")
  77. return
  78. }
  79. index := dateLen - 1
  80. if intervalMove > 0 {
  81. index -= intervalMove
  82. }
  83. if index < 0 || index > dateLen {
  84. err = fmt.Errorf("交易日序列异常")
  85. return
  86. }
  87. baseDate = tradeDates[index]
  88. }
  89. return
  90. }
  91. // CalculateTableRowData 计算表格行数据
  92. func CalculateTableRowData(exchange string, baseDate time.Time, topData []*tradeAnalysisModel.ContractTopRankData, contractsData []*tradeAnalysisModel.ContractCompanyTradeData) (rows []*tradeAnalysisModel.TableRowData, err error) {
  93. contractTopData := make(map[string]*tradeAnalysisModel.ContractTopRankData)
  94. for _, v := range topData {
  95. contractTopData[v.ClassifyType] = v
  96. }
  97. rows = make([]*tradeAnalysisModel.TableRowData, 0)
  98. for _, v := range contractsData {
  99. // 取出基准日期的数据
  100. cd := new(tradeAnalysisModel.ContractCompanyTradeDataList)
  101. for _, d := range v.DataList {
  102. if d.Date.Equal(baseDate) {
  103. cd = d
  104. break
  105. }
  106. }
  107. // 合约基准日期无数据
  108. if cd.Date.IsZero() {
  109. continue
  110. }
  111. td, ok := contractTopData[v.ClassifyType]
  112. if !ok {
  113. // 无前20数据
  114. continue
  115. }
  116. row := new(tradeAnalysisModel.TableRowData)
  117. row.Exchange = exchange
  118. row.ClassifyName = td.ClassifyName
  119. row.ClassifyType = v.ClassifyType
  120. row.BuyValue = cd.BuyVal
  121. row.BuyChange = cd.BuyChange
  122. row.SoldValue = cd.SoldVal
  123. row.SoldChange = cd.SoldChange
  124. row.PureBuyVal = cd.PureBuyVal
  125. row.PureBuyChange = cd.PureBuyChange
  126. row.TopBuyValue = td.BuyValue
  127. row.TopSoldValue = td.SoldValue
  128. row.TopBuyChange = td.BuyChange
  129. row.TopSoldChange = td.SoldChange
  130. // 计算值
  131. row.BuySoldRatio = math.Round(float64(cd.BuyVal)/float64(cd.BuyVal+cd.SoldVal)*100) / 100
  132. row.BuyTopRatio = math.Round(float64(cd.BuyVal)/float64(td.BuyValue)*100) / 100
  133. row.SoldTopRatio = math.Round(float64(cd.SoldVal)/float64(td.SoldValue)*100) / 100
  134. row.TopPureBuy = td.BuyValue - td.SoldValue
  135. row.TopPureBuyChange = int(math.Abs(float64(td.BuyChange))) + int(math.Abs(float64(td.SoldChange))) // 净多变化=Abs(多单变化)+Abs(空单变化)
  136. row.TopBuySoldRatio = math.Round(float64(td.BuyValue)/float64(td.BuyValue+td.SoldValue)*100) / 100
  137. rows = append(rows, row)
  138. }
  139. return
  140. }
  141. // GetTableRowsDataByConfig 根据配置获取表格行数据
  142. func GetTableRowsDataByConfig(tableConfig tradeAnalysisModel.TableExtraConfig) (tableRows []*tradeAnalysisModel.TableRowData, err error) {
  143. // 基准日期
  144. baseDate, e := GetAnalysisTableBaseDate(tableConfig.DateType, tableConfig.IntervalMove, tableConfig.FixedDate)
  145. if e != nil {
  146. err = fmt.Errorf("获取基准日期失败, %v", e)
  147. return
  148. }
  149. // 根据类型取出合约数
  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. var sortRules []string // 最终排序(合约加总以品种排序,其他以为合约排序)
  163. classifyContractsData := make(map[string][]*tradeAnalysisModel.ContractTopRankData) // 根据品种分组的合约数据
  164. classifyContracts := make(map[string][]string) // 品种合约
  165. for _, v := range tableConfig.ClassifyList {
  166. for _, classify := range v.ClassifyNames {
  167. // 获取合约排名及持仓数据
  168. contractRanks, e := GetTopContractRank(v.Exchange, []string{classify}, baseDate)
  169. if e != nil {
  170. err = fmt.Errorf("获取基准日期合约排名失败, %v", e)
  171. return
  172. }
  173. if len(contractRanks) == 0 {
  174. continue
  175. }
  176. flag := fmt.Sprintf("%s-%s", v.Exchange, classify)
  177. // 取出指定数量的合约
  178. var contractNum int
  179. for _, rd := range contractRanks {
  180. if contractNum >= contractMax {
  181. continue
  182. }
  183. contractNum += 1
  184. classifyContracts[classify] = append(classifyContracts[classify], rd.ClassifyType)
  185. if classifyContractsData[flag] == nil {
  186. classifyContractsData[flag] = make([]*tradeAnalysisModel.ContractTopRankData, 0)
  187. }
  188. classifyContractsData[flag] = append(classifyContractsData[flag], rd)
  189. // 以合约排序
  190. if tableConfig.ContractType != tradeAnalysisModel.ContractQueryTypeTotal {
  191. sortRules = append(sortRules, rd.ClassifyType)
  192. }
  193. }
  194. // 以品种排序
  195. if tableConfig.ContractType == tradeAnalysisModel.ContractQueryTypeTotal {
  196. sortRules = append(sortRules, classify)
  197. }
  198. }
  199. }
  200. mussyRows := make([]*tradeAnalysisModel.TableRowData, 0)
  201. for k, contracts := range classifyContractsData {
  202. var exchange, classifyName string
  203. keyArr := strings.Split(k, "-")
  204. if len(keyArr) != 2 {
  205. continue
  206. }
  207. exchange = keyArr[0]
  208. classifyName = keyArr[1]
  209. classifyTypes := classifyContracts[classifyName]
  210. if len(classifyTypes) == 0 {
  211. continue
  212. }
  213. // 合约加总时,contracts也需要加总,且ClassifyType为品种名
  214. if tableConfig.ContractType == tradeAnalysisModel.ContractQueryTypeTotal {
  215. contracts = MergeClassifyTypeTopRankData(contracts)
  216. }
  217. contractRowData, e := GetTableTradeData(exchange, classifyName, classifyTypes, tableConfig.CompanyName, tableConfig.PredictRatio, baseDate.AddDate(0, 0, -5), baseDate.AddDate(0, 0, 5), tableConfig.ContractType)
  218. if e != nil {
  219. err = fmt.Errorf("获取公司合约多空单数据失败, %v", e)
  220. return
  221. }
  222. if len(contractRowData) == 0 {
  223. continue
  224. }
  225. // 计算行数据
  226. rows, e := CalculateTableRowData(exchange, baseDate, contracts, contractRowData)
  227. if e != nil {
  228. err = fmt.Errorf("计算合约数据失败, %v", e)
  229. return
  230. }
  231. mussyRows = append(mussyRows, rows...)
  232. }
  233. // 排序
  234. tableRows = make([]*tradeAnalysisModel.TableRowData, 0)
  235. contractRow := make(map[string]*tradeAnalysisModel.TableRowData)
  236. for _, v := range mussyRows {
  237. contractRow[v.ClassifyType] = v
  238. }
  239. for _, v := range sortRules {
  240. t := contractRow[v]
  241. if t != nil {
  242. tableRows = append(tableRows, t)
  243. }
  244. }
  245. return
  246. }
  247. // MergeClassifyTypeTopRankData 类型为合约加总时-合并当日的TOP数据
  248. func MergeClassifyTypeTopRankData(classifyTypesData []*tradeAnalysisModel.ContractTopRankData) (mergedData []*tradeAnalysisModel.ContractTopRankData) {
  249. mergedData = make([]*tradeAnalysisModel.ContractTopRankData, 0)
  250. mergeData := new(tradeAnalysisModel.ContractTopRankData)
  251. for _, v := range classifyTypesData {
  252. mergeData.Exchange = v.Exchange
  253. mergeData.DealValue += v.DealValue
  254. mergeData.BuyValue += v.BuyValue
  255. mergeData.BuyChange += v.BuyChange
  256. mergeData.SoldValue += v.SoldValue
  257. mergeData.SoldChange += v.SoldChange
  258. mergeData.PureBuyValue += v.PureBuyValue
  259. mergeData.PureBuyChange += v.PureBuyChange
  260. mergeData.ClassifyName = v.ClassifyName
  261. mergeData.ClassifyType = v.ClassifyName // 合约合并后为品种名
  262. mergeData.DataTime = v.DataTime
  263. }
  264. mergedData = append(mergedData, mergeData)
  265. return
  266. }