package trade_analysis import ( "eta/eta_index_lib/models" tradeAnalysisModel "eta/eta_index_lib/models/trade_analysis" "eta/eta_index_lib/utils" "fmt" "sort" "strings" "time" ) // FormatCompanyTradeData2EdbData [公司-合约加总]转为指标数据 func FormatCompanyTradeData2EdbData(companyTradeData *tradeAnalysisModel.ContractCompanyTradeData, tradeType int) (edbData []*models.EdbDataList, err error) { if companyTradeData == nil { err = fmt.Errorf("持仓数据异常") return } edbData = make([]*models.EdbDataList, 0) var minData, maxData float64 for dk, dv := range companyTradeData.DataList { // 交易方向 var val float64 if tradeType == tradeAnalysisModel.WarehouseBuyChartType { if dv.BuyValType == tradeAnalysisModel.TradeDataTypeNull { continue } val = float64(dv.BuyVal) } if tradeType == tradeAnalysisModel.WarehouseSoldChartType { if dv.SoldValType == tradeAnalysisModel.TradeDataTypeNull { continue } val = float64(dv.SoldVal) } if tradeType == tradeAnalysisModel.WarehousePureBuyChartType { if dv.PureBuyValType == tradeAnalysisModel.TradeDataTypeNull { continue } val = float64(dv.PureBuyVal) } if dk == 0 { minData = val maxData = val } if val < minData { minData = val } if val > maxData { maxData = val } edbData = append(edbData, &models.EdbDataList{ DataTime: dv.Date.Format(utils.FormatDate), DataTimestamp: dv.Date.UnixNano() / 1e6, Value: val, }) } return } func GetWarehouseTradeData(exchange, classifyName string, contracts, companies []string, predictRatio float64) (companyTradeData []*tradeAnalysisModel.ContractCompanyTradeData, err error) { // 获取合约持仓数据 contractTradeData, lastBuyVal, lastSoldVal, e := GetContractCompanyTradeData(exchange, []string{classifyName}, contracts, companies, time.Time{}, time.Time{}) if e != nil { err = fmt.Errorf("获取合约-持仓数据失败, %v", e) return } // 填充[合约-公司]预估数据, 并根据[公司-多合约]分组, [公司]算作一个指标, 指标值为[多个合约]的计算加总 companyContracts := make(map[string][]*tradeAnalysisModel.ContractCompanyTradeData) for _, v := range contractTradeData { td, fd, ed, e := PredictingTradeData(v.DataList, lastBuyVal[v.ClassifyType], lastSoldVal[v.ClassifyType], predictRatio) if e != nil { err = fmt.Errorf("数据补全失败, %v", e) return } v.DataList = td v.StartDate = fd v.EndDate = ed if companyContracts[v.CompanyName] == nil { companyContracts[v.CompanyName] = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0) } companyContracts[v.CompanyName] = append(companyContracts[v.CompanyName], v) } // 以[公司]为组, 计算合约加总 mussyTradeData := make(map[string]*tradeAnalysisModel.ContractCompanyTradeData) for k, v := range companyContracts { companyData := new(tradeAnalysisModel.ContractCompanyTradeData) companyData.CompanyName = k companyData.DataList = make([]*tradeAnalysisModel.ContractCompanyTradeDataList, 0) contractArr := make([]string, 0) // 合约加总 sumDateData := make(map[time.Time]*tradeAnalysisModel.ContractCompanyTradeDataList) for _, vv := range v { contractArr = append(contractArr, vv.ClassifyType) for _, dv := range vv.DataList { if sumDateData[dv.Date] == nil { sumDateData[dv.Date] = new(tradeAnalysisModel.ContractCompanyTradeDataList) sumDateData[dv.Date].Date = dv.Date } // 数据类型以第一个非零值为准, 只处理多空和净多, 变化就不管了 if sumDateData[dv.Date].BuyValType == tradeAnalysisModel.TradeDataTypeNull && dv.BuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].BuyValType = dv.BuyValType } if sumDateData[dv.Date].BuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.BuyValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].BuyValType = dv.BuyValType } if dv.BuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].BuyVal += dv.BuyVal } // 空单 if sumDateData[dv.Date].SoldValType == tradeAnalysisModel.TradeDataTypeNull && dv.SoldValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].SoldValType = dv.SoldValType } if sumDateData[dv.Date].SoldValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.SoldValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].SoldValType = dv.SoldValType } if dv.SoldValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].SoldVal += dv.SoldVal } // 净多单 if sumDateData[dv.Date].PureBuyValType == tradeAnalysisModel.TradeDataTypeNull && dv.PureBuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].PureBuyValType = dv.PureBuyValType } if sumDateData[dv.Date].PureBuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.PureBuyValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].PureBuyValType = dv.PureBuyValType } if dv.PureBuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].PureBuyVal += dv.PureBuyVal } } // 多个合约比对开始结束时间 if companyData.StartDate.IsZero() { companyData.StartDate = vv.StartDate } if vv.StartDate.Before(companyData.StartDate) { companyData.StartDate = vv.StartDate } if companyData.EndDate.IsZero() { companyData.EndDate = vv.EndDate } if vv.EndDate.Before(companyData.EndDate) { companyData.EndDate = vv.EndDate } } for _, sv := range sumDateData { companyData.DataList = append(companyData.DataList, sv) } sort.Slice(companyData.DataList, func(i, j int) bool { return companyData.DataList[i].Date.Before(companyData.DataList[j].Date) }) companyData.ClassifyType = strings.Join(contractArr, ",") mussyTradeData[k] = companyData } // 数据根据公司排序, 不然会随机乱 companyTradeData = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0) for _, v := range companies { // 没数据也需要加进去, 不然edbList会少 if mussyTradeData[v] == nil { companyData := new(tradeAnalysisModel.ContractCompanyTradeData) companyData.CompanyName = v companyData.DataList = make([]*tradeAnalysisModel.ContractCompanyTradeDataList, 0) companyTradeData = append(companyTradeData, companyData) continue } companyTradeData = append(companyTradeData, mussyTradeData[v]) } return } // PredictingTradeData 根据数据库中的多空数据填充预估数据 func PredictingTradeData(originData []*tradeAnalysisModel.ContractCompanyTradeDataList, lastBuyDateVal, lastSoldDateVal map[time.Time]int, predictRatio float64) (newData []*tradeAnalysisModel.ContractCompanyTradeDataList, firstDate, endDate time.Time, err error) { // 测试用的验证数据 //lastBuyDateVal, lastSoldDateVal = make(map[time.Time]int), make(map[time.Time]int) //lastBuyDateVal[time.Date(2024, 7, 16, 0, 0, 0, 0, time.Local)] = 4602 //lastBuyDateVal[time.Date(2024, 7, 17, 0, 0, 0, 0, time.Local)] = 5116 //lastBuyDateVal[time.Date(2024, 7, 18, 0, 0, 0, 0, time.Local)] = 5130 //lastBuyDateVal[time.Date(2024, 7, 19, 0, 0, 0, 0, time.Local)] = 5354 //lastBuyDateVal[time.Date(2024, 7, 22, 0, 0, 0, 0, time.Local)] = 5916 //lastBuyDateVal[time.Date(2024, 7, 23, 0, 0, 0, 0, time.Local)] = 6524 //lastBuyDateVal[time.Date(2024, 7, 26, 0, 0, 0, 0, time.Local)] = 6575 //lastBuyDateVal[time.Date(2024, 7, 29, 0, 0, 0, 0, time.Local)] = 7461 //lastBuyDateVal[time.Date(2024, 7, 30, 0, 0, 0, 0, time.Local)] = 8488 // //lastSoldDateVal[time.Date(2024, 7, 11, 0, 0, 0, 0, time.Local)] = 5467 //lastSoldDateVal[time.Date(2024, 7, 12, 0, 0, 0, 0, time.Local)] = 5248 //lastSoldDateVal[time.Date(2024, 7, 15, 0, 0, 0, 0, time.Local)] = 5102 //lastSoldDateVal[time.Date(2024, 7, 16, 0, 0, 0, 0, time.Local)] = 4771 //lastSoldDateVal[time.Date(2024, 7, 23, 0, 0, 0, 0, time.Local)] = 5989 //lastSoldDateVal[time.Date(2024, 7, 26, 0, 0, 0, 0, time.Local)] = 6745 //lastSoldDateVal[time.Date(2024, 7, 30, 0, 0, 0, 0, time.Local)] = 7272 // //originData = make([]*tradeAnalysisModel.ContractCompanyTradeDataList, 0) //originData = append(originData, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 10, 0, 0, 0, 0, time.Local), // BuyVal: 14324, // BuyValType: tradeAnalysisModel.TradeDataTypeOrigin, // BuyChange: -1107, // BuyChangeType: tradeAnalysisModel.TradeDataTypeOrigin, // SoldVal: 0, // SoldValType: tradeAnalysisModel.TradeDataTypeNull, // SoldChange: 0, // SoldChangeType: tradeAnalysisModel.TradeDataTypeNull, //}, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 11, 0, 0, 0, 0, time.Local), // BuyVal: 14280, // BuyValType: tradeAnalysisModel.TradeDataTypeOrigin, // BuyChange: -44, // BuyChangeType: tradeAnalysisModel.TradeDataTypeOrigin, //}, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 12, 0, 0, 0, 0, time.Local), // BuyVal: 14214, // BuyValType: tradeAnalysisModel.TradeDataTypeOrigin, // BuyChange: -66, // BuyChangeType: tradeAnalysisModel.TradeDataTypeOrigin, //}, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 15, 0, 0, 0, 0, time.Local), // BuyVal: 14269, // BuyValType: tradeAnalysisModel.TradeDataTypeOrigin, // BuyChange: 55, // BuyChangeType: tradeAnalysisModel.TradeDataTypeOrigin, //}, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 17, 0, 0, 0, 0, time.Local), // SoldVal: 5254, // SoldValType: tradeAnalysisModel.TradeDataTypeOrigin, // SoldChange: 708, // SoldChangeType: tradeAnalysisModel.TradeDataTypeOrigin, //}, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 18, 0, 0, 0, 0, time.Local), // SoldVal: 6595, // SoldValType: tradeAnalysisModel.TradeDataTypeOrigin, // SoldChange: 1341, // SoldChangeType: tradeAnalysisModel.TradeDataTypeOrigin, //}, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 19, 0, 0, 0, 0, time.Local), // SoldVal: 5938, // SoldValType: tradeAnalysisModel.TradeDataTypeOrigin, // SoldChange: -657, // SoldChangeType: tradeAnalysisModel.TradeDataTypeOrigin, //}, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 22, 0, 0, 0, 0, time.Local), // SoldVal: 6131, // SoldValType: tradeAnalysisModel.TradeDataTypeOrigin, // SoldChange: 193, // SoldChangeType: tradeAnalysisModel.TradeDataTypeOrigin, //}, &tradeAnalysisModel.ContractCompanyTradeDataList{ // Date: time.Date(2024, 7, 29, 0, 0, 0, 0, time.Local), // SoldVal: 6679, // SoldValType: tradeAnalysisModel.TradeDataTypeOrigin, // SoldChange: 312, // SoldChangeType: tradeAnalysisModel.TradeDataTypeOrigin, //}) if len(originData) == 0 { return } if predictRatio < 0 || predictRatio > 1 { err = fmt.Errorf("估计参数不在0-1之间") return } sort.Slice(originData, func(i, j int) bool { return originData[i].Date.Before(originData[j].Date) }) dateVal := make(map[time.Time]*tradeAnalysisModel.ContractCompanyTradeDataList) for _, v := range originData { dateVal[v.Date] = v } // 生成开始日期-1d(可能会往前面推算一天)至结束日期间的交易日, 以交易日为时间序列遍历 tradeDays := utils.GetTradingDays(originData[0].Date.AddDate(0, 0, -1), originData[len(originData)-1].Date) for k, v := range tradeDays { // T日多空均无的情况 //bothLast := false if dateVal[v] == nil { // T-1和T+1[原始数据]均无值, 那么T日无数据 hasPrev, hasNext := false, false if k-1 >= 0 { hasPrev = true } if k+1 <= len(tradeDays)-1 { hasNext = true } if !hasPrev && !hasNext { continue } // T+1有值, 优先从T+1推, 然后继续走下面计算净多单的逻辑 if hasNext { nextDay := tradeDays[k+1] if dateVal[nextDay] != nil { // T+1有多/空及多空变化, 且是原始数据, 那么推出数据并在map中新加一日数据 if dateVal[nextDay].BuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dateVal[nextDay].BuyChangeType == tradeAnalysisModel.TradeDataTypeOrigin { if _, ok := dateVal[v]; !ok { dateVal[v] = new(tradeAnalysisModel.ContractCompanyTradeDataList) dateVal[v].Date = v } dateVal[v].BuyVal = dateVal[nextDay].BuyVal - dateVal[nextDay].BuyChange dateVal[v].BuyValType = tradeAnalysisModel.TradeDataTypeOrigin } if dateVal[nextDay].SoldValType == tradeAnalysisModel.TradeDataTypeOrigin && dateVal[nextDay].SoldChangeType == tradeAnalysisModel.TradeDataTypeOrigin { if _, ok := dateVal[v]; !ok { dateVal[v] = new(tradeAnalysisModel.ContractCompanyTradeDataList) dateVal[v].Date = v } dateVal[v].SoldVal = dateVal[nextDay].SoldVal - dateVal[nextDay].SoldChange dateVal[v].SoldValType = tradeAnalysisModel.TradeDataTypeOrigin } } } // T+1没推出来而T-1有值, 那么T多空均取末位, 计算净多单 _, has := dateVal[v] if hasPrev && !has { sv, sok := lastSoldDateVal[v] bv, bok := lastBuyDateVal[v] if !sok && !bok { continue } dateVal[v] = new(tradeAnalysisModel.ContractCompanyTradeDataList) dateVal[v].Date = v if sok { dateVal[v].SoldVal = int(predictRatio*float64(sv) + 0.5) dateVal[v].SoldValType = tradeAnalysisModel.TradeDataTypeCalculate } if bok { dateVal[v].BuyVal = int(predictRatio*float64(bv) + 0.5) dateVal[v].BuyValType = tradeAnalysisModel.TradeDataTypeCalculate } if dateVal[v].BuyValType > tradeAnalysisModel.TradeDataTypeNull && dateVal[v].SoldValType > tradeAnalysisModel.TradeDataTypeNull { dateVal[v].PureBuyVal = dateVal[v].BuyVal - dateVal[v].SoldVal dateVal[v].PureBuyValType = tradeAnalysisModel.TradeDataTypeCalculate } continue } } // 多空均有的情况下计算净多单 if dateVal[v].BuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dateVal[v].SoldValType == tradeAnalysisModel.TradeDataTypeOrigin { dateVal[v].PureBuyVal = dateVal[v].BuyVal - dateVal[v].SoldVal dateVal[v].PureBuyValType = tradeAnalysisModel.TradeDataTypeOrigin // 原始值算出来的也作原始值 } // 仅有多单, 空单取末位, 计算净多单 if dateVal[v].BuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dateVal[v].SoldValType == tradeAnalysisModel.TradeDataTypeNull { if sv, ok := lastSoldDateVal[v]; ok { dateVal[v].SoldVal = int(predictRatio*float64(sv) + 0.5) // 估计参数*末位值, 向上取整 dateVal[v].SoldValType = tradeAnalysisModel.TradeDataTypeCalculate dateVal[v].PureBuyVal = dateVal[v].BuyVal - dateVal[v].SoldVal dateVal[v].PureBuyValType = tradeAnalysisModel.TradeDataTypeCalculate } } // 仅有空单, 多单取末位, 计算净多单 if dateVal[v].SoldValType == tradeAnalysisModel.TradeDataTypeOrigin && dateVal[v].BuyValType == tradeAnalysisModel.TradeDataTypeNull { if sv, ok := lastBuyDateVal[v]; ok { dateVal[v].BuyVal = int(predictRatio*float64(sv) + 0.5) dateVal[v].BuyValType = tradeAnalysisModel.TradeDataTypeCalculate dateVal[v].PureBuyVal = dateVal[v].BuyVal - dateVal[v].SoldVal dateVal[v].PureBuyValType = tradeAnalysisModel.TradeDataTypeCalculate } } } // 二次遍历, 计算与T-1的变化值 for k, v := range tradeDays { // 无T/T-1数据, 忽略 if dateVal[v] == nil { continue } if k-1 < 0 { continue } beforeDay := tradeDays[k-1] if dateVal[beforeDay] == nil { continue } // 多单变化 if dateVal[v].BuyChangeType == tradeAnalysisModel.TradeDataTypeNull { if dateVal[v].BuyValType > tradeAnalysisModel.TradeDataTypeNull && dateVal[beforeDay].BuyValType > tradeAnalysisModel.TradeDataTypeNull { dateVal[v].BuyChange = dateVal[v].BuyVal - dateVal[beforeDay].BuyVal // 如果当日多单或者前日多单是估计值, 那么多单变化也为估计值 if dateVal[v].BuyValType == tradeAnalysisModel.TradeDataTypeCalculate || dateVal[beforeDay].BuyValType == tradeAnalysisModel.TradeDataTypeCalculate { dateVal[v].BuyChangeType = tradeAnalysisModel.TradeDataTypeCalculate } } } // 空单变化 if dateVal[v].SoldChangeType == tradeAnalysisModel.TradeDataTypeNull { if dateVal[v].SoldValType > tradeAnalysisModel.TradeDataTypeNull && dateVal[beforeDay].SoldValType > tradeAnalysisModel.TradeDataTypeNull { dateVal[v].SoldChange = dateVal[v].SoldVal - dateVal[beforeDay].SoldVal // 如果当日空单或者前日空单是估计值, 那么空单变化也为估计值 if dateVal[v].SoldValType == tradeAnalysisModel.TradeDataTypeCalculate || dateVal[beforeDay].SoldValType == tradeAnalysisModel.TradeDataTypeCalculate { dateVal[v].SoldChangeType = tradeAnalysisModel.TradeDataTypeCalculate } } } // 净多变化 if dateVal[v].PureBuyChangeType == tradeAnalysisModel.TradeDataTypeNull { if dateVal[v].PureBuyValType > tradeAnalysisModel.TradeDataTypeNull && dateVal[beforeDay].PureBuyValType > tradeAnalysisModel.TradeDataTypeNull { dateVal[v].PureBuyChange = dateVal[v].PureBuyVal - dateVal[beforeDay].PureBuyVal dateVal[v].PureBuyChangeType = tradeAnalysisModel.TradeDataTypeOrigin // 如果当日净多单或者前日净多单是估计值, 那么净多单变化也为估计值 if dateVal[v].PureBuyValType == tradeAnalysisModel.TradeDataTypeCalculate || dateVal[beforeDay].PureBuyValType == tradeAnalysisModel.TradeDataTypeCalculate { dateVal[v].PureBuyChangeType = tradeAnalysisModel.TradeDataTypeCalculate } } } } // 重新遍历map, 生成数据序列并排序 newData = make([]*tradeAnalysisModel.ContractCompanyTradeDataList, 0) for _, v := range dateVal { if v.BuyValType == tradeAnalysisModel.TradeDataTypeNull && v.SoldValType == tradeAnalysisModel.TradeDataTypeNull { continue } newData = append(newData, v) } sort.Slice(newData, func(i, j int) bool { return newData[i].Date.Before(newData[j].Date) }) if len(newData) > 0 { firstDate = newData[0].Date endDate = newData[len(newData)-1].Date } return } // GetTopContractRank 获取TOP20根据成交量的合约排名 func GetTopContractRank(exchange string, classifyNames []string, dataDate time.Time) (items []*tradeAnalysisModel.ContractTopRankData, err error) { // 郑商所/广期所查询方式不一样 var tradeAnalysis TradeAnalysisInterface switch exchange { case tradeAnalysisModel.TradeExchangeZhengzhou: tradeAnalysis = &ZhengzhouTradeAnalysis{} case tradeAnalysisModel.TradeExchangeGuangzhou: tradeAnalysis = &GuangzhouTradeAnalysis{} default: tradeAnalysis = &BaseTradeAnalysis{} } // 郑商所-需要把所选品种转为实际合约进行后续的查询 if exchange == tradeAnalysisModel.TradeExchangeZhengzhou { classifies, e := GetZhengzhouContractsByClassifyNames(classifyNames) if e != nil { err = fmt.Errorf("获取郑商所实际合约失败, %v", e) return } classifyNames = classifies } // 获取多单/空单原始数据 rankData, e := tradeAnalysis.GetContractTopRankData(exchange, classifyNames, dataDate) if e != nil { err = fmt.Errorf("获取多空单原始数据失败, %v", e) return } items = make([]*tradeAnalysisModel.ContractTopRankData, 0) for _, v := range rankData { v.Exchange = exchange // 郑商所-这里注意把查出来的品种和合约赋值,不然后续是乱的 if v.Exchange == tradeAnalysisModel.TradeExchangeZhengzhou { v.ClassifyType = v.ClassifyName v.ClassifyName = GetZhengzhouClassifyName(v.ClassifyName) } items = append(items, v) } return } // GetTableTradeData 获取多空分析表格持仓数据 func GetTableTradeData(exchange string, classifyName string, contracts []string, companyName string, predictRatio float64, startDate, endDate time.Time, contractType int) (companyTradeData []*tradeAnalysisModel.ContractCompanyTradeData, err error) { companyTradeData = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0) // 获取合约持仓数据 contractTradeData, lastBuyVal, lastSoldVal, e := GetContractCompanyTradeData(exchange, []string{classifyName}, contracts, []string{companyName}, startDate, endDate) if e != nil { err = fmt.Errorf("获取合约-持仓数据失败, %v", e) return } // 填充[合约-公司]预估数据, 并根据[公司-多合约]分组, [公司]算作一个指标, 指标值为[多个合约]的计算加总 companyContracts := make(map[string][]*tradeAnalysisModel.ContractCompanyTradeData) for _, v := range contractTradeData { td, fd, ed, e := PredictingTradeData(v.DataList, lastBuyVal[v.ClassifyType], lastSoldVal[v.ClassifyType], predictRatio) if e != nil { err = fmt.Errorf("数据补全失败, %v", e) return } v.DataList = td v.StartDate = fd v.EndDate = ed // 合约类型参数不为合约加总时, 每个合约算一行数据 if contractType != tradeAnalysisModel.ContractQueryTypeTotal { companyTradeData = append(companyTradeData, v) continue } // 往下计算合约加总 if companyContracts[v.CompanyName] == nil { companyContracts[v.CompanyName] = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0) } companyContracts[v.CompanyName] = append(companyContracts[v.CompanyName], v) } // 类型为合约加总才往下合并 if contractType != tradeAnalysisModel.ContractQueryTypeTotal { return } // 以[公司]为组, 计算合约加总 for k, v := range companyContracts { companyData := new(tradeAnalysisModel.ContractCompanyTradeData) companyData.CompanyName = k companyData.DataList = make([]*tradeAnalysisModel.ContractCompanyTradeDataList, 0) contractArr := make([]string, 0) // 合约加总 sumDateData := make(map[time.Time]*tradeAnalysisModel.ContractCompanyTradeDataList) for _, vv := range v { contractArr = append(contractArr, vv.ClassifyType) for _, dv := range vv.DataList { if sumDateData[dv.Date] == nil { sumDateData[dv.Date] = new(tradeAnalysisModel.ContractCompanyTradeDataList) sumDateData[dv.Date].Date = dv.Date } // 数据类型以第一个非零值为准, 只处理多空和净多, 变化就不管了 if sumDateData[dv.Date].BuyValType == tradeAnalysisModel.TradeDataTypeNull && dv.BuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].BuyValType = dv.BuyValType } if sumDateData[dv.Date].BuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.BuyValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].BuyValType = dv.BuyValType } if dv.BuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].BuyVal += dv.BuyVal } // 空单 if sumDateData[dv.Date].SoldValType == tradeAnalysisModel.TradeDataTypeNull && dv.SoldValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].SoldValType = dv.SoldValType } if sumDateData[dv.Date].SoldValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.SoldValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].SoldValType = dv.SoldValType } if dv.SoldValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].SoldVal += dv.SoldVal } // 净多单 if sumDateData[dv.Date].PureBuyValType == tradeAnalysisModel.TradeDataTypeNull && dv.PureBuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].PureBuyValType = dv.PureBuyValType } if sumDateData[dv.Date].PureBuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.PureBuyValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].PureBuyValType = dv.PureBuyValType } if dv.PureBuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].PureBuyVal += dv.PureBuyVal } } // 多个合约比对开始结束时间 if companyData.StartDate.IsZero() { companyData.StartDate = vv.StartDate } if vv.StartDate.Before(companyData.StartDate) { companyData.StartDate = vv.StartDate } if companyData.EndDate.IsZero() { companyData.EndDate = vv.EndDate } if vv.EndDate.Before(companyData.EndDate) { companyData.EndDate = vv.EndDate } } for _, sv := range sumDateData { companyData.DataList = append(companyData.DataList, sv) } sort.Slice(companyData.DataList, func(i, j int) bool { return companyData.DataList[i].Date.Before(companyData.DataList[j].Date) }) //companyData.ClassifyType = strings.Join(contractArr, ",") companyData.Exchange = exchange companyData.CompanyName = k companyData.ClassifyType = classifyName companyTradeData = append(companyTradeData, companyData) } return } // GetCorrelationTableTradeData 获取相关性表格持仓数据 func GetCorrelationTableTradeData(exchange string, classifyName string, contracts, companies []string, predictRatio float64, contractType int) (companyTradeData []*tradeAnalysisModel.ContractCompanyTradeData, err error) { companyTradeData = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0) // 获取合约持仓数据 contractTradeData, lastBuyVal, lastSoldVal, e := GetContractCompanyTradeData(exchange, []string{classifyName}, contracts, companies, time.Time{}, time.Time{}) if e != nil { err = fmt.Errorf("获取合约-持仓数据失败, %v", e) return } // 填充[合约-公司]预估数据, 并根据[公司-多合约]分组, [公司]算作一个指标, 指标值为[多个合约]的计算加总 companyContracts := make(map[string][]*tradeAnalysisModel.ContractCompanyTradeData) for _, v := range contractTradeData { td, fd, ed, e := PredictingTradeData(v.DataList, lastBuyVal[v.ClassifyType], lastSoldVal[v.ClassifyType], predictRatio) if e != nil { err = fmt.Errorf("数据补全失败, %v", e) return } v.DataList = td v.StartDate = fd v.EndDate = ed // 合约类型参数不为合约加总时, 每个合约算一行数据 if contractType != tradeAnalysisModel.ContractQueryTypeTotal { companyTradeData = append(companyTradeData, v) continue } // 往下计算合约加总 if companyContracts[v.CompanyName] == nil { companyContracts[v.CompanyName] = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0) } companyContracts[v.CompanyName] = append(companyContracts[v.CompanyName], v) } // 类型为合约加总才往下合并 if contractType != tradeAnalysisModel.ContractQueryTypeTotal { return } // 以[公司]为组, 计算合约加总 for k, v := range companyContracts { companyData := new(tradeAnalysisModel.ContractCompanyTradeData) companyData.CompanyName = k companyData.DataList = make([]*tradeAnalysisModel.ContractCompanyTradeDataList, 0) contractArr := make([]string, 0) // 合约加总 sumDateData := make(map[time.Time]*tradeAnalysisModel.ContractCompanyTradeDataList) for _, vv := range v { contractArr = append(contractArr, vv.ClassifyType) for _, dv := range vv.DataList { if sumDateData[dv.Date] == nil { sumDateData[dv.Date] = new(tradeAnalysisModel.ContractCompanyTradeDataList) sumDateData[dv.Date].Date = dv.Date } // 数据类型以第一个非零值为准, 只处理多空和净多, 变化就不管了 if sumDateData[dv.Date].BuyValType == tradeAnalysisModel.TradeDataTypeNull && dv.BuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].BuyValType = dv.BuyValType } if sumDateData[dv.Date].BuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.BuyValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].BuyValType = dv.BuyValType } if dv.BuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].BuyVal += dv.BuyVal } // 空单 if sumDateData[dv.Date].SoldValType == tradeAnalysisModel.TradeDataTypeNull && dv.SoldValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].SoldValType = dv.SoldValType } if sumDateData[dv.Date].SoldValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.SoldValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].SoldValType = dv.SoldValType } if dv.SoldValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].SoldVal += dv.SoldVal } // 净多单 if sumDateData[dv.Date].PureBuyValType == tradeAnalysisModel.TradeDataTypeNull && dv.PureBuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].PureBuyValType = dv.PureBuyValType } if sumDateData[dv.Date].PureBuyValType == tradeAnalysisModel.TradeDataTypeOrigin && dv.PureBuyValType == tradeAnalysisModel.TradeDataTypeCalculate { sumDateData[dv.Date].PureBuyValType = dv.PureBuyValType } if dv.PureBuyValType > tradeAnalysisModel.TradeDataTypeNull { sumDateData[dv.Date].PureBuyVal += dv.PureBuyVal } } // 多个合约比对开始结束时间 if companyData.StartDate.IsZero() { companyData.StartDate = vv.StartDate } if vv.StartDate.Before(companyData.StartDate) { companyData.StartDate = vv.StartDate } if companyData.EndDate.IsZero() { companyData.EndDate = vv.EndDate } if vv.EndDate.Before(companyData.EndDate) { companyData.EndDate = vv.EndDate } } for _, sv := range sumDateData { companyData.DataList = append(companyData.DataList, sv) } sort.Slice(companyData.DataList, func(i, j int) bool { return companyData.DataList[i].Date.Before(companyData.DataList[j].Date) }) //companyData.ClassifyType = strings.Join(contractArr, ",") companyData.IsTotal = true companyData.Exchange = exchange companyData.CompanyName = k companyData.ClassifyName = classifyName companyData.ClassifyType = classifyName companyTradeData = append(companyTradeData, companyData) } return } // TransTradeData2EdbData 持仓数据转为指标数据 func TransTradeData2EdbData(tradeData []*tradeAnalysisModel.ContractCompanyTradeData, contractPosition int) (edbData []*tradeAnalysisModel.ContractCompanyTradeEdb, edbDataMap []map[time.Time]int, err error) { if len(tradeData) == 0 { return } edbData = make([]*tradeAnalysisModel.ContractCompanyTradeEdb, 0) edbDataMap = make([]map[time.Time]int, 0) for _, v := range tradeData { newEdb := new(tradeAnalysisModel.ContractCompanyTradeEdb) newEdb.Exchange = v.Exchange newEdb.ClassifyName = v.ClassifyName newEdb.ClassifyType = v.ClassifyType newEdb.CompanyName = v.CompanyName newEdb.IsTotal = v.IsTotal newEdb.ContractPosition = contractPosition newEdb.StartDate = v.StartDate newEdb.EndDate = v.EndDate newEdb.DataList = make([]*tradeAnalysisModel.ContractCompanyTradeEdbData, 0) dataMap := make(map[time.Time]int) for _, d := range v.DataList { var vd int switch contractPosition { case tradeAnalysisModel.ContractPositionBuy: if d.BuyValType == tradeAnalysisModel.TradeDataTypeNull { continue } vd = d.BuyVal case tradeAnalysisModel.ContractPositionSold: if d.SoldValType == tradeAnalysisModel.TradeDataTypeNull { continue } vd = d.SoldVal case tradeAnalysisModel.ContractPositionPureBuy: if d.PureBuyValType == tradeAnalysisModel.TradeDataTypeNull { continue } vd = d.PureBuyVal default: continue } newEdb.DataList = append(newEdb.DataList, &tradeAnalysisModel.ContractCompanyTradeEdbData{ DataTime: d.Date, Val: vd, }) dataMap[d.Date] = vd } edbData = append(edbData, newEdb) edbDataMap = append(edbDataMap, dataMap) } return } // GetContractCompanyTradeData 获取合约持仓数据 func GetContractCompanyTradeData(exchange string, classifyNames, contracts, companies []string, startDate, endDate time.Time) (contractTradeData map[string]*tradeAnalysisModel.ContractCompanyTradeData, lastBuyVal, lastSoldVal map[string]map[time.Time]int, err error) { // 各原始数据表期货公司名称不一致 companyMap := make(map[string]string) { ob := new(tradeAnalysisModel.TradeFuturesCompany) list, e := ob.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "") if e != nil { err = fmt.Errorf("获取期货公司名称失败: %v", e) return } switch exchange { case "zhengzhou": for _, v := range list { companyMap[v.CompanyName] = v.ZhengzhouName } case "dalian": for _, v := range list { companyMap[v.CompanyName] = v.DalianName } case "shanghai": for _, v := range list { companyMap[v.CompanyName] = v.ShanghaiName } case "cffex": for _, v := range list { companyMap[v.CompanyName] = v.CffexName } case "ine": for _, v := range list { companyMap[v.CompanyName] = v.IneName } case "guangzhou": for _, v := range list { companyMap[v.CompanyName] = v.GuangzhouName } } } var queryCompanies []string for _, v := range companies { if v == tradeAnalysisModel.TradeFuturesCompanyTop20 { queryCompanies = append(queryCompanies, tradeAnalysisModel.TradeFuturesCompanyTop20) continue } companyName, ok := companyMap[v] if !ok { utils.FileLog.Info(fmt.Sprintf("交易所%s公司名称映射不存在: %s", exchange, v)) continue } queryCompanies = append(queryCompanies, companyName) } // 郑商所/广期所查询方式不一样 var tradeAnalysis TradeAnalysisInterface switch exchange { case tradeAnalysisModel.TradeExchangeZhengzhou: tradeAnalysis = &ZhengzhouTradeAnalysis{} case tradeAnalysisModel.TradeExchangeGuangzhou: tradeAnalysis = &GuangzhouTradeAnalysis{} default: tradeAnalysis = &BaseTradeAnalysis{} } // 获取多单/空单原始数据 originList, _, lastOriginList, e := tradeAnalysis.GetTradeDataByContracts(exchange, classifyNames, contracts, queryCompanies, startDate, endDate) if e != nil { err = fmt.Errorf("获取多空单原始数据失败, %v", e) return } // [合约-期货公司]数据分组 contractTradeData = make(map[string]*tradeAnalysisModel.ContractCompanyTradeData) { keyDateData := make(map[string]*tradeAnalysisModel.ContractCompanyTradeDataList) keyDateDataExist := make(map[string]bool) for _, v := range originList { companyName := v.CompanyName k := fmt.Sprintf("%s-%s", v.ClassifyType, companyName) if contractTradeData[k] == nil { contractTradeData[k] = new(tradeAnalysisModel.ContractCompanyTradeData) contractTradeData[k].Exchange = exchange contractTradeData[k].CompanyName = companyName contractTradeData[k].ClassifyName = v.ClassifyName contractTradeData[k].ClassifyType = v.ClassifyType contractTradeData[k].DataList = make([]*tradeAnalysisModel.ContractCompanyTradeDataList, 0) } kd := fmt.Sprintf("%s-%s", k, v.DataTime.Format(utils.FormatDate)) if keyDateData[kd] == nil { keyDateData[kd] = new(tradeAnalysisModel.ContractCompanyTradeDataList) keyDateData[kd].Date = v.DataTime } if v.ValType == 1 { keyDateData[kd].BuyVal = v.Val keyDateData[kd].BuyValType = tradeAnalysisModel.TradeDataTypeOrigin keyDateData[kd].BuyChange = v.ValChange keyDateData[kd].BuyChangeType = tradeAnalysisModel.TradeDataTypeOrigin } if v.ValType == 2 { keyDateData[kd].SoldVal = v.Val keyDateData[kd].SoldValType = tradeAnalysisModel.TradeDataTypeOrigin keyDateData[kd].SoldChange = v.ValChange keyDateData[kd].SoldChangeType = tradeAnalysisModel.TradeDataTypeOrigin } if !keyDateDataExist[kd] { contractTradeData[k].DataList = append(contractTradeData[k].DataList, keyDateData[kd]) keyDateDataExist[kd] = true } } } // 合约的[日期-末位值] lastBuyVal = make(map[string]map[time.Time]int) lastSoldVal = make(map[string]map[time.Time]int) { for _, v := range lastOriginList { if v.ValType == 1 { if lastBuyVal[v.ClassifyType] == nil { lastBuyVal[v.ClassifyType] = make(map[time.Time]int) } lastBuyVal[v.ClassifyType][v.DataTime] = v.Val continue } if lastSoldVal[v.ClassifyType] == nil { lastSoldVal[v.ClassifyType] = make(map[time.Time]int) } lastSoldVal[v.ClassifyType][v.DataTime] = v.Val } } return } // GetTradeClassifyNewestDataTime 获取数据最新日期 func GetTradeClassifyNewestDataTime(exchange string, classifyNames []string) (dataTime time.Time, err error) { var tradeAnalysis TradeAnalysisInterface switch exchange { case tradeAnalysisModel.TradeExchangeZhengzhou: tradeAnalysis = &ZhengzhouTradeAnalysis{} case tradeAnalysisModel.TradeExchangeGuangzhou: tradeAnalysis = &GuangzhouTradeAnalysis{} default: tradeAnalysis = &BaseTradeAnalysis{} } if exchange == tradeAnalysisModel.TradeExchangeZhengzhou { classifies, e := GetZhengzhouContractsByClassifyNames(classifyNames) if e != nil { err = fmt.Errorf("获取郑商所实际合约失败, %v", e) return } classifyNames = classifies } d, e := tradeAnalysis.GetClassifyNewestDataTime(exchange, classifyNames) if e != nil && e.Error() != utils.ErrNoRow() { err = fmt.Errorf("获取品种最新数据日期失败, %v", e) return } if !d.IsZero() { dataTime = d } else { dataTime = time.Now().Local() } return }