package trade_analysis

import (
	"eta/eta_api/models/data_manage"
	tradeAnalysisModel "eta/eta_api/models/data_manage/trade_analysis"
	"eta/eta_api/services/data"
	"eta/eta_api/utils"
	"fmt"
	"sort"
	"strings"
	"time"
)

// FormatCompanyTradeData2EdbMappings [公司-合约加总]转为指标数据
func FormatCompanyTradeData2EdbMappings(companyTradeData []*tradeAnalysisModel.ContractCompanyTradeData, tradeType, dateType, dateTypeNum int, startDate, endDate string, chartEdbList []*data_manage.ChartSaveItem) (edbMappings []*data_manage.ChartEdbInfoMapping, chartName string, err error) {
	edbMappings = make([]*data_manage.ChartEdbInfoMapping, 0)
	if dateType <= 0 {
		dateType = utils.DateTypeOneMonth
	}

	// 期货公司名称作为标识进行匹配
	edbMap := make(map[string]*data_manage.ChartSaveItem)
	if len(chartEdbList) > 0 {
		for _, v := range chartEdbList {
			edbMap[v.UniqueFlag] = v
		}
	}

	for k, v := range companyTradeData {
		mapping := new(data_manage.ChartEdbInfoMapping)
		mapping.EdbName = v.CompanyName
		mapping.EdbNameEn = v.CompanyName
		mapping.EdbAliasName = v.CompanyName
		mapping.EdbAliasNameEn = v.CompanyName
		mapping.Frequency = "日度"
		mapping.FrequencyEn = data.GetFrequencyEn(mapping.Frequency)
		mapping.SourceName = utils.SourceNameTradeAnalysis
		mapping.Source = utils.CHART_SOURCE_TRADE_ANALYSIS_PROCESS
		mapping.IsAxis = 1
		mapping.EdbInfoType = 1
		mapping.StartDate = v.StartDate.Format(utils.FormatDate)
		mapping.EndDate = v.EndDate.Format(utils.FormatDate)
		mapping.ConvertUnit = tradeAnalysisModel.WarehouseDefaultUnit // 固定单位
		mapping.UniqueFlag = v.CompanyName                            // 期货公司名称作为每条曲线的唯一标识

		// 有配置那么取配置中的图例名称和左右轴
		edbConf := edbMap[mapping.UniqueFlag]
		if edbConf != nil {
			mapping.EdbName = edbConf.EdbAliasName
			mapping.EdbNameEn = edbConf.EdbAliasName
			mapping.EdbAliasName = edbConf.EdbAliasName
			mapping.EdbAliasNameEn = edbConf.EdbAliasName
			mapping.IsAxis = edbConf.IsAxis
		}

		// 根据参数取日期范围
		var startTime, endTime time.Time
		if dateType > 0 {
			st, ed := utils.GetDateByDateTypeV2(dateType, startDate, endDate, dateTypeNum, 0)
			if st != "" {
				startTime, _ = time.ParseInLocation(utils.FormatDate, st, time.Local)
			}
			if startTime.IsZero() {
				startTime = v.StartDate
			}
			if ed != "" {
				endTime, _ = time.ParseInLocation(utils.FormatDate, ed, time.Local)
			}
			if endTime.IsZero() {
				endTime = v.EndDate
			}
		}

		// 指标数据和最值
		edbData := make([]*data_manage.EdbDataList, 0)
		var minData, maxData float64
		var setMinMax bool
		for _, dv := range v.DataList {
			if dv.Date.Before(startTime) || dv.Date.After(endTime) {
				continue
			}

			// 交易方向
			var (
				val    float64
				hasVal bool
			)
			if tradeType == tradeAnalysisModel.WarehouseBuyChartType {
				if dv.BuyValType == tradeAnalysisModel.TradeDataTypeNull {
					continue
				}
				hasVal = true
				val = float64(dv.BuyVal)
			}
			if tradeType == tradeAnalysisModel.WarehouseSoldChartType {
				if dv.SoldValType == tradeAnalysisModel.TradeDataTypeNull {
					continue
				}
				hasVal = true
				val = float64(dv.SoldVal)
			}
			if tradeType == tradeAnalysisModel.WarehousePureBuyChartType {
				if dv.PureBuyValType == tradeAnalysisModel.TradeDataTypeNull {
					continue
				}
				hasVal = true
				val = float64(dv.PureBuyVal)
			}
			if !hasVal {
				continue
			}

			if !setMinMax {
				minData = val
				maxData = val
				setMinMax = true
			}
			if val < minData {
				minData = val
			}
			if val > maxData {
				maxData = val
			}
			edbData = append(edbData, &data_manage.EdbDataList{
				DataTime:      dv.Date.Format(utils.FormatDate),
				DataTimestamp: dv.Date.UnixNano() / 1e6,
				Value:         val,
			})
		}
		mapping.MinData = minData
		mapping.MaxData = maxData
		mapping.DataList = edbData
		edbMappings = append(edbMappings, mapping)

		// 图表默认名称
		if k == 0 {
			chartName += strings.ReplaceAll(v.ClassifyType, ",", "")
		}
		chartName += v.CompanyName
	}

	// 图表名称后缀
	chartName += tradeAnalysisModel.WarehouseTypeSuffixNames[tradeType]
	return
}

