|
@@ -0,0 +1,1019 @@
|
|
|
|
+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, time.Time{})
|
|
|
|
+ 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 = time.Now()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 指标数据和最值
|
|
|
|
+ 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 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
|
|
|
|
+}
|