2 次代碼提交 3d3cb4b34a ... 7e89f145d8

作者 SHA1 備註 提交日期
  hsun 7e89f145d8 Merge branch 'feature/eta_2.1.4' into debug 1 周之前
  hsun b602ffba1a fix: 持仓-相关性值 1 周之前
共有 2 個文件被更改,包括 167 次插入145 次删除
  1. 65 138
      services/data/trade_analysis/trade_analysis_correlation.go
  2. 102 7
      services/data/trade_analysis/trade_analysis_data.go

+ 65 - 138
services/data/trade_analysis/trade_analysis_correlation.go

@@ -65,6 +65,8 @@ func CheckAnalysisCorrelationExtraConfig(extraConfig tradeAnalysisModel.Correlat
 
 // GetCorrelationTableRowsDataByConfig 根据配置获取相关性表格数据
 func GetCorrelationTableRowsDataByConfig(tableConfig tradeAnalysisModel.CorrelationTableExtraConfig) (tables []*tradeAnalysisModel.CorrelationTableData, err error) {
+	tables = make([]*tradeAnalysisModel.CorrelationTableData, 0)
+
 	// 获取标的指标数据
 	baseDateData := make(map[time.Time]float64)
 	{
@@ -103,7 +105,7 @@ func GetCorrelationTableRowsDataByConfig(tableConfig tradeAnalysisModel.Correlat
 	}
 
 	// [合约+期货公司]持仓数据
-	tradeData, e := GetCorrelationTableTradeData(tableConfig.Exchange, []string{tableConfig.ClassifyName}, contracts, tableConfig.CompanyNames, tableConfig.PredictRatio)
+	tradeData, e := GetCorrelationTableTradeData(tableConfig.Exchange, tableConfig.ClassifyName, contracts, tableConfig.CompanyNames, tableConfig.PredictRatio, tableConfig.ContractType)
 	if e != nil {
 		err = fmt.Errorf("获取[合约+期货公司]持仓数据失败, %v", e)
 		return
@@ -118,34 +120,37 @@ func GetCorrelationTableRowsDataByConfig(tableConfig tradeAnalysisModel.Correlat
 
 	// 遍历相关性配置(目前最多有两个滚动相关性), 遍历指标, 分别计算滚动相关性
 	maxPre := 10 // 需要展示的以标的指标日期为准往前推N个交易日的滚动相关性
-	startDate := baseDate.AddDate(0, 0, -maxPre)
-	endDate := baseDate
-	rowDays := utils.GetTradingDays(baseDate.AddDate(0, 0, -20), baseDate) // 从20个自然日里截取11个数据对应的交易日,且当日排最前,后面依次为0、-1到-10
+	startBase := baseDate.AddDate(0, 0, -maxPre)
+
+	// 从20个自然日里截取11个数据对应的交易日,且当日排最前,后面依次为0、-1到-10
+	rowDays := utils.GetTradingDays(baseDate.AddDate(0, 0, -20), baseDate)
 	rowDays = utils.ReverseTimeSlice(rowDays)
 	rowDays = rowDays[:11]
-	tables = make([]*tradeAnalysisModel.CorrelationTableData, 0)
 	for _, rc := range tableConfig.RollConfig {
 		tableData := new(tradeAnalysisModel.CorrelationTableData)
 		tableData.CalculateValue = rc.CalculateValue
 		tableData.LeadValue = rc.LeadValue
 		tableData.RowsData = make([]*tradeAnalysisModel.CorrelationTableRowData, 0)
 
+		// 计算滚动相关性的开始日期, 用计算窗口往前推(可以往前多推俩月否则可能取不到)
+		startDate := startBase.AddDate(0, 0, -(rc.CalculateValue + rc.LeadValue + 60))
+
 		for kd, kv := range tradeEdbList {
 			row := new(tradeAnalysisModel.CorrelationTableRowData)
 			row.Exchange = kv.Exchange
 			row.CompanyName = kv.CompanyName
 			row.ClassifyName = kv.ClassifyName
 			row.ClassifyType = kv.ClassifyType
-			// 数据为合约加总时名称为合约名,否则为合约+期货公司+方向
+			// 数据为合约加总时名称为品种名+方向,否则为合约+期货公司+方向
 			if kv.IsTotal {
-				row.RowName = kv.ClassifyType
+				row.RowName = fmt.Sprintf("%s%s%s", kv.ClassifyName, kv.CompanyName, tradeAnalysisModel.WarehouseTypeSuffixNames[kv.ContractPosition])
 			} else {
 				row.RowName = fmt.Sprintf("%s%s%s", kv.ClassifyType, kv.CompanyName, tradeAnalysisModel.WarehouseTypeSuffixNames[kv.ContractPosition])
 			}
 			row.DayData = make([]*tradeAnalysisModel.CorrelationTableRowDayData, 0)
 
 			// 这里加行数据
-			rd, e := CalculateRollCorrelationData(rc.CalculateValue, rc.LeadValue, baseDateData, tradeEdbDataMap[kd], startDate, endDate)
+			rd, e := CalculateRollCorrelationData(rc.CalculateValue, rc.LeadValue, baseDateData, tradeEdbDataMap[kd], startDate, baseDate)
 			if e != nil {
 				err = fmt.Errorf("计算行数据-滚动相关性失败, %v", e)
 				return
@@ -211,154 +216,76 @@ func GetTopContractsByType(contractType int, exchange, classifyName string, base
 
 // CalculateRollCorrelationData 计算滚动相关性
 func CalculateRollCorrelationData(calculateValue, leadValue int, baseEdbData map[time.Time]float64, changeEdbData map[time.Time]int, startDate, endDate time.Time) (dateRatio map[time.Time]float64, err error) {
-	//dataList = make([]*data_manage.EdbDataList, 0)
+	dateRatio = make(map[time.Time]float64)
 
 	// 计算窗口,不包含第一天
-	//startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
-	//startDate = startDateTime.AddDate(0, 0, 1).Format(utils.FormatDate)
 	startDate = startDate.AddDate(0, 0, 1)
 
-	//baseEdbInfo := edbInfoMappingA
-	//changeEdbInfo := edbInfoMappingB
-
-	// 获取时间基准指标在时间区间内的值
-	//aDataList := make([]*data_manage.EdbDataList, 0)
-	//switch baseEdbInfo.EdbInfoCategoryType {
-	//case 0:
-	//	aDataList, err = data_manage.GetEdbDataList(baseEdbInfo.Source, baseEdbInfo.SubSource, baseEdbInfo.EdbInfoId, startDate, endDate)
-	//case 1:
-	//	_, aDataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdbInfo.EdbInfoId, startDate, endDate, true)
-	//default:
-	//	err = errors.New("指标base类型异常")
-	//	return
-	//}
-
-	// 获取变频指标所有日期的值, 插值法完善数据
-	//bDataList := make([]*data_manage.EdbDataList, 0)
-	//switch changeEdbInfo.EdbInfoCategoryType {
-	//case 0:
-	//	bDataList, err = data_manage.GetEdbDataList(changeEdbInfo.Source, changeEdbInfo.SubSource, changeEdbInfo.EdbInfoId, "", "")
-	//case 1:
-	//	_, bDataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(changeEdbInfo.EdbInfoId, "", "", false)
-	//default:
-	//	err = errors.New("指标change类型异常")
-	//	return
-	//}
-
-	// 数据平移变频指标领先/滞后的日期(单位天)
-	// 2023-03-17 时间序列始终以指标A为基准, 始终是B进行平移
-	//baseDataList := make([]*data_manage.EdbDataList, 0)
-	//baseDataMap := make(map[string]float64)
-	//changeDataList := make([]*data_manage.EdbDataList, 0)
-	changeDataMap := make(map[time.Time]float64)
-
-	// A指标不管三七二十一,先变个频再说
-	//{
-	//	_, e := HandleDataByLinearRegression(aDataList, baseDataMap)
-	//	if e != nil {
-	//		err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
-	//		return
-	//	}
-	//	//baseDataList = tmpNewChangeDataList
-	//}
-	// B指标不管三七二十一,先变个频再说
-	//{
-	//	tmpNewChangeDataList, e := HandleDataByLinearRegression(bDataList, changeDataMap)
-	//	if e != nil {
-	//		err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
-	//		return
-	//	}
-	//	changeDataList = tmpNewChangeDataList
-	//
-	//	// 平移下日期
-	//	moveUnitDays := utils.FrequencyDaysMap[leadUnit]
-	//	_, changeDataMap = MoveDataDaysToNewDataList(changeDataList, leadValue*moveUnitDays)
-	//}
-
-	// TODO:平移下日期
-	//moveUnitDays := utils.FrequencyDaysMap[leadUnit]
-	//_, changeDataMap = MoveDataDaysToNewDataList(changeDataList, leadValue)
-	changeDataMap = MoveDataDaysToNewDataList(changeEdbData, leadValue)
+	// 平移变频指标
+	changeDataMap := MoveDataDaysToNewDataList(changeEdbData, leadValue)
 
 	// 计算计算时,需要多少个日期内数据
-	//calculateDay := utils.FrequencyDaysMap[calculateUnit] * calculateValue
 	calculateDay := calculateValue
 
 	var minRatio, maxRatio float64
-	dateRatio = make(map[time.Time]float64)
 	// 计算 每个日期的相关性值
-	{
-		startDateTime := startDate
-		//startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
-		//if endDate == `` {
-		//	endDate = baseEdbInfo.EndDate
-		//}
-		//endDateTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
-		endDateTime := endDate.AddDate(0, 0, -(calculateDay - 1))
-
-		// 是否开始第一条数据
-		var isStart, isNotFirst bool
-		for currDay := startDateTime; !currDay.After(endDateTime); currDay = currDay.AddDate(0, 0, 1) {
-			yCalculateData := make([]float64, 0)
-			baseCalculateData := make([]float64, 0)
-
-			// 取出对应的基准日期的值
-			for i := 0; i < calculateDay; i++ {
-				//iDay := currDay.AddDate(0, 0, i).Format(utils.FormatDate)
-				iDay := currDay.AddDate(0, 0, i)
-
-				tmpBaseValue, ok1 := baseEdbData[iDay]
-				tmpChangeValue, ok2 := changeDataMap[iDay]
-				if !ok1 || !ok2 {
-					continue
-				}
-				baseCalculateData = append(baseCalculateData, tmpBaseValue)
-				yCalculateData = append(yCalculateData, tmpChangeValue)
-			}
-
-			// 没有数据的话,那就不返回
-			if len(baseCalculateData) == 0 {
+	startDateTime := startDate
+	endDateTime := endDate.AddDate(0, 0, -(calculateDay - 1))
+
+	// 是否开始第一条数据
+	var isStart, isNotFirst bool
+	for currDay := startDateTime; !currDay.After(endDateTime); currDay = currDay.AddDate(0, 0, 1) {
+		yCalculateData := make([]float64, 0)
+		baseCalculateData := make([]float64, 0)
+
+		// 取出对应的基准日期的值
+		for i := 0; i < calculateDay; i++ {
+			iDay := currDay.AddDate(0, 0, i)
+
+			tmpBaseValue, ok1 := baseEdbData[iDay]
+			tmpChangeValue, ok2 := changeDataMap[iDay]
+			if !ok1 || !ok2 {
 				continue
 			}
-			// 公式计算出领先/滞后频度对应点的相关性系数
-			ratio := utils.CalculateCorrelationByIntArr(baseCalculateData, yCalculateData)
+			baseCalculateData = append(baseCalculateData, tmpBaseValue)
+			yCalculateData = append(yCalculateData, tmpChangeValue)
+		}
 
-			// 过滤前面都是0的数据
-			{
-				if ratio != 0 {
-					isStart = true
-				}
+		// 没有数据的话,那就不返回
+		if len(baseCalculateData) == 0 {
+			continue
+		}
+		// 公式计算出领先/滞后频度对应点的相关性系数
+		ratio := utils.CalculateCorrelationByIntArr(baseCalculateData, yCalculateData)
 
-				if !isStart {
-					continue
-				}
+		// 过滤前面都是0的数据
+		{
+			if ratio != 0 {
+				isStart = true
 			}
 
-			dataTime := currDay.AddDate(0, 0, calculateDay-1)
-			//dataList = append(dataList, data_manage.EdbDataList{
-			//	//EdbDataId:     0,
-			//	EdbInfoId:     0,
-			//	DataTime:      dataTime.Format(utils.FormatDate),
-			//	DataTimestamp: dataTime.UnixNano() / 1e6,
-			//	Value:         ratio,
-			//})
-			// 保留4位小数
-			ratio = math.Round(ratio*10000) / 10000
-			dateRatio[dataTime] = ratio
-
-			if !isNotFirst {
-				minRatio = ratio
-				maxRatio = ratio
-				isNotFirst = true
-			}
-			if minRatio > ratio {
-				minRatio = ratio
-			}
-			if maxRatio < ratio {
-				maxRatio = ratio
+			if !isStart {
+				continue
 			}
 		}
-		//dataResp.DataList = dataList
+
+		dataTime := currDay.AddDate(0, 0, calculateDay-1)
+
+		// 保留4位小数
+		ratio = math.Round(ratio*10000) / 10000
+		dateRatio[dataTime] = ratio
+
+		if !isNotFirst {
+			minRatio = ratio
+			maxRatio = ratio
+			isNotFirst = true
+		}
+		if minRatio > ratio {
+			minRatio = ratio
+		}
+		if maxRatio < ratio {
+			maxRatio = ratio
+		}
 	}
 	return
 }

+ 102 - 7
services/data/trade_analysis/trade_analysis_data.go

@@ -67,7 +67,7 @@ func FormatCompanyTradeData2EdbMappings(companyTradeData []*tradeAnalysisModel.C
 				endTime, _ = time.ParseInLocation(utils.FormatDate, ed, time.Local)
 			}
 			if endTime.IsZero() {
-				endTime = v.EndDate
+				endTime = time.Now()
 			}
 		}
 
@@ -672,7 +672,7 @@ func GetTableTradeData(exchange string, classifyName string, contracts []string,
 		})
 		//companyData.ClassifyType = strings.Join(contractArr, ",")
 		companyData.Exchange = exchange
-		companyData.CompanyName = classifyName
+		companyData.CompanyName = k
 		companyData.ClassifyType = classifyName
 		companyTradeData = append(companyTradeData, companyData)
 	}
@@ -680,16 +680,18 @@ func GetTableTradeData(exchange string, classifyName string, contracts []string,
 }
 
 // GetCorrelationTableTradeData 获取相关性表格持仓数据
-func GetCorrelationTableTradeData(exchange string, classifyNames, contracts, companies []string, predictRatio float64) (tradeData []*tradeAnalysisModel.ContractCompanyTradeData, err error) {
+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, classifyNames, contracts, companies, time.Time{}, time.Time{})
+	contractTradeData, lastBuyVal, lastSoldVal, e := GetContractCompanyTradeData(exchange, []string{classifyName}, contracts, companies, time.Time{}, time.Time{})
 	if e != nil {
 		err = fmt.Errorf("获取合约-持仓数据失败, %v", e)
 		return
 	}
 
-	// 填充预估数据
-	tradeData = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0)
+	// 填充[合约-公司]预估数据, 并根据[公司-多合约]分组, [公司]算作一个指标, 指标值为[多个合约]的计算加总
+	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 {
@@ -699,7 +701,100 @@ func GetCorrelationTableTradeData(exchange string, classifyNames, contracts, com
 		v.DataList = td
 		v.StartDate = fd
 		v.EndDate = ed
-		tradeData = append(tradeData, v)
+
+		// 合约类型参数不为合约加总时, 每个合约算一行数据
+		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
 }