func GetOriginTradeData(exchange, classifyName string, contracts, companies []string, predictRatio float64) (companyTradeData []*tradeAnalysisModel.ContractCompanyTradeData, 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 {
		// TOP20用空名称去查询
		if v == tradeAnalysisModel.TradeFuturesCompanyTop20 {
			queryCompanies = append(queryCompanies, "")
			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, e := tradeAnalysis.GetTradeDataByClassifyAndCompany(exchange, classifyName, contracts, queryCompanies)
	if e != nil {
		err = fmt.Errorf("获取多空单原始数据失败, %v", e)
		return
	}

	keyItems := make(map[string]*tradeAnalysisModel.ContractCompanyTradeData)
	keyDateData := make(map[string]*tradeAnalysisModel.ContractCompanyTradeDataList)
	keyDateDataExist := make(map[string]bool)
	for _, v := range originList {
		// TOP20对应数据库中的空名称
		companyName := v.CompanyName
		if companyName == "" {
			companyName = tradeAnalysisModel.TradeFuturesCompanyTop20
		}

		k := fmt.Sprintf("%s-%s", v.ClassifyType, companyName)
		if keyItems[k] == nil {
			keyItems[k] = new(tradeAnalysisModel.ContractCompanyTradeData)
			keyItems[k].CompanyName = companyName
			keyItems[k].ClassifyType = v.ClassifyType
			keyItems[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] {
			keyItems[k].DataList = append(keyItems[k].DataList, keyDateData[kd])
			keyDateDataExist[kd] = true
		}
	}

	// 获取[合约]每日的末位多空单
	contractLastBuyDateVal := make(map[string]map[time.Time]int)
	contractLastSoldDateVal := make(map[string]map[time.Time]int)
	{
		lastOriginList, e := tradeAnalysis.GetLastTradeDataByClassify(exchange, classifyName, contracts)
		if e != nil {
			err = fmt.Errorf("获取末位多空单原始数据失败, %v", e)
			return
		}
		for _, v := range lastOriginList {
			if v.ValType == 1 {
				if contractLastBuyDateVal[v.ClassifyType] == nil {
					contractLastBuyDateVal[v.ClassifyType] = make(map[time.Time]int)
				}
				contractLastBuyDateVal[v.ClassifyType][v.DataTime] = v.Val
				continue
			}
			if contractLastSoldDateVal[v.ClassifyType] == nil {
				contractLastSoldDateVal[v.ClassifyType] = make(map[time.Time]int)
			}
			contractLastSoldDateVal[v.ClassifyType][v.DataTime] = v.Val
		}
	}

	// 填充[合约-公司]预估数据, 并根据[公司-多合约]分组, [公司]算作一个指标, 指标值为[多个合约]的计算加总
	companyContracts := make(map[string][]*tradeAnalysisModel.ContractCompanyTradeData)
	for _, v := range keyItems {
		td, fd, ed, e := PredictingTradeData(v.DataList, contractLastBuyDateVal[v.ClassifyType], contractLastSoldDateVal[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
}