package trade_analysis import ( tradeAnalysisModel "eta/eta_api/models/data_manage/trade_analysis" "eta/eta_api/utils" "fmt" "math" "strings" "time" ) // CheckAnalysisTableExtraConfig 校验表格配置 func CheckAnalysisTableExtraConfig(extraConfig tradeAnalysisModel.TableExtraConfig) (pass bool, tips string) { if extraConfig.CompanyName == "" { tips = "请选择期货公司" return } if len(extraConfig.ClassifyList) == 0 { tips = "请选择品种" return } var classifyTotal int for _, v := range extraConfig.ClassifyList { if v.Exchange == "" { tips = "请选择交易所" return } if len(v.ClassifyNames) == 0 { tips = "请选择品种" return } classifyTotal += len(v.ClassifyNames) } // 品种选择加个上限吧,过多SQL会很慢 if classifyTotal > 20 { tips = "选择品种不超过20个" return } typeArr := []int{tradeAnalysisModel.ContractQueryTypeTop, tradeAnalysisModel.ContractQueryTypeTop2, tradeAnalysisModel.ContractQueryTypeTop3, tradeAnalysisModel.ContractQueryTypeAll, tradeAnalysisModel.ContractQueryTypeTotal} if !utils.InArrayByInt(typeArr, extraConfig.ContractType) { tips = "请选择正确的合约" return } if extraConfig.DateType == 1 && extraConfig.FixedDate == "" { tips = "请选择固定日期" return } if extraConfig.FixedDate != "" { _, e := time.Parse(utils.FormatDate, extraConfig.FixedDate) if e != nil { tips = "固定日期格式有误" return } } if extraConfig.PredictRatio < 0 || extraConfig.PredictRatio > 1 { tips = "请输入正确的估计参数" return } pass = true return } // GetAnalysisTableBaseDate 根据配置获取基准交易日期 func GetAnalysisTableBaseDate(dateType, intervalMove int, fixedDate string) (baseDate time.Time, err error) { if dateType == 1 { // 固定日期 t, _ := time.ParseInLocation(utils.FormatDate, fixedDate, time.Local) baseDate = t } else { // 最新交易日 st := time.Now().AddDate(0, 0, -7) // 默认前移7天, 在开始结束区间内取出指定交易日 if intervalMove > 0 { period := intervalMove * 7 st = st.AddDate(0, 0, -period) } tradeDates := utils.GetTradingDays(st, time.Now()) dateLen := len(tradeDates) if dateLen == 0 { err = fmt.Errorf("交易日序列异常") return } index := dateLen - 1 if intervalMove > 0 { index -= intervalMove } if index < 0 || index > dateLen { err = fmt.Errorf("交易日序列异常") return } baseDate = tradeDates[index] } return } // CalculateTableRowData 计算表格行数据 func CalculateTableRowData(exchange string, baseDate time.Time, topData []*tradeAnalysisModel.ContractTopRankData, contractsData []*tradeAnalysisModel.ContractCompanyTradeData) (rows []*tradeAnalysisModel.TableRowData, err error) { contractTopData := make(map[string]*tradeAnalysisModel.ContractTopRankData) for _, v := range topData { contractTopData[v.ClassifyType] = v } rows = make([]*tradeAnalysisModel.TableRowData, 0) for _, v := range contractsData { // 取出基准日期的数据 cd := new(tradeAnalysisModel.ContractCompanyTradeDataList) for _, d := range v.DataList { if d.Date.Equal(baseDate) { cd = d break } } // 合约基准日期无数据 if cd.Date.IsZero() { continue } td, ok := contractTopData[v.ClassifyType] if !ok { // 无前20数据 continue } row := new(tradeAnalysisModel.TableRowData) row.Exchange = exchange row.ClassifyName = td.ClassifyName row.ClassifyType = v.ClassifyType row.BuyValue = cd.BuyVal row.BuyChange = cd.BuyChange row.SoldValue = cd.SoldVal row.SoldChange = cd.SoldChange row.PureBuyVal = cd.PureBuyVal row.PureBuyChange = cd.PureBuyChange row.TopBuyValue = td.BuyValue row.TopSoldValue = td.SoldValue row.TopBuyChange = td.BuyChange row.TopSoldChange = td.SoldChange // 计算值 row.BuySoldRatio = math.Round(float64(cd.BuyVal)/float64(cd.BuyVal+cd.SoldVal)*100) / 100 row.BuyTopRatio = math.Round(float64(cd.BuyVal)/float64(td.BuyValue)*100) / 100 row.SoldTopRatio = math.Round(float64(cd.SoldVal)/float64(td.SoldValue)*100) / 100 row.TopPureBuy = td.BuyValue - td.SoldValue row.TopPureBuyChange = int(math.Abs(float64(td.BuyChange))) + int(math.Abs(float64(td.SoldChange))) // 净多变化=Abs(多单变化)+Abs(空单变化) row.TopBuySoldRatio = math.Round(float64(td.BuyValue)/float64(td.BuyValue+td.SoldValue)*100) / 100 rows = append(rows, row) } return } // GetTableRowsDataByConfig 根据配置获取表格行数据 func GetTableRowsDataByConfig(tableConfig tradeAnalysisModel.TableExtraConfig) (tableRows []*tradeAnalysisModel.TableRowData, err error) { // 基准日期 baseDate, e := GetAnalysisTableBaseDate(tableConfig.DateType, tableConfig.IntervalMove, tableConfig.FixedDate) if e != nil { err = fmt.Errorf("获取基准日期失败, %v", e) return } // 根据类型取出合约数 var contractMax int // 需要取出的品种对应的最大合约数 //classifyMax := make(map[string]int) // 品种对应的合约数 switch tableConfig.ContractType { case tradeAnalysisModel.ContractQueryTypeTop: contractMax = 1 case tradeAnalysisModel.ContractQueryTypeTop2: contractMax = 2 case tradeAnalysisModel.ContractQueryTypeTop3: contractMax = 3 case tradeAnalysisModel.ContractQueryTypeAll, tradeAnalysisModel.ContractQueryTypeTotal: contractMax = 999 } var sortRules []string // 最终排序(合约加总以品种排序,其他以为合约排序) classifyContractsData := make(map[string][]*tradeAnalysisModel.ContractTopRankData) // 根据品种分组的合约数据 classifyContracts := make(map[string][]string) // 品种合约 for _, v := range tableConfig.ClassifyList { for _, classify := range v.ClassifyNames { // 获取合约排名及持仓数据 contractRanks, e := GetTopContractRank(v.Exchange, []string{classify}, baseDate) if e != nil { err = fmt.Errorf("获取基准日期合约排名失败, %v", e) return } if len(contractRanks) == 0 { continue } flag := fmt.Sprintf("%s-%s", v.Exchange, classify) // 取出指定数量的合约 var contractNum int for _, rd := range contractRanks { if contractNum >= contractMax { continue } contractNum += 1 classifyContracts[classify] = append(classifyContracts[classify], rd.ClassifyType) if classifyContractsData[flag] == nil { classifyContractsData[flag] = make([]*tradeAnalysisModel.ContractTopRankData, 0) } classifyContractsData[flag] = append(classifyContractsData[flag], rd) // 以合约排序 if tableConfig.ContractType != tradeAnalysisModel.ContractQueryTypeTotal { sortRules = append(sortRules, rd.ClassifyType) } } // 以品种排序 if tableConfig.ContractType == tradeAnalysisModel.ContractQueryTypeTotal { sortRules = append(sortRules, classify) } } } mussyRows := make([]*tradeAnalysisModel.TableRowData, 0) for k, contracts := range classifyContractsData { var exchange, classifyName string keyArr := strings.Split(k, "-") if len(keyArr) != 2 { continue } exchange = keyArr[0] classifyName = keyArr[1] classifyTypes := classifyContracts[classifyName] if len(classifyTypes) == 0 { continue } // 合约加总时,contracts也需要加总,且ClassifyType为品种名 if tableConfig.ContractType == tradeAnalysisModel.ContractQueryTypeTotal { contracts = MergeClassifyTypeTopRankData(contracts) } contractRowData, e := GetTableTradeData(exchange, classifyName, classifyTypes, tableConfig.CompanyName, tableConfig.PredictRatio, baseDate.AddDate(0, 0, -5), baseDate.AddDate(0, 0, 5), tableConfig.ContractType) if e != nil { err = fmt.Errorf("获取公司合约多空单数据失败, %v", e) return } if len(contractRowData) == 0 { continue } // 计算行数据 rows, e := CalculateTableRowData(exchange, baseDate, contracts, contractRowData) if e != nil { err = fmt.Errorf("计算合约数据失败, %v", e) return } mussyRows = append(mussyRows, rows...) } // 排序 tableRows = make([]*tradeAnalysisModel.TableRowData, 0) contractRow := make(map[string]*tradeAnalysisModel.TableRowData) for _, v := range mussyRows { contractRow[v.ClassifyType] = v } for _, v := range sortRules { t := contractRow[v] if t != nil { tableRows = append(tableRows, t) } } return } // MergeClassifyTypeTopRankData 类型为合约加总时-合并当日的TOP数据 func MergeClassifyTypeTopRankData(classifyTypesData []*tradeAnalysisModel.ContractTopRankData) (mergedData []*tradeAnalysisModel.ContractTopRankData) { mergedData = make([]*tradeAnalysisModel.ContractTopRankData, 0) mergeData := new(tradeAnalysisModel.ContractTopRankData) for _, v := range classifyTypesData { mergeData.Exchange = v.Exchange mergeData.DealValue += v.DealValue mergeData.BuyValue += v.BuyValue mergeData.BuyChange += v.BuyChange mergeData.SoldValue += v.SoldValue mergeData.SoldChange += v.SoldChange mergeData.PureBuyValue += v.PureBuyValue mergeData.PureBuyChange += v.PureBuyChange mergeData.ClassifyName = v.ClassifyName mergeData.ClassifyType = v.ClassifyName // 合约合并后为品种名 mergeData.DataTime = v.DataTime } mergedData = append(mergedData, mergeData) return }