Explorar o código

fix: 优化持仓分析二期SQL

hsun hai 3 meses
pai
achega
3781b942aa

+ 2 - 2
controllers/trade_analysis/warehouse.go

@@ -220,7 +220,7 @@ func (this *WarehouseController) Preview() {
 	}
 
 	// 获取指标数据, 该图表未用实际指标, 为了统一数据格式用ChartEdbInfoMapping
-	companyTradeData, e := tradeAnalysisService.GetOriginTradeData(extraConfig.Exchange, extraConfig.ClassifyName, extraConfig.Contracts, extraConfig.Companies, extraConfig.PredictRatio)
+	companyTradeData, e := tradeAnalysisService.GetWarehouseTradeData(extraConfig.Exchange, extraConfig.ClassifyName, extraConfig.Contracts, extraConfig.Companies, extraConfig.PredictRatio)
 	if e != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = fmt.Sprintf("获取期货公司持仓加总数据失败, %v", e)
@@ -687,7 +687,7 @@ func (this *WarehouseController) Detail() {
 	}
 
 	// 获取图表数据
-	companyTradeData, e := tradeAnalysisService.GetOriginTradeData(extraConfig.Exchange, extraConfig.ClassifyName, extraConfig.Contracts, extraConfig.Companies, extraConfig.PredictRatio)
+	companyTradeData, e := tradeAnalysisService.GetWarehouseTradeData(extraConfig.Exchange, extraConfig.ClassifyName, extraConfig.Contracts, extraConfig.Companies, extraConfig.PredictRatio)
 	if e != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = fmt.Sprintf("获取期货公司持仓加总数据失败, %v", e)

+ 465 - 331
models/data_manage/trade_analysis/trade_analysis.go

@@ -4,6 +4,7 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"strings"
 	"time"
 )
 
@@ -24,9 +25,11 @@ const (
 	GuangZhouSeatNameSold        = "持卖单量"    // 广期所指标名称中的空单名称
 	GuangZhouTopSeatNameBuy      = "持买单量总计"  // 广期所指标名称中的TOP20多单名称
 	GuangZhouTopSeatNameSold     = "持卖单量总计"  // 广期所指标名称中的TOP20空单名称
+	GuangZhouTopSeatNameDeal     = "成交量总计"   // 广期所指标名称中的TOP20成交量名称
 )
 
 const (
+	TradeExchangeDalian    = "dalian"
 	TradeExchangeZhengzhou = "zhengzhou"
 	TradeExchangeGuangzhou = "guangzhou"
 )
@@ -43,6 +46,7 @@ var GuangzhouSeatNameValType = map[string]int{
 	GuangZhouSeatNameSold:    2,
 	GuangZhouTopSeatNameBuy:  1,
 	GuangZhouTopSeatNameSold: 2,
+	GuangZhouTopSeatNameDeal: 3,
 }
 
 // 合约查询方式
@@ -228,180 +232,252 @@ type OriginTradeData struct {
 }
 
 // GetTradeDataByClassifyAndCompany 根据品种和公司名称获取持仓数据
-func GetTradeDataByClassifyAndCompany(exchange string, classifyNames, contracts, companies []string, startDate, endDate time.Time) (items []*OriginTradeData, err error) {
+//func GetTradeDataByClassifyAndCompany(exchange string, classifyNames, contracts, companies []string, startDate, endDate time.Time) (items []*OriginTradeData, err error) {
+//	if exchange == "" {
+//		err = fmt.Errorf("数据表名称有误")
+//		return
+//	}
+//	if len(contracts) == 0 || len(classifyNames) == 0 || len(companies) == 0 {
+//		return
+//	}
+//	condBuy := fmt.Sprintf(`classify_name IN (%s) AND classify_type IN (%s)`, utils.GetOrmInReplace(len(classifyNames)), utils.GetOrmInReplace(len(contracts)))
+//	parsBuy := make([]interface{}, 0)
+//	parsBuy = append(parsBuy, classifyNames, contracts)
+//
+//	condSold := fmt.Sprintf(`classify_name IN (%s) AND classify_type IN (%s)`, utils.GetOrmInReplace(len(classifyNames)), utils.GetOrmInReplace(len(contracts)))
+//	parsSold := make([]interface{}, 0)
+//	parsSold = append(parsSold, classifyNames, contracts)
+//
+//	if !startDate.IsZero() && !endDate.IsZero() {
+//		st := startDate.Format(utils.FormatDate)
+//		ed := endDate.Format(utils.FormatDate)
+//		condBuy += fmt.Sprintf(` AND (data_time BETWEEN ? AND ?)`)
+//		parsBuy = append(parsBuy, st, ed)
+//		condSold += fmt.Sprintf(` AND (data_time BETWEEN ? AND ?)`)
+//		parsSold = append(parsSold, st, ed)
+//	}
+//
+//	// 是否含有TOP20
+//	var hasTop bool
+//	var condCompanies []string
+//	for _, v := range companies {
+//		if v == TradeFuturesCompanyTop20 {
+//			hasTop = true
+//			continue
+//		}
+//		condCompanies = append(condCompanies, v)
+//	}
+//	if !hasTop {
+//		if len(condCompanies) == 0 {
+//			err = fmt.Errorf("查询条件-期货公司异常")
+//			return
+//		}
+//		condBuy += fmt.Sprintf(` AND buy_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
+//		parsBuy = append(parsBuy, condCompanies)
+//		condSold += fmt.Sprintf(` AND sold_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
+//		parsSold = append(parsSold, condCompanies)
+//	} else {
+//		if len(condCompanies) > 0 {
+//			condBuy += fmt.Sprintf(` AND (rank = 999 OR buy_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
+//			condSold += fmt.Sprintf(` AND (rank = 999 OR sold_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
+//			parsBuy = append(parsBuy, condCompanies)
+//			parsSold = append(parsSold, condCompanies)
+//		} else {
+//			condBuy += ` AND rank = 999`
+//			condSold += ` AND rank = 999`
+//		}
+//	}
+//
+//	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
+//	sql := `SELECT
+//			rank,
+//			buy_short_name AS company_name,
+//			buy_value AS val,
+//			buy_change AS val_change,
+//			classify_name,
+//			classify_type,
+//			data_time,
+//			1 AS val_type
+//		FROM
+//			%s
+//		WHERE
+//			%s
+//		UNION ALL
+//		(
+//		SELECT
+//			rank,
+//			sold_short_name,
+//			sold_value,
+//			sold_change,
+//			classify_name,
+//			classify_type,
+//			data_time,
+//			2 AS val_type
+//		FROM
+//			%s
+//		WHERE
+//			%s
+//		)`
+//	sql = fmt.Sprintf(sql, tableName, condBuy, tableName, condSold)
+//	o := orm.NewOrmUsingDB("data")
+//	_, err = o.Raw(sql, parsBuy, parsSold).QueryRows(&items)
+//	return
+//}
+
+// BaseFromTradeCommonIndex 郑商所/大商所/上期所/上期能源指标表通用字段
+type BaseFromTradeCommonIndex struct {
+	Rank          int       `description:"排名"`
+	DealShortName string    `description:"成交量公司简称"`
+	DealName      string    `description:"成交量指标名称"`
+	DealCode      string    `description:"成交量指标编码"`
+	DealValue     int       `description:"成交量"`
+	DealChange    int       `description:"成交变化量"`
+	BuyShortName  string    `description:"持买单量公司简称"`
+	BuyName       string    `description:"持买单量指标名称"`
+	BuyCode       string    `description:"持买单量指标编码"`
+	BuyValue      int       `description:"持买单量"`
+	BuyChange     int       `description:"持买单量变化量"`
+	SoldShortName string    `description:"持卖单量公司简称"`
+	SoldName      string    `description:"持卖单量指标名称"`
+	SoldCode      string    `description:"持卖单量指标编码"`
+	SoldValue     int       `description:"持卖单量"`
+	SoldChange    int       `description:"持卖单变化量"`
+	Frequency     string    `description:"频度"`
+	ClassifyName  string    `description:"品种"`
+	ClassifyType  string    `description:"合约"`
+	CreateTime    time.Time `description:"创建时间"`
+	ModifyTime    time.Time `description:"更新时间"`
+	DataTime      time.Time `description:"数据日期"`
+}
+
+// GetTradeDataByContracts 根据合约获取持仓数据
+func GetTradeDataByContracts(exchange string, classifyNames, contracts []string, startDate, endDate time.Time) (items []*BaseFromTradeCommonIndex, err error) {
 	if exchange == "" {
 		err = fmt.Errorf("数据表名称有误")
 		return
 	}
-	if len(contracts) == 0 || len(classifyNames) == 0 || len(companies) == 0 {
-		return
+	var cond string
+	var pars []interface{}
+	if len(classifyNames) > 0 {
+		cond += fmt.Sprintf(` AND classify_name IN (%s)`, utils.GetOrmInReplace(len(classifyNames)))
+		pars = append(pars, classifyNames)
 	}
-	condBuy := fmt.Sprintf(`classify_name IN (%s) AND classify_type IN (%s)`, utils.GetOrmInReplace(len(classifyNames)), utils.GetOrmInReplace(len(contracts)))
-	parsBuy := make([]interface{}, 0)
-	parsBuy = append(parsBuy, classifyNames, contracts)
-
-	condSold := fmt.Sprintf(`classify_name IN (%s) AND classify_type IN (%s)`, utils.GetOrmInReplace(len(classifyNames)), utils.GetOrmInReplace(len(contracts)))
-	parsSold := make([]interface{}, 0)
-	parsSold = append(parsSold, classifyNames, contracts)
-
-	if !startDate.IsZero() && !endDate.IsZero() {
-		st := startDate.Format(utils.FormatDate)
-		ed := endDate.Format(utils.FormatDate)
-		condBuy += fmt.Sprintf(` AND (data_time BETWEEN ? AND ?)`)
-		parsBuy = append(parsBuy, st, ed)
-		condSold += fmt.Sprintf(` AND (data_time BETWEEN ? AND ?)`)
-		parsSold = append(parsSold, st, ed)
+	if len(contracts) > 0 {
+		cond += fmt.Sprintf(` AND classify_type IN (%s)`, utils.GetOrmInReplace(len(contracts)))
+		pars = append(pars, contracts)
 	}
-
-	// 是否含有TOP20
-	var hasTop bool
-	var condCompanies []string
-	for _, v := range companies {
-		if v == TradeFuturesCompanyTop20 {
-			hasTop = true
-			continue
-		}
-		condCompanies = append(condCompanies, v)
-	}
-	if !hasTop {
-		if len(condCompanies) == 0 {
-			err = fmt.Errorf("查询条件-期货公司异常")
-			return
-		}
-		condBuy += fmt.Sprintf(` AND buy_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
-		parsBuy = append(parsBuy, condCompanies)
-		condSold += fmt.Sprintf(` AND sold_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
-		parsSold = append(parsSold, condCompanies)
-	} else {
-		if len(condCompanies) > 0 {
-			condBuy += fmt.Sprintf(` AND (rank = 999 OR buy_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
-			condSold += fmt.Sprintf(` AND (rank = 999 OR sold_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
-			parsBuy = append(parsBuy, condCompanies)
-			parsSold = append(parsSold, condCompanies)
-		} else {
-			condBuy += ` AND rank = 999`
-			condSold += ` AND rank = 999`
-		}
+	if !startDate.IsZero() && !endDate.IsZero() {
+		cond += ` AND (data_time BETWEEN ? AND ?)`
+		pars = append(pars, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
 	}
-
+	fields := []string{"rank", "buy_short_name", "buy_value", "buy_change", "sold_short_name", "sold_value", "sold_change", "classify_name", "classify_type", "data_time"}
 	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
-	sql := `SELECT
-			rank,
-			buy_short_name AS company_name,
-			buy_value AS val,
-			buy_change AS val_change,
-			classify_name,
-			classify_type,
-			data_time,
-			1 AS val_type 
-		FROM
-			%s 
-		WHERE
-			%s
-		UNION ALL
-		(
-		SELECT
-			rank,
-			sold_short_name,
-			sold_value,
-			sold_change,
-			classify_name,
-			classify_type,
-			data_time,
-			2 AS val_type 
-		FROM
-			%s 
-		WHERE
-			%s
-		)`
-	sql = fmt.Sprintf(sql, tableName, condBuy, tableName, condSold)
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sql, parsBuy, parsSold).QueryRows(&items)
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s ORDER BY data_time DESC`, strings.Join(fields, ","), tableName, cond)
+	_, err = orm.NewOrmUsingDB("data").Raw(sql, pars).QueryRows(&items)
 	return
 }
 
-// GetTradeZhengzhouDataByClassifyAndCompany 郑商所-根据品种和公司名称获取持仓数据
-func GetTradeZhengzhouDataByClassifyAndCompany(exchange string, contracts, companies []string) (items []*OriginTradeData, err error) {
-	if exchange == "" {
-		err = fmt.Errorf("数据表名称有误")
-		return
-	}
-	if len(contracts) == 0 || len(companies) == 0 {
-		return
+// GetZhengzhouTradeDataByContracts 郑商所-根据合约获取持仓数据
+func GetZhengzhouTradeDataByContracts(classifyNames []string, startDate, endDate time.Time) (items []*BaseFromTradeCommonIndex, err error) {
+	var cond string
+	var pars []interface{}
+	if len(classifyNames) > 0 {
+		cond += fmt.Sprintf(` AND classify_name IN (%s)`, utils.GetOrmInReplace(len(classifyNames)))
+		pars = append(pars, classifyNames)
 	}
-	condBuy := fmt.Sprintf(`classify_name IN (%s)`, utils.GetOrmInReplace(len(contracts)))
-	parsBuy := make([]interface{}, 0)
-	parsBuy = append(parsBuy, contracts)
-
-	condSold := fmt.Sprintf(`classify_name IN (%s)`, utils.GetOrmInReplace(len(contracts)))
-	parsSold := make([]interface{}, 0)
-	parsSold = append(parsSold, contracts)
-
-	// 是否含有TOP20
-	var hasTop bool
-	var condCompanies []string
-	for _, v := range companies {
-		if v == TradeFuturesCompanyTop20 {
-			hasTop = true
-			continue
-		}
-		condCompanies = append(condCompanies, v)
-	}
-	if !hasTop {
-		if len(condCompanies) == 0 {
-			err = fmt.Errorf("查询条件-期货公司异常")
-			return
-		}
-		condBuy += fmt.Sprintf(` AND buy_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
-		parsBuy = append(parsBuy, condCompanies)
-		condSold += fmt.Sprintf(` AND sold_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
-		parsSold = append(parsSold, condCompanies)
-	} else {
-		if len(condCompanies) > 0 {
-			condBuy += fmt.Sprintf(` AND (rank = 999 OR buy_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
-			condSold += fmt.Sprintf(` AND (rank = 999 OR sold_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
-			parsBuy = append(parsBuy, condCompanies)
-			parsSold = append(parsSold, condCompanies)
-		} else {
-			condBuy += ` AND rank = 999`
-			condSold += ` AND rank = 999`
-		}
+	if !startDate.IsZero() && !endDate.IsZero() {
+		cond += ` AND (data_time BETWEEN ? AND ?)`
+		pars = append(pars, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
 	}
-
-	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
-	sql := `SELECT
-			rank,
-			buy_short_name AS company_name,
-			buy_value AS val,
-			buy_change AS val_change,
-			classify_name AS classify_type,
-			data_time,
-			1 AS val_type 
-		FROM
-			%s 
-		WHERE
-			%s
-		UNION ALL
-		(
-		SELECT
-			rank,
-			sold_short_name,
-			sold_value,
-			sold_change,
-			classify_name AS classify_type,
-			data_time,
-			2 AS val_type 
-		FROM
-			%s 
-		WHERE
-			%s
-		)`
-	sql = fmt.Sprintf(sql, tableName, condBuy, tableName, condSold)
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sql, parsBuy, parsSold).QueryRows(&items)
+	// ps.classify_name实为合约代码
+	fields := []string{"rank", "buy_short_name", "buy_value", "buy_change", "sold_short_name", "sold_value", "sold_change", "classify_name AS classify_type", "data_time"}
+	sql := fmt.Sprintf(`SELECT %s FROM base_from_trade_zhengzhou_index WHERE 1=1 %s ORDER BY data_time DESC`, strings.Join(fields, ","), cond)
+	_, err = orm.NewOrmUsingDB("data").Raw(sql, pars).QueryRows(&items)
 	return
 }
 
+// GetTradeZhengzhouDataByClassifyAndCompany 郑商所-根据品种和公司名称获取持仓数据
+//func GetTradeZhengzhouDataByClassifyAndCompany(exchange string, contracts, companies []string) (items []*OriginTradeData, err error) {
+//	if exchange == "" {
+//		err = fmt.Errorf("数据表名称有误")
+//		return
+//	}
+//	if len(contracts) == 0 || len(companies) == 0 {
+//		return
+//	}
+//	condBuy := fmt.Sprintf(`classify_name IN (%s)`, utils.GetOrmInReplace(len(contracts)))
+//	parsBuy := make([]interface{}, 0)
+//	parsBuy = append(parsBuy, contracts)
+//
+//	condSold := fmt.Sprintf(`classify_name IN (%s)`, utils.GetOrmInReplace(len(contracts)))
+//	parsSold := make([]interface{}, 0)
+//	parsSold = append(parsSold, contracts)
+//
+//	// 是否含有TOP20
+//	var hasTop bool
+//	var condCompanies []string
+//	for _, v := range companies {
+//		if v == TradeFuturesCompanyTop20 {
+//			hasTop = true
+//			continue
+//		}
+//		condCompanies = append(condCompanies, v)
+//	}
+//	if !hasTop {
+//		if len(condCompanies) == 0 {
+//			err = fmt.Errorf("查询条件-期货公司异常")
+//			return
+//		}
+//		condBuy += fmt.Sprintf(` AND buy_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
+//		parsBuy = append(parsBuy, condCompanies)
+//		condSold += fmt.Sprintf(` AND sold_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
+//		parsSold = append(parsSold, condCompanies)
+//	} else {
+//		if len(condCompanies) > 0 {
+//			condBuy += fmt.Sprintf(` AND (rank = 999 OR buy_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
+//			condSold += fmt.Sprintf(` AND (rank = 999 OR sold_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
+//			parsBuy = append(parsBuy, condCompanies)
+//			parsSold = append(parsSold, condCompanies)
+//		} else {
+//			condBuy += ` AND rank = 999`
+//			condSold += ` AND rank = 999`
+//		}
+//	}
+//
+//	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
+//	sql := `SELECT
+//			rank,
+//			buy_short_name AS company_name,
+//			buy_value AS val,
+//			buy_change AS val_change,
+//			classify_name AS classify_type,
+//			data_time,
+//			1 AS val_type
+//		FROM
+//			%s
+//		WHERE
+//			%s
+//		UNION ALL
+//		(
+//		SELECT
+//			rank,
+//			sold_short_name,
+//			sold_value,
+//			sold_change,
+//			classify_name AS classify_type,
+//			data_time,
+//			2 AS val_type
+//		FROM
+//			%s
+//		WHERE
+//			%s
+//		)`
+//	sql = fmt.Sprintf(sql, tableName, condBuy, tableName, condSold)
+//	o := orm.NewOrmUsingDB("data")
+//	_, err = o.Raw(sql, parsBuy, parsSold).QueryRows(&items)
+//	return
+//}
+
 // ContractCompanyTradeData [合约-期货公司]持仓数据
 type ContractCompanyTradeData struct {
 	Exchange     string                          `description:"交易所"`
@@ -432,138 +508,138 @@ type ContractCompanyTradeDataList struct {
 }
 
 // GetLastTradeDataByClassify 获取[合约]末位多空单数据
-func GetLastTradeDataByClassify(exchange string, classifyNames, contracts []string) (items []*OriginTradeData, err error) {
-	if exchange == "" {
-		err = fmt.Errorf("数据表名称有误")
-		return
-	}
-	if len(classifyNames) == 0 || len(contracts) == 0 {
-		return
-	}
-	classifyReplacer := utils.GetOrmInReplace(len(classifyNames))
-	contractReplacer := utils.GetOrmInReplace(len(contracts))
-
-	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
-	sql := `SELECT 
-			tpt.rank,
-			tpt.buy_short_name AS company_name,
-			tpt.buy_value AS val,
-			tpt.buy_change AS val_change,
-			tpt.classify_name,
-			tpt.classify_type,
-			tpt.data_time,
-			1 AS val_type
-		FROM 
-			%s tpt
-		JOIN 
-			(
-				SELECT
-					data_time, classify_type, MAX(rank) AS max_rank
-				FROM 
-					%s
-				WHERE 
-					classify_name IN (%s) AND classify_type IN (%s) AND buy_short_name <> ''
-				GROUP BY 
-					data_time,
-					classify_type
-			) sub
-		ON
-			tpt.data_time = sub.data_time AND tpt.classify_type = sub.classify_type AND tpt.rank = sub.max_rank
-		WHERE 
-			tpt.classify_name IN (%s) AND tpt.classify_type IN (%s)
-		UNION ALL
-		(
-		SELECT 
-			tpt.rank, tpt.sold_short_name, tpt.sold_value, tpt.sold_change, tpt.classify_name, tpt.classify_type, tpt.data_time, 2 AS val_type
-		FROM 
-			%s tpt
-		JOIN 
-			(
-				SELECT 
-					data_time, classify_type, MAX(rank) AS max_rank
-				FROM 
-					%s
-				WHERE 
-					classify_name IN (%s) AND classify_type IN (%s) AND sold_short_name <> ''
-				GROUP BY 
-					data_time, classify_type
-			) sub
-		ON 
-			tpt.data_time = sub.data_time AND tpt.classify_type = sub.classify_type AND tpt.rank = sub.max_rank
-		WHERE 
-			tpt.classify_name IN (%s) AND tpt.classify_type IN (%s)
-		)`
-	sql = fmt.Sprintf(sql, tableName, tableName, classifyReplacer, contractReplacer, classifyReplacer, contractReplacer, tableName, tableName, classifyReplacer, contractReplacer, classifyReplacer, contractReplacer)
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sql, classifyNames, contracts, classifyNames, contracts, classifyNames, contracts, classifyNames, contracts).QueryRows(&items)
-	return
-}
+//func GetLastTradeDataByClassify(exchange string, classifyNames, contracts []string) (items []*OriginTradeData, err error) {
+//	if exchange == "" {
+//		err = fmt.Errorf("数据表名称有误")
+//		return
+//	}
+//	if len(classifyNames) == 0 || len(contracts) == 0 {
+//		return
+//	}
+//	classifyReplacer := utils.GetOrmInReplace(len(classifyNames))
+//	contractReplacer := utils.GetOrmInReplace(len(contracts))
+//
+//	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
+//	sql := `SELECT
+//			tpt.rank,
+//			tpt.buy_short_name AS company_name,
+//			tpt.buy_value AS val,
+//			tpt.buy_change AS val_change,
+//			tpt.classify_name,
+//			tpt.classify_type,
+//			tpt.data_time,
+//			1 AS val_type
+//		FROM
+//			%s tpt
+//		JOIN
+//			(
+//				SELECT
+//					data_time, classify_type, MAX(rank) AS max_rank
+//				FROM
+//					%s
+//				WHERE
+//					classify_name IN (%s) AND classify_type IN (%s) AND buy_short_name <> ''
+//				GROUP BY
+//					data_time,
+//					classify_type
+//			) sub
+//		ON
+//			tpt.data_time = sub.data_time AND tpt.classify_type = sub.classify_type AND tpt.rank = sub.max_rank
+//		WHERE
+//			tpt.classify_name IN (%s) AND tpt.classify_type IN (%s)
+//		UNION ALL
+//		(
+//		SELECT
+//			tpt.rank, tpt.sold_short_name, tpt.sold_value, tpt.sold_change, tpt.classify_name, tpt.classify_type, tpt.data_time, 2 AS val_type
+//		FROM
+//			%s tpt
+//		JOIN
+//			(
+//				SELECT
+//					data_time, classify_type, MAX(rank) AS max_rank
+//				FROM
+//					%s
+//				WHERE
+//					classify_name IN (%s) AND classify_type IN (%s) AND sold_short_name <> ''
+//				GROUP BY
+//					data_time, classify_type
+//			) sub
+//		ON
+//			tpt.data_time = sub.data_time AND tpt.classify_type = sub.classify_type AND tpt.rank = sub.max_rank
+//		WHERE
+//			tpt.classify_name IN (%s) AND tpt.classify_type IN (%s)
+//		)`
+//	sql = fmt.Sprintf(sql, tableName, tableName, classifyReplacer, contractReplacer, classifyReplacer, contractReplacer, tableName, tableName, classifyReplacer, contractReplacer, classifyReplacer, contractReplacer)
+//	o := orm.NewOrmUsingDB("data")
+//	_, err = o.Raw(sql, classifyNames, contracts, classifyNames, contracts, classifyNames, contracts, classifyNames, contracts).QueryRows(&items)
+//	return
+//}
 
 // GetLastTradeZhengzhouDataByClassify 郑商所-获取[合约]末位多空单数据
-func GetLastTradeZhengzhouDataByClassify(exchange string, contracts []string) (items []*OriginTradeData, err error) {
-	if exchange == "" {
-		err = fmt.Errorf("数据表名称有误")
-		return
-	}
-	if len(contracts) == 0 {
-		return
-	}
-	contractReplacer := utils.GetOrmInReplace(len(contracts))
-
-	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
-	sql := `SELECT 
-			tpt.rank,
-			tpt.buy_short_name AS company_name,
-			tpt.buy_value AS val,
-			tpt.buy_change AS val_change,
-  			tpt.classify_name AS classify_type,
-			tpt.data_time,
-			1 AS val_type
-		FROM 
-			%s tpt
-		JOIN 
-			(
-				SELECT
-					data_time, classify_name, MAX(rank) AS max_rank
-				FROM 
-					%s
-				WHERE 
-					classify_name IN (%s) AND buy_short_name <> ''
-				GROUP BY 
-					data_time,
-					classify_name
-			) sub
-		ON
-			tpt.data_time = sub.data_time AND tpt.classify_name = sub.classify_name AND tpt.rank = sub.max_rank
-		WHERE 
-			tpt.classify_name IN (%s)
-		UNION ALL
-		(
-		SELECT 
-			tpt.rank, tpt.sold_short_name, tpt.sold_value, tpt.sold_change, tpt.classify_name AS classify_type, tpt.data_time, 2 AS val_type
-		FROM 
-			%s tpt
-		JOIN 
-			(
-				SELECT 
-					data_time, classify_name, MAX(rank) AS max_rank
-				FROM 
-					%s
-				WHERE 
-					classify_name IN (%s) AND sold_short_name <> ''
-				GROUP BY 
-					data_time, classify_name
-			) sub
-		ON 
-			tpt.data_time = sub.data_time AND tpt.classify_name = sub.classify_name AND tpt.rank = sub.max_rank
-		WHERE 
-			tpt.classify_name IN (%s)
-		)`
-	sql = fmt.Sprintf(sql, tableName, tableName, contractReplacer, contractReplacer, tableName, tableName, contractReplacer, contractReplacer)
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sql, contracts, contracts, contracts, contracts).QueryRows(&items)
-	return
-}
+//func GetLastTradeZhengzhouDataByClassify(exchange string, contracts []string) (items []*OriginTradeData, err error) {
+//	if exchange == "" {
+//		err = fmt.Errorf("数据表名称有误")
+//		return
+//	}
+//	if len(contracts) == 0 {
+//		return
+//	}
+//	contractReplacer := utils.GetOrmInReplace(len(contracts))
+//
+//	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
+//	sql := `SELECT
+//			tpt.rank,
+//			tpt.buy_short_name AS company_name,
+//			tpt.buy_value AS val,
+//			tpt.buy_change AS val_change,
+//  			tpt.classify_name AS classify_type,
+//			tpt.data_time,
+//			1 AS val_type
+//		FROM
+//			%s tpt
+//		JOIN
+//			(
+//				SELECT
+//					data_time, classify_name, MAX(rank) AS max_rank
+//				FROM
+//					%s
+//				WHERE
+//					classify_name IN (%s) AND buy_short_name <> ''
+//				GROUP BY
+//					data_time,
+//					classify_name
+//			) sub
+//		ON
+//			tpt.data_time = sub.data_time AND tpt.classify_name = sub.classify_name AND tpt.rank = sub.max_rank
+//		WHERE
+//			tpt.classify_name IN (%s)
+//		UNION ALL
+//		(
+//		SELECT
+//			tpt.rank, tpt.sold_short_name, tpt.sold_value, tpt.sold_change, tpt.classify_name AS classify_type, tpt.data_time, 2 AS val_type
+//		FROM
+//			%s tpt
+//		JOIN
+//			(
+//				SELECT
+//					data_time, classify_name, MAX(rank) AS max_rank
+//				FROM
+//					%s
+//				WHERE
+//					classify_name IN (%s) AND sold_short_name <> ''
+//				GROUP BY
+//					data_time, classify_name
+//			) sub
+//		ON
+//			tpt.data_time = sub.data_time AND tpt.classify_name = sub.classify_name AND tpt.rank = sub.max_rank
+//		WHERE
+//			tpt.classify_name IN (%s)
+//		)`
+//	sql = fmt.Sprintf(sql, tableName, tableName, contractReplacer, contractReplacer, tableName, tableName, contractReplacer, contractReplacer)
+//	o := orm.NewOrmUsingDB("data")
+//	_, err = o.Raw(sql, contracts, contracts, contracts, contracts).QueryRows(&items)
+//	return
+//}
 
 type BaseFromTradeGuangzhouIndex struct {
 	BaseFromTradeGuangzhouIndexId    int       `orm:"column(base_from_trade_guangzhou_index_id);pk"`
@@ -578,10 +654,41 @@ type BaseFromTradeGuangzhouIndex struct {
 	ModifyTime                       time.Time `description:"修改日期"`
 }
 
-func GetBaseFromTradeGuangzhouIndexByClassifyId(classifyId int) (list []*BaseFromTradeGuangzhouIndex, err error) {
+//func GetBaseFromTradeGuangzhouIndexByClassifyId(classifyId int, contractIds []int) (list []*BaseFromTradeGuangzhouIndex, err error) {
+//	o := orm.NewOrmUsingDB("data")
+//	cond := ` base_from_trade_guangzhou_classify_id = ?`
+//	pars := make([]interface{}, 0)
+//	pars = append(pars, classifyId)
+//	if len(contractIds) > 0 {
+//		cond += fmt.Sprintf(` AND base_from_trade_guangzhou_contract_id IN (%s)`, utils.GetOrmInReplace(len(contractIds)))
+//		pars = append(pars, contractIds)
+//	}
+//	sql := fmt.Sprintf(`SELECT * FROM base_from_trade_guangzhou_index WHERE 1=1 %s `, cond)
+//	_, err = o.Raw(sql, pars).QueryRows(&list)
+//	return
+//}
+
+func GetBaseFromTradeGuangzhouIndex(classifyIds []int, contracts []string, indexKeyword string) (list []*BaseFromTradeGuangzhouIndex, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := `SELECT * FROM base_from_trade_guangzhou_index WHERE base_from_trade_guangzhou_classify_id = ?`
-	_, err = o.Raw(sql, classifyId).QueryRows(&list)
+	cond := ``
+	pars := make([]interface{}, 0)
+	if len(classifyIds) > 0 {
+		cond += fmt.Sprintf(` AND b.base_from_trade_guangzhou_classify_id IN (%s)`, utils.GetOrmInReplace(len(classifyIds)))
+		pars = append(pars, classifyIds)
+	}
+	if len(contracts) > 0 {
+		cond += fmt.Sprintf(` AND b.contract IN (%s)`, utils.GetOrmInReplace(len(contracts)))
+		pars = append(pars, contracts)
+	}
+	if indexKeyword != "" {
+		cond += fmt.Sprintf(` AND a.index_name LIKE ?`)
+		pars = append(pars, indexKeyword)
+	}
+	sql := `SELECT a.* FROM base_from_trade_guangzhou_index AS a
+		JOIN base_from_trade_guangzhou_contract AS b ON a.base_from_trade_guangzhou_contract_id = b.base_from_trade_guangzhou_contract_id
+		WHERE 1=1 %s`
+	sql = fmt.Sprintf(sql, cond)
+	_, err = o.Raw(sql, pars).QueryRows(&list)
 	return
 }
 
@@ -596,48 +703,60 @@ type BaseFromTradeGuangzhouData struct {
 	ModifyTime                    time.Time `description:"修改日期"`
 }
 
-// GetBaseFromTradeGuangzhouDataByIndexIds 获取指标数据
-func GetBaseFromTradeGuangzhouDataByIndexIds(indexIds []int) (list []*BaseFromTradeGuangzhouData, err error) {
+// GetBaseFromTradeGuangzhouDataByIndexIds 广期所-获取指标数据
+func GetBaseFromTradeGuangzhouDataByIndexIds(indexIds []int, startDate, endDate time.Time) (list []*BaseFromTradeGuangzhouData, err error) {
 	if len(indexIds) == 0 {
 		return
 	}
-	o := orm.NewOrmUsingDB("data")
-	sql := fmt.Sprintf(`SELECT * FROM base_from_trade_guangzhou_data WHERE base_from_trade_guangzhou_index_id IN (%s) ORDER BY base_from_trade_guangzhou_index_id`, utils.GetOrmInReplace(len(indexIds)))
-	_, err = o.Raw(sql, indexIds).QueryRows(&list)
+	cond := fmt.Sprintf(` AND base_from_trade_guangzhou_index_id IN (%s)`, utils.GetOrmInReplace(len(indexIds)))
+	pars := make([]interface{}, 0)
+	pars = append(pars, indexIds)
+	if !startDate.IsZero() && !endDate.IsZero() {
+		if startDate.Equal(endDate) {
+			cond += ` AND data_time = ?`
+			pars = append(pars, startDate.Format(utils.FormatDate))
+		}
+		if !startDate.Equal(endDate) {
+			cond += ` AND (data_time BETWEEN ? AND ?)`
+			pars = append(pars, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
+		}
+	}
+	sql := fmt.Sprintf(`SELECT * FROM base_from_trade_guangzhou_data WHERE 1=1 %s ORDER BY base_from_trade_guangzhou_index_id`, cond)
+	_, err = orm.NewOrmUsingDB("data").Raw(sql, pars).QueryRows(&list)
 	return
 }
 
 // GetBaseFromTradeGuangzhouMinDataByIndexIds 获取指标中的末位数据
-func GetBaseFromTradeGuangzhouMinDataByIndexIds(indexIds []int) (list []*BaseFromTradeGuangzhouData, err error) {
-	indexLen := len(indexIds)
-	if indexLen == 0 {
-		return
-	}
-	o := orm.NewOrmUsingDB("data")
-	sql := fmt.Sprintf(`SELECT 
-			t1.data_time,
-			t1.min_value AS value
-		FROM 
-			(
-				SELECT 
-					data_time,
-					MIN(value) AS min_value
-				FROM 
-					base_from_trade_guangzhou_data
-				WHERE 
-					base_from_trade_guangzhou_index_id IN (%s)
-				GROUP BY 
-					data_time
-			) t1
-		JOIN 
-			base_from_trade_guangzhou_data t2
-		ON 
-			t1.data_time = t2.data_time AND t1.min_value = t2.value AND t2.base_from_trade_guangzhou_index_id IN (%s)
-		GROUP BY 
-			t1.data_time`, utils.GetOrmInReplace(indexLen), utils.GetOrmInReplace(indexLen))
-	_, err = o.Raw(sql, indexIds, indexIds).QueryRows(&list)
-	return
-}
+//func GetBaseFromTradeGuangzhouMinDataByIndexIds(indexIds []int) (list []*BaseFromTradeGuangzhouData, err error) {
+//	indexLen := len(indexIds)
+//	if indexLen == 0 {
+//		return
+//	}
+//	o := orm.NewOrmUsingDB("data")
+//	sql := fmt.Sprintf(`SELECT
+//			t1.data_time,
+//			t1.min_value AS value
+//		FROM
+//			(
+//				SELECT
+//					data_time,
+//					MIN(value) AS min_value
+//				FROM
+//					base_from_trade_guangzhou_data
+//				WHERE
+//					base_from_trade_guangzhou_index_id IN (%s)
+//				GROUP BY
+//					data_time
+//			) t1
+//		JOIN
+//			base_from_trade_guangzhou_data t2
+//		ON
+//			t1.data_time = t2.data_time AND t1.min_value = t2.value AND t2.base_from_trade_guangzhou_index_id IN (%s)
+//		GROUP BY
+//			t1.data_time`, utils.GetOrmInReplace(indexLen), utils.GetOrmInReplace(indexLen))
+//	_, err = o.Raw(sql, indexIds, indexIds).QueryRows(&list)
+//	return
+//}
 
 // ContractTopRankData TOP20合约排名数据
 type ContractTopRankData struct {
@@ -654,7 +773,7 @@ type ContractTopRankData struct {
 	DataTime      time.Time `description:"数据日期"`
 }
 
-// TODO:GetContractTopRankData 获取合约根据当日成交量排名
+// GetContractTopRankData 获取合约TOP20根据当日成交量排名
 func GetContractTopRankData(exchange string, classifyNames []string, dataDate time.Time) (items []*ContractTopRankData, err error) {
 	if exchange == "" {
 		err = fmt.Errorf("数据表名称有误")
@@ -664,10 +783,25 @@ func GetContractTopRankData(exchange string, classifyNames []string, dataDate ti
 		return
 	}
 	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
-	sql := `SELECT * FROM %s WHERE data_time = ? AND classify_name IN (%s) AND rank = 999 GROUP BY classify_type ORDER BY deal_value DESC`
-	sql = fmt.Sprintf(sql, tableName, utils.GetOrmInReplace(len(classifyNames)))
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sql, dataDate.Format(utils.FormatDate), classifyNames).QueryRows(&items)
+	// 大商所存在TOP20的rank=0
+	queryRank := ` rank = 999`
+	if exchange == TradeExchangeDalian {
+		queryRank = ` (rank = 999 OR rank = 0)`
+	}
+	sql := `SELECT * FROM %s WHERE data_time = ? AND classify_name IN (%s) AND %s GROUP BY classify_type ORDER BY deal_value DESC`
+	sql = fmt.Sprintf(sql, tableName, utils.GetOrmInReplace(len(classifyNames)), queryRank)
+	_, err = orm.NewOrmUsingDB("data").Raw(sql, dataDate.Format(utils.FormatDate), classifyNames).QueryRows(&items)
+	return
+}
+
+// GetZhengzhouContractTopRankData 郑商所-获取合约根据当日成交量排名
+func GetZhengzhouContractTopRankData(classifyNames []string, dataDate time.Time) (items []*ContractTopRankData, err error) {
+	if len(classifyNames) == 0 {
+		return
+	}
+	sql := `SELECT * FROM base_from_trade_zhengzhou_index WHERE data_time = ? AND classify_name IN (%s) AND rank = 999 GROUP BY classify_name ORDER BY deal_value DESC`
+	sql = fmt.Sprintf(sql, utils.GetOrmInReplace(len(classifyNames)))
+	_, err = orm.NewOrmUsingDB("data").Raw(sql, dataDate.Format(utils.FormatDate), classifyNames).QueryRows(&items)
 	return
 }
 

+ 1 - 1
models/data_manage/trade_analysis/trade_analysis_table.go

@@ -35,7 +35,7 @@ type TableRowData struct {
 	TopSoldValue     int     `description:"前20空单"`
 	TopBuyChange     int     `description:"前20多单变动"`
 	TopSoldChange    int     `description:"前20空单变动"`
-	TopPureBuy       int     `description:"前20净多单变动"`
+	TopPureBuy       int     `description:"前20净多单"`
 	TopPureBuyChange int     `description:"前20净多单变动"`
 	TopBuySoldRatio  float64 `description:"前20多空比"`
 }

+ 25 - 0
services/data/trade_analysis/trade_analysis.go

@@ -406,3 +406,28 @@ func GetPositionTopDetail(req trade_analysis.GetPositionTopReq) (ret trade_analy
 
 	return
 }
+
+// GetZhengzhouContractsByClassifyNames 郑商所-获取所选品种下的所有合约
+func GetZhengzhouContractsByClassifyNames(classifyNames []string) (contracts []string, err error) {
+	var cond string
+	var pars []interface{}
+	classifyOb := new(trade_analysis.BaseFromTradeClassify)
+	cond += fmt.Sprintf(` AND %s = ?`, classifyOb.Cols().Exchange)
+	pars = append(pars, trade_analysis.TradeExchangeZhengzhou)
+	fields := []string{classifyOb.Cols().ClassifyName, classifyOb.Cols().Exchange}
+	list, e := classifyOb.GetClassifyItemsByCondition(cond, pars, fields, "id ASC")
+	if e != nil {
+		err = fmt.Errorf("获取郑商所品种合约失败, %v", e)
+		return
+	}
+	for _, v := range list {
+		classifyName := GetZhengzhouClassifyName(v.ClassifyName)
+		if classifyName == "" {
+			continue
+		}
+		if utils.InArrayByStr(classifyNames, classifyName) {
+			contracts = append(contracts, v.ClassifyName)
+		}
+	}
+	return
+}

+ 3 - 3
services/data/trade_analysis/trade_analysis_correlation.go

@@ -98,8 +98,8 @@ func GetCorrelationTableRowsDataByConfig(tableConfig tradeAnalysisModel.Correlat
 	}
 
 	// 根据配置取出需要查询的合约
-	baseDate := time.Now()                                    // 取合约以当日为基准(如主力合约为当日的主力合约)
-	baseDate = time.Date(2024, 8, 12, 0, 0, 0, 0, time.Local) // TODO:测试数据
+	baseDate := time.Now() // 取合约以当日为基准(如主力合约为当日的主力合约)
+	//baseDate = time.Date(2024, 8, 12, 0, 0, 0, 0, time.Local) // TODO:测试数据
 	contracts, e := GetTopContractsByType(tableConfig.ContractType, tableConfig.Exchange, tableConfig.ClassifyName, baseDate)
 	if e != nil {
 		err = fmt.Errorf("获取持仓相关性合约失败, %v", e)
@@ -108,7 +108,7 @@ func GetCorrelationTableRowsDataByConfig(tableConfig tradeAnalysisModel.Correlat
 	//fmt.Println(contracts)
 
 	// [合约+期货公司]持仓数据
-	tradeData, e := GetContractCompanyTradeData(tableConfig.Exchange, []string{tableConfig.ClassifyName}, contracts, tableConfig.CompanyNames, tableConfig.PredictRatio)
+	tradeData, e := GetCorrelationTableTradeData(tableConfig.Exchange, []string{tableConfig.ClassifyName}, contracts, tableConfig.CompanyNames, tableConfig.PredictRatio)
 	if e != nil {
 		err = fmt.Errorf("获取[合约+期货公司]持仓数据失败, %v", e)
 		return

+ 541 - 361
services/data/trade_analysis/trade_analysis_data.go

@@ -144,144 +144,158 @@ func FormatCompanyTradeData2EdbMappings(companyTradeData []*tradeAnalysisModel.C
 	return
 }
 
-func GetOriginTradeData(exchange, classifyName string, contracts, companies []string, predictRatio float64) (companyTradeData []*tradeAnalysisModel.ContractCompanyTradeData, err error) {
+func GetWarehouseTradeData(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 {
-		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, e := tradeAnalysis.GetTradeDataByClassifyAndCompany(exchange, []string{classifyName}, contracts, queryCompanies, time.Time{}, time.Time{})
+	//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, e := tradeAnalysis.GetTradeDataByClassifyAndCompany(exchange, []string{classifyName}, contracts, queryCompanies, time.Time{}, time.Time{})
+	////if e != nil {
+	////	err = fmt.Errorf("获取多空单原始数据失败, %v", e)
+	////	return
+	////}
+	//originList, _, lastOriginList, e := tradeAnalysis.GetTradeDataByContracts(exchange, []string{classifyName}, contracts, queryCompanies, time.Time{}, time.Time{})
+	//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 {
+	//	// Rank999-对应的是TOP20
+	//	companyName := v.CompanyName
+	//	//if v.Rank == 999 {
+	//	//	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, []string{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
+	//	}
+	//}
+
+	//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)
+
+	// 获取合约持仓数据
+	contractTradeData, lastBuyVal, lastSoldVal, e := GetContractCompanyTradeData(exchange, []string{classifyName}, contracts, companies, time.Time{}, time.Time{})
 	if e != nil {
-		err = fmt.Errorf("获取多空单原始数据失败, %v", e)
+		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 {
-		// Rank999-对应的是TOP20
-		companyName := v.CompanyName
-		if v.Rank == 999 {
-			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, []string{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)
+	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
@@ -658,13 +672,17 @@ func GetTopContractRank(exchange string, classifyNames []string, dataDate time.T
 		tradeAnalysis = &BaseTradeAnalysis{}
 	}
 
-	// TODO:郑商所品种
+	// 郑商所-需要把所选品种转为实际合约进行后续的查询
 	if exchange == tradeAnalysisModel.TradeExchangeZhengzhou {
-
+		classifies, e := GetZhengzhouContractsByClassifyNames(classifyNames)
+		if e != nil {
+			err = fmt.Errorf("获取郑商所实际合约失败, %v", e)
+			return
+		}
+		classifyNames = classifies
 	}
 
 	// 获取多单/空单原始数据
-	// TODO:净多单变化
 	rankData, e := tradeAnalysis.GetContractTopRankData(exchange, classifyNames, dataDate)
 	if e != nil {
 		err = fmt.Errorf("获取多空单原始数据失败, %v", e)
@@ -678,145 +696,158 @@ func GetTopContractRank(exchange string, classifyNames []string, dataDate time.T
 	return
 }
 
-func GetTableTradeData(exchange string, classifyNames, contracts, companies []string, predictRatio float64, baseDate time.Time, contractType int) (companyTradeData []*tradeAnalysisModel.ContractCompanyTradeData, err error) {
+// GetTableTradeData 获取多空分析表格持仓数据
+func GetTableTradeData(exchange string, classifyNames, contracts, companies []string, predictRatio float64, startDate, endDate time.Time, contractType int) (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 {
-		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, e := tradeAnalysis.GetTradeDataByClassifyAndCompany(exchange, classifyNames, contracts, queryCompanies, baseDate.AddDate(0, 0, -5), baseDate.AddDate(0, 0, 5))
+	//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, e := tradeAnalysis.GetTradeDataByClassifyAndCompany(exchange, classifyNames, contracts, queryCompanies, baseDate.AddDate(0, 0, -5), baseDate.AddDate(0, 0, 5))
+	////if e != nil {
+	////	err = fmt.Errorf("获取多空单原始数据失败, %v", e)
+	////	return
+	////}
+	//originList, _, lastOriginList, e := tradeAnalysis.GetTradeDataByContracts(exchange, classifyNames, contracts, queryCompanies, baseDate.AddDate(0, 0, -5), baseDate.AddDate(0, 0, 5))
+	//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 {
+	//	// Rank999-对应的是TOP20
+	//	companyName := v.CompanyName
+	//	//if v.Rank == 999 {
+	//	//	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, classifyNames, 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
+	//	}
+	//}
+
+	// 获取合约持仓数据
+	contractTradeData, lastBuyVal, lastSoldVal, e := GetContractCompanyTradeData(exchange, classifyNames, contracts, companies, startDate, endDate)
 	if e != nil {
-		err = fmt.Errorf("获取多空单原始数据失败, %v", e)
+		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 {
-		// Rank999-对应的是TOP20
-		companyName := v.CompanyName
-		if v.Rank == 999 {
-			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, classifyNames, 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
-		}
-	}
-
 	// 填充[合约-公司]预估数据, 并根据[公司-多合约]分组, [公司]算作一个指标, 指标值为[多个合约]的计算加总
 	companyTradeData = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0)
 	companyContracts := make(map[string][]*tradeAnalysisModel.ContractCompanyTradeData)
-	for _, v := range keyItems {
-		td, fd, ed, e := PredictingTradeData(v.DataList, contractLastBuyDateVal[v.ClassifyType], contractLastSoldDateVal[v.ClassifyType], predictRatio)
+	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
@@ -917,8 +948,229 @@ func GetTableTradeData(exchange string, classifyNames, contracts, companies []st
 	return
 }
 
-// GetContractCompanyTradeData 获取[合约-期货公司]持仓数据, 填充预估值
-func GetContractCompanyTradeData(exchange string, classifyNames, contracts, companies []string, predictRatio float64) (tradeData []*tradeAnalysisModel.ContractCompanyTradeData, err error) {
+// GetCorrelationTableTradeData 获取相关性表格持仓数据
+func GetCorrelationTableTradeData(exchange string, classifyNames, contracts, companies []string, predictRatio float64) (tradeData []*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 {
+	//	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, e := tradeAnalysis.GetTradeDataByClassifyAndCompany(exchange, classifyNames, contracts, queryCompanies, time.Time{}, time.Time{})
+	////if e != nil {
+	////	err = fmt.Errorf("获取多空单原始数据失败, %v", e)
+	////	return
+	////}
+	//originList, _, lastOriginList, e := tradeAnalysis.GetTradeDataByContracts(exchange, classifyNames, contracts, queryCompanies, time.Time{}, time.Time{})
+	//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 {
+	//		// Rank999-对应的是TOP20
+	//		companyName := v.CompanyName
+	//		if v.Rank == 999 {
+	//			companyName = tradeAnalysisModel.TradeFuturesCompanyTop20
+	//		}
+	//
+	//		k := fmt.Sprintf("%s-%s", v.ClassifyType, companyName)
+	//		if keyItems[k] == nil {
+	//			keyItems[k] = new(tradeAnalysisModel.ContractCompanyTradeData)
+	//			keyItems[k].Exchange = exchange
+	//			keyItems[k].CompanyName = companyName
+	//			keyItems[k].ClassifyName = v.ClassifyName
+	//			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, classifyNames, 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
+	//	}
+	//}
+
+	// 获取合约持仓数据
+	contractTradeData, lastBuyVal, lastSoldVal, e := GetContractCompanyTradeData(exchange, classifyNames, contracts, companies, time.Time{}, time.Time{})
+	if e != nil {
+		err = fmt.Errorf("获取合约-持仓数据失败, %v", e)
+		return
+	}
+
+	// 填充预估数据
+	tradeData = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0)
+	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
+		tradeData = append(tradeData, v)
+	}
+	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)
 	{
@@ -981,32 +1233,32 @@ func GetContractCompanyTradeData(exchange string, classifyNames, contracts, comp
 	}
 
 	// 获取多单/空单原始数据
-	originList, e := tradeAnalysis.GetTradeDataByClassifyAndCompany(exchange, classifyNames, contracts, queryCompanies, time.Time{}, time.Time{})
+	originList, _, lastOriginList, e := tradeAnalysis.GetTradeDataByContracts(exchange, classifyNames, contracts, queryCompanies, startDate, endDate)
 	if e != nil {
 		err = fmt.Errorf("获取多空单原始数据失败, %v", e)
 		return
 	}
 
 	// [合约-期货公司]数据分组
-	keyItems := make(map[string]*tradeAnalysisModel.ContractCompanyTradeData)
+	contractTradeData = make(map[string]*tradeAnalysisModel.ContractCompanyTradeData)
 	{
 		keyDateData := make(map[string]*tradeAnalysisModel.ContractCompanyTradeDataList)
 		keyDateDataExist := make(map[string]bool)
 		for _, v := range originList {
 			// Rank999-对应的是TOP20
 			companyName := v.CompanyName
-			if v.Rank == 999 {
-				companyName = tradeAnalysisModel.TradeFuturesCompanyTop20
-			}
+			//if v.Rank == 999 {
+			//	companyName = tradeAnalysisModel.TradeFuturesCompanyTop20
+			//}
 
 			k := fmt.Sprintf("%s-%s", v.ClassifyType, companyName)
-			if keyItems[k] == nil {
-				keyItems[k] = new(tradeAnalysisModel.ContractCompanyTradeData)
-				keyItems[k].Exchange = exchange
-				keyItems[k].CompanyName = companyName
-				keyItems[k].ClassifyName = v.ClassifyName
-				keyItems[k].ClassifyType = v.ClassifyType
-				keyItems[k].DataList = make([]*tradeAnalysisModel.ContractCompanyTradeDataList, 0)
+			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))
@@ -1027,101 +1279,29 @@ func GetContractCompanyTradeData(exchange string, classifyNames, contracts, comp
 				keyDateData[kd].SoldChangeType = tradeAnalysisModel.TradeDataTypeOrigin
 			}
 			if !keyDateDataExist[kd] {
-				keyItems[k].DataList = append(keyItems[k].DataList, keyDateData[kd])
+				contractTradeData[k].DataList = append(contractTradeData[k].DataList, keyDateData[kd])
 				keyDateDataExist[kd] = true
 			}
 		}
 	}
 
-	// 获取[合约]每日的末位多空单
-	contractLastBuyDateVal := make(map[string]map[time.Time]int)
-	contractLastSoldDateVal := make(map[string]map[time.Time]int)
+	// 合约的[日期-末位值]
+	lastBuyVal = make(map[string]map[time.Time]int)
+	lastSoldVal = make(map[string]map[time.Time]int)
 	{
-		lastOriginList, e := tradeAnalysis.GetLastTradeDataByClassify(exchange, classifyNames, 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)
+				if lastBuyVal[v.ClassifyType] == nil {
+					lastBuyVal[v.ClassifyType] = make(map[time.Time]int)
 				}
-				contractLastBuyDateVal[v.ClassifyType][v.DataTime] = v.Val
+				lastBuyVal[v.ClassifyType][v.DataTime] = v.Val
 				continue
 			}
-			if contractLastSoldDateVal[v.ClassifyType] == nil {
-				contractLastSoldDateVal[v.ClassifyType] = make(map[time.Time]int)
+			if lastSoldVal[v.ClassifyType] == nil {
+				lastSoldVal[v.ClassifyType] = make(map[time.Time]int)
 			}
-			contractLastSoldDateVal[v.ClassifyType][v.DataTime] = v.Val
-		}
-	}
-
-	// 填充预估数据
-	tradeData = make([]*tradeAnalysisModel.ContractCompanyTradeData, 0)
-	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
+			lastSoldVal[v.ClassifyType][v.DataTime] = v.Val
 		}
-		v.DataList = td
-		v.StartDate = fd
-		v.EndDate = ed
-		tradeData = append(tradeData, v)
-	}
-	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
 }

+ 506 - 145
services/data/trade_analysis/trade_analysis_interface.go

@@ -4,27 +4,160 @@ import (
 	tradeAnalysisModel "eta/eta_api/models/data_manage/trade_analysis"
 	"eta/eta_api/utils"
 	"fmt"
-	"strconv"
+	"sort"
 	"strings"
 	"time"
 )
 
 // TradeAnalysisInterface 持仓分析查询接口
 type TradeAnalysisInterface interface {
-	GetTradeDataByClassifyAndCompany(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, err error) // 根据品种和公司获取原始数据
-	GetLastTradeDataByClassify(exchange string, classifyName, contracts []string) (items []*tradeAnalysisModel.OriginTradeData, err error)                                                      // 获取品种末位数据
+	GetTradeDataByContracts(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, topItems, lastItems []*tradeAnalysisModel.OriginTradeData, err error)
 	GetContractTopRankData(exchange string, classifyNames []string, dataDate time.Time) (items []*tradeAnalysisModel.ContractTopRankData, err error)
+	//GetTradeDataByClassifyAndCompany(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, err error)
+	//GetLastTradeDataByClassify(exchange string, classifyName, contracts []string) (items []*tradeAnalysisModel.OriginTradeData, err error) // 获取品种末位数据
 }
 
 // BaseTradeAnalysis 通用交易所
 type BaseTradeAnalysis struct{}
 
-func (b *BaseTradeAnalysis) GetTradeDataByClassifyAndCompany(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, err error) {
-	return tradeAnalysisModel.GetTradeDataByClassifyAndCompany(exchange, classifyNames, contracts, queryCompanies, startDate, endDate)
+//func (b *BaseTradeAnalysis) GetTradeDataByClassifyAndCompany(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, err error) {
+//	return tradeAnalysisModel.GetTradeDataByClassifyAndCompany(exchange, classifyNames, contracts, queryCompanies, startDate, endDate)
+//}
+
+//func (b *BaseTradeAnalysis) GetLastTradeDataByClassify(exchange string, classifyName, contracts []string) (items []*tradeAnalysisModel.OriginTradeData, err error) {
+//	return tradeAnalysisModel.GetLastTradeDataByClassify(exchange, classifyName, contracts)
+//}
+
+// GetTradeDataByContracts 根据合约获取公司的持仓数据、TOP20数据以及每日的末位数据
+func (b *BaseTradeAnalysis) GetTradeDataByContracts(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items, topItems, lastItems []*tradeAnalysisModel.OriginTradeData, err error) {
+	// 根据合约获取数据
+	originData, e := tradeAnalysisModel.GetTradeDataByContracts(exchange, classifyNames, contracts, startDate, endDate)
+	if e != nil {
+		err = fmt.Errorf("根据合约获取持仓数据失败, %v", e)
+		return
+	}
+	items, topItems, lastItems = formatOriginData2UseData(originData, queryCompanies)
+	return
 }
 
-func (b *BaseTradeAnalysis) GetLastTradeDataByClassify(exchange string, classifyName, contracts []string) (items []*tradeAnalysisModel.OriginTradeData, err error) {
-	return tradeAnalysisModel.GetLastTradeDataByClassify(exchange, classifyName, contracts)
+// formatOriginData2UseData 原始数据转换为持仓数据、TOP20以及末位数据
+func formatOriginData2UseData(originData []*tradeAnalysisModel.BaseFromTradeCommonIndex, queryCompanies []string) (items, topItems, lastItems []*tradeAnalysisModel.OriginTradeData) {
+	items, topItems, lastItems = make([]*tradeAnalysisModel.OriginTradeData, 0), make([]*tradeAnalysisModel.OriginTradeData, 0), make([]*tradeAnalysisModel.OriginTradeData, 0)
+	buyMaxRank, soldMaxRang := make(map[string]*tradeAnalysisModel.BaseFromTradeCommonIndex), make(map[string]*tradeAnalysisModel.BaseFromTradeCommonIndex)
+	for _, v := range originData {
+		// TOP20(大商所的Rank存在为0的)
+		if v.Rank == 0 || v.Rank == 999 {
+			topBuy := &tradeAnalysisModel.OriginTradeData{
+				Rank:         v.Rank,
+				CompanyName:  tradeAnalysisModel.TradeFuturesCompanyTop20,
+				Val:          v.BuyValue,
+				ValChange:    v.BuyChange,
+				ValType:      1,
+				DataTime:     v.DataTime,
+				ClassifyName: v.ClassifyName,
+				ClassifyType: v.ClassifyType,
+			}
+			topSold := &tradeAnalysisModel.OriginTradeData{
+				Rank:         v.Rank,
+				CompanyName:  tradeAnalysisModel.TradeFuturesCompanyTop20,
+				Val:          v.SoldValue,
+				ValChange:    v.SoldChange,
+				ValType:      2,
+				DataTime:     v.DataTime,
+				ClassifyName: v.ClassifyName,
+				ClassifyType: v.ClassifyType,
+			}
+			topItems = append(topItems, topBuy, topSold)
+			continue
+		}
+
+		// 查询的公司-买单
+		contractDateKey := fmt.Sprintf("%s_%s", v.DataTime.Format(utils.FormatDate), v.ClassifyType)
+		if utils.InArrayByStr(queryCompanies, v.BuyShortName) {
+			items = append(items, &tradeAnalysisModel.OriginTradeData{
+				Rank:         v.Rank,
+				CompanyName:  v.BuyShortName,
+				Val:          v.BuyValue,
+				ValChange:    v.BuyChange,
+				ValType:      1,
+				DataTime:     v.DataTime,
+				ClassifyName: v.ClassifyName,
+				ClassifyType: v.ClassifyType,
+			})
+
+			// 比对[合约-数据日期]对应的rank,取出末位
+			if buyMaxRank[contractDateKey] != nil && v.Rank > buyMaxRank[contractDateKey].Rank {
+				buyMaxRank[contractDateKey] = v
+			}
+			if buyMaxRank[contractDateKey] == nil {
+				buyMaxRank[contractDateKey] = v
+			}
+		}
+
+		// 查询的公司-卖单
+		if utils.InArrayByStr(queryCompanies, v.SoldShortName) {
+			items = append(items, &tradeAnalysisModel.OriginTradeData{
+				Rank:         v.Rank,
+				CompanyName:  v.SoldShortName,
+				Val:          v.SoldValue,
+				ValChange:    v.SoldChange,
+				ValType:      2,
+				DataTime:     v.DataTime,
+				ClassifyName: v.ClassifyName,
+				ClassifyType: v.ClassifyType,
+			})
+
+			// 比对数据日期对应的rank,取出末位
+			if soldMaxRang[contractDateKey] != nil && v.Rank > soldMaxRang[contractDateKey].Rank {
+				soldMaxRang[contractDateKey] = v
+			}
+			if soldMaxRang[contractDateKey] == nil {
+				soldMaxRang[contractDateKey] = v
+			}
+		}
+	}
+
+	// 如果查询的公司中含TOP20,那么追加进items
+	var hasTop bool
+	if utils.InArrayByStr(queryCompanies, tradeAnalysisModel.TradeFuturesCompanyTop20) {
+		hasTop = true
+	}
+	if hasTop {
+		items = append(items, topItems...)
+	}
+
+	// 末位数据
+	for _, v := range buyMaxRank {
+		if v == nil {
+			continue
+		}
+		lastItems = append(lastItems, &tradeAnalysisModel.OriginTradeData{
+			Rank:         v.Rank,
+			CompanyName:  v.BuyShortName,
+			Val:          v.BuyValue,
+			ValChange:    v.BuyChange,
+			ValType:      1,
+			DataTime:     v.DataTime,
+			ClassifyName: v.ClassifyName,
+			ClassifyType: v.ClassifyType,
+		})
+	}
+	for _, v := range buyMaxRank {
+		if v == nil {
+			continue
+		}
+		lastItems = append(lastItems, &tradeAnalysisModel.OriginTradeData{
+			Rank:         v.Rank,
+			CompanyName:  v.SoldShortName,
+			Val:          v.SoldValue,
+			ValChange:    v.SoldChange,
+			ValType:      2,
+			DataTime:     v.DataTime,
+			ClassifyName: v.ClassifyName,
+			ClassifyType: v.ClassifyType,
+		})
+	}
+	return
 }
 
 func (b *BaseTradeAnalysis) GetContractTopRankData(exchange string, classifyNames []string, dataDate time.Time) (items []*tradeAnalysisModel.ContractTopRankData, err error) {
@@ -34,171 +167,399 @@ func (b *BaseTradeAnalysis) GetContractTopRankData(exchange string, classifyName
 // ZhengzhouTradeAnalysis 郑商所
 type ZhengzhouTradeAnalysis struct{}
 
-func (z *ZhengzhouTradeAnalysis) GetTradeDataByClassifyAndCompany(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, err error) {
-	// TODO:
-	return tradeAnalysisModel.GetTradeZhengzhouDataByClassifyAndCompany(exchange, contracts, queryCompanies)
-}
+//func (z *ZhengzhouTradeAnalysis) GetTradeDataByClassifyAndCompany(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, err error) {
+//	return tradeAnalysisModel.GetTradeZhengzhouDataByClassifyAndCompany(exchange, contracts, queryCompanies)
+//}
 
-func (z *ZhengzhouTradeAnalysis) GetLastTradeDataByClassify(exchange string, classifyName, contracts []string) (items []*tradeAnalysisModel.OriginTradeData, err error) {
-	return tradeAnalysisModel.GetLastTradeZhengzhouDataByClassify(exchange, contracts)
+//func (z *ZhengzhouTradeAnalysis) GetLastTradeDataByClassify(exchange string, classifyName, contracts []string) (items []*tradeAnalysisModel.OriginTradeData, err error) {
+//	return tradeAnalysisModel.GetLastTradeZhengzhouDataByClassify(exchange, contracts)
+//}
+
+func (z *ZhengzhouTradeAnalysis) GetTradeDataByContracts(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items, topItems, lastItems []*tradeAnalysisModel.OriginTradeData, err error) {
+	// 根据合约获取数据
+	originData, e := tradeAnalysisModel.GetZhengzhouTradeDataByContracts(contracts, startDate, endDate)
+	if e != nil {
+		err = fmt.Errorf("根据合约获取持仓数据失败, %v", e)
+		return
+	}
+	items, topItems, lastItems = formatOriginData2UseData(originData, queryCompanies)
+	return
 }
 
 func (z *ZhengzhouTradeAnalysis) GetContractTopRankData(exchange string, classifyNames []string, dataDate time.Time) (items []*tradeAnalysisModel.ContractTopRankData, err error) {
-	// TODO:
-	return tradeAnalysisModel.GetContractTopRankData(exchange, classifyNames, dataDate)
+	return tradeAnalysisModel.GetZhengzhouContractTopRankData(classifyNames, dataDate)
 }
 
 // GuangzhouTradeAnalysis 广期所
 type GuangzhouTradeAnalysis struct{}
 
-func (g *GuangzhouTradeAnalysis) GetTradeDataByClassifyAndCompany(exchange string, classifyNames []string, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, err error) {
-	classifyIdMap := map[string]int{"si": 7, "lc": 8}
+//func (g *GuangzhouTradeAnalysis) GetTradeDataByClassifyAndCompany(exchange string, classifyNames []string, contracts, queryCompanies []string, startDate, endDate time.Time) (items []*tradeAnalysisModel.OriginTradeData, err error) {
+//	classifyIdMap := map[string]int{"si": 7, "lc": 8}
+//
+//	// TODO:
+//	items = make([]*tradeAnalysisModel.OriginTradeData, 0)
+//	for _, classifyName := range classifyNames {
+//		classifyId := classifyIdMap[classifyName]
+//		if classifyId == 0 {
+//			err = fmt.Errorf("品种有误")
+//			return
+//		}
+//
+//		// TOP20
+//		seatNameArr := []string{tradeAnalysisModel.GuangZhouSeatNameBuy, tradeAnalysisModel.GuangZhouSeatNameSold}
+//		if utils.InArrayByStr(queryCompanies, tradeAnalysisModel.TradeFuturesCompanyTop20) {
+//			seatNameArr = append(seatNameArr, tradeAnalysisModel.GuangZhouTopSeatNameBuy, tradeAnalysisModel.GuangZhouTopSeatNameSold)
+//		}
+//
+//		// 查询品种下所有指标
+//		indexes, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouIndexByClassifyId(classifyId)
+//		if e != nil {
+//			err = fmt.Errorf("获取广期所指标失败, %v", e)
+//			return
+//		}
+//		var indexIds []int
+//		indexInfo := make(map[int]*tradeAnalysisModel.OriginTradeData)
+//		for _, v := range indexes {
+//			// eg.永安期货_si2401_持买单量
+//			nameArr := strings.Split(v.IndexName, "_")
+//			if len(nameArr) != 3 {
+//				continue
+//			}
+//			companyName := nameArr[0]
+//			if nameArr[0] == tradeAnalysisModel.GuangZhouTopCompanyAliasName {
+//				companyName = tradeAnalysisModel.TradeFuturesCompanyTop20
+//			}
+//			if !utils.InArrayByStr(seatNameArr, nameArr[2]) {
+//				continue
+//			}
+//			if !utils.InArrayByStr(queryCompanies, companyName) {
+//				continue
+//			}
+//			if !utils.InArrayByStr(contracts, nameArr[1]) {
+//				continue
+//			}
+//			indexIds = append(indexIds, v.BaseFromTradeGuangzhouIndexId)
+//			if indexInfo[v.BaseFromTradeGuangzhouIndexId] == nil {
+//				if tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]] == 0 {
+//					continue
+//				}
+//				indexInfo[v.BaseFromTradeGuangzhouIndexId] = new(tradeAnalysisModel.OriginTradeData)
+//				indexInfo[v.BaseFromTradeGuangzhouIndexId].CompanyName = companyName
+//				indexInfo[v.BaseFromTradeGuangzhouIndexId].ClassifyName = classifyName
+//				indexInfo[v.BaseFromTradeGuangzhouIndexId].ClassifyType = nameArr[1]
+//				indexInfo[v.BaseFromTradeGuangzhouIndexId].ValType = tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]]
+//			}
+//		}
+//		if len(indexIds) == 0 {
+//			continue
+//		}
+//
+//		// 查询指标数据
+//		indexesData, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouDataByIndexIds(indexIds)
+//		if e != nil {
+//			err = fmt.Errorf("获取广期所指标数据失败, %v", e)
+//			return
+//		}
+//		for _, v := range indexesData {
+//			info, ok := indexInfo[v.BaseFromTradeGuangzhouIndexId]
+//			if !ok {
+//				continue
+//			}
+//			items = append(items, &tradeAnalysisModel.OriginTradeData{
+//				CompanyName:  info.CompanyName,
+//				Val:          int(v.Value),
+//				ValChange:    int(v.QtySub),
+//				DataTime:     v.DataTime,
+//				ClassifyName: info.ClassifyName,
+//				ClassifyType: info.ClassifyType,
+//				ValType:      info.ValType,
+//			})
+//		}
+//	}
+//	return
+//}
 
-	// TODO:
-	items = make([]*tradeAnalysisModel.OriginTradeData, 0)
-	for _, classifyName := range classifyNames {
-		classifyId := classifyIdMap[classifyName]
-		if classifyId == 0 {
-			err = fmt.Errorf("品种有误")
-			return
-		}
+//func (g *GuangzhouTradeAnalysis) GetLastTradeDataByClassify(exchange string, classifyNames, contracts []string) (items []*tradeAnalysisModel.OriginTradeData, err error) {
+//	classifyIdMap := map[string]int{"si": 7, "lc": 8}
+//	for _, classifyName := range classifyNames {
+//		classifyId := classifyIdMap[classifyName]
+//		if classifyId == 0 {
+//			err = fmt.Errorf("品种有误")
+//			return
+//		}
+//		seatNameArr := []string{tradeAnalysisModel.GuangZhouSeatNameBuy, tradeAnalysisModel.GuangZhouSeatNameSold}
+//
+//		// 查询品种下所有指标
+//		indexes, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouIndexByClassifyId(classifyId)
+//		if e != nil {
+//			err = fmt.Errorf("获取广期所指标失败, %v", e)
+//			return
+//		}
+//
+//		// 获取各合约下的指标
+//		contractIndexIds := make(map[string][]int)
+//		for _, v := range indexes {
+//			// eg.永安期货_si2401_持买单量
+//			nameArr := strings.Split(v.IndexName, "_")
+//			if len(nameArr) != 3 {
+//				continue
+//			}
+//			if !utils.InArrayByStr(contracts, nameArr[1]) {
+//				continue
+//			}
+//			if !utils.InArrayByStr(seatNameArr, nameArr[2]) {
+//				continue
+//			}
+//			if tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]] == 0 {
+//				continue
+//			}
+//			k := fmt.Sprintf("%s-%d", nameArr[1], tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]])
+//			contractIndexIds[k] = append(contractIndexIds[k], v.BaseFromTradeGuangzhouIndexId)
+//		}
+//
+//		// ps.如果后面如果有空可以优化一下这里, 把末位数据每天写进一张表里面
+//		for k, v := range contractIndexIds {
+//			keyArr := strings.Split(k, "-")
+//			contract := keyArr[0]
+//			valType, _ := strconv.Atoi(keyArr[1])
+//			lastVales, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouMinDataByIndexIds(v)
+//			if e != nil {
+//				err = fmt.Errorf("获取合约末位数据失败, %v", e)
+//				return
+//			}
+//			for _, vv := range lastVales {
+//				items = append(items, &tradeAnalysisModel.OriginTradeData{
+//					Val:          int(vv.Value),
+//					DataTime:     vv.DataTime,
+//					ClassifyType: contract,
+//					ValType:      valType,
+//				})
+//			}
+//		}
+//	}
+//	return
+//}
+
+func (g *GuangzhouTradeAnalysis) GetTradeDataByContracts(exchange string, classifyNames, contracts, queryCompanies []string, startDate, endDate time.Time) (items, topItems, lastItems []*tradeAnalysisModel.OriginTradeData, err error) {
+	items, topItems, lastItems = make([]*tradeAnalysisModel.OriginTradeData, 0), make([]*tradeAnalysisModel.OriginTradeData, 0), make([]*tradeAnalysisModel.OriginTradeData, 0)
 
-		// TOP20
-		seatNameArr := []string{tradeAnalysisModel.GuangZhouSeatNameBuy, tradeAnalysisModel.GuangZhouSeatNameSold}
-		if utils.InArrayByStr(queryCompanies, tradeAnalysisModel.TradeFuturesCompanyTop20) {
-			seatNameArr = append(seatNameArr, tradeAnalysisModel.GuangZhouTopSeatNameBuy, tradeAnalysisModel.GuangZhouTopSeatNameSold)
+	// 取品种ID
+	classifyNameId := map[string]int{"si": 7, "lc": 8}
+	classifyIdName := map[int]string{7: "si", 8: "lc"}
+	var classifyIds []int
+	for _, v := range classifyNames {
+		if classifyNameId[v] > 0 {
+			classifyIds = append(classifyIds, classifyNameId[v])
 		}
+	}
 
-		// 查询品种下所有指标
-		indexes, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouIndexByClassifyId(classifyId)
-		if e != nil {
-			err = fmt.Errorf("获取广期所指标失败, %v", e)
-			return
+	// 查询指标
+	indexes, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouIndex(classifyIds, contracts, "")
+	if e != nil {
+		err = fmt.Errorf("获取广期所指标失败, %v", e)
+		return
+	}
+	var indexIds []int
+
+	// 过滤掉成交量,只取买单卖单
+	seatNameArr := []string{tradeAnalysisModel.GuangZhouSeatNameBuy, tradeAnalysisModel.GuangZhouSeatNameSold, tradeAnalysisModel.GuangZhouTopSeatNameBuy, tradeAnalysisModel.GuangZhouTopSeatNameSold}
+	//if utils.InArrayByStr(queryCompanies, tradeAnalysisModel.TradeFuturesCompanyTop20) {
+	//	seatNameArr = append(seatNameArr, tradeAnalysisModel.GuangZhouTopSeatNameBuy, tradeAnalysisModel.GuangZhouTopSeatNameSold)
+	//}
+	indexInfo := make(map[int]*tradeAnalysisModel.OriginTradeData)
+
+	// 查询公司中是否含TOP20
+	var hasTop bool
+	if utils.InArrayByStr(queryCompanies, tradeAnalysisModel.TradeFuturesCompanyTop20) {
+		hasTop = true
+	}
+	isTopIndex := make(map[int]bool)
+
+	//contractIndexIds := make(map[string][]int) // [合约+方向-指标ID]
+	//indexIdContract := make(map[int]string)    // [指标ID-合约_方向]
+	for _, v := range indexes {
+		// eg.永安期货_si2401_持买单量
+		nameArr := strings.Split(v.IndexName, "_")
+		if len(nameArr) != 3 {
+			continue
 		}
-		var indexIds []int
-		indexInfo := make(map[int]*tradeAnalysisModel.OriginTradeData)
-		for _, v := range indexes {
-			// eg.永安期货_si2401_持买单量
-			nameArr := strings.Split(v.IndexName, "_")
-			if len(nameArr) != 3 {
-				continue
-			}
-			companyName := nameArr[0]
-			if nameArr[0] == tradeAnalysisModel.GuangZhouTopCompanyAliasName {
-				companyName = tradeAnalysisModel.TradeFuturesCompanyTop20
-			}
-			if !utils.InArrayByStr(seatNameArr, nameArr[2]) {
-				continue
-			}
-			if !utils.InArrayByStr(queryCompanies, companyName) {
-				continue
-			}
-			if !utils.InArrayByStr(contracts, nameArr[1]) {
-				continue
-			}
-			indexIds = append(indexIds, v.BaseFromTradeGuangzhouIndexId)
-			if indexInfo[v.BaseFromTradeGuangzhouIndexId] == nil {
-				if tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]] == 0 {
-					continue
-				}
-				indexInfo[v.BaseFromTradeGuangzhouIndexId] = new(tradeAnalysisModel.OriginTradeData)
-				indexInfo[v.BaseFromTradeGuangzhouIndexId].CompanyName = companyName
-				indexInfo[v.BaseFromTradeGuangzhouIndexId].ClassifyName = classifyName
-				indexInfo[v.BaseFromTradeGuangzhouIndexId].ClassifyType = nameArr[1]
-				indexInfo[v.BaseFromTradeGuangzhouIndexId].ValType = tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]]
-			}
+		companyName := nameArr[0]
+		var isTop bool
+		if nameArr[0] == tradeAnalysisModel.GuangZhouTopCompanyAliasName {
+			isTop = true
+			isTopIndex[v.BaseFromTradeGuangzhouIndexId] = true
+			companyName = tradeAnalysisModel.TradeFuturesCompanyTop20
 		}
-		if len(indexIds) == 0 {
+		if !utils.InArrayByStr(seatNameArr, nameArr[2]) {
 			continue
 		}
-
-		// 查询指标数据
-		indexesData, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouDataByIndexIds(indexIds)
-		if e != nil {
-			err = fmt.Errorf("获取广期所指标数据失败, %v", e)
-			return
+		// 过滤掉非TOP20以及非查询公司
+		if !isTop && !utils.InArrayByStr(queryCompanies, companyName) {
+			continue
 		}
-		for _, v := range indexesData {
-			info, ok := indexInfo[v.BaseFromTradeGuangzhouIndexId]
-			if !ok {
+		indexIds = append(indexIds, v.BaseFromTradeGuangzhouIndexId)
+
+		// 指标信息
+		if indexInfo[v.BaseFromTradeGuangzhouIndexId] == nil {
+			contractType := tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]]
+			if contractType == 0 {
 				continue
 			}
-			items = append(items, &tradeAnalysisModel.OriginTradeData{
-				CompanyName:  info.CompanyName,
-				Val:          int(v.Value),
-				ValChange:    int(v.QtySub),
-				DataTime:     v.DataTime,
-				ClassifyName: info.ClassifyName,
-				ClassifyType: info.ClassifyType,
-				ValType:      info.ValType,
-			})
+			indexInfo[v.BaseFromTradeGuangzhouIndexId] = new(tradeAnalysisModel.OriginTradeData)
+			indexInfo[v.BaseFromTradeGuangzhouIndexId].CompanyName = companyName
+			indexInfo[v.BaseFromTradeGuangzhouIndexId].ClassifyName = classifyIdName[v.BaseFromTradeGuangzhouClassifyId]
+			indexInfo[v.BaseFromTradeGuangzhouIndexId].ClassifyType = nameArr[1]
+			indexInfo[v.BaseFromTradeGuangzhouIndexId].ValType = contractType
 		}
+
+		//k := fmt.Sprintf("%s-%d", nameArr[1], tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]])
+		//contractIndexIds[k] = append(contractIndexIds[k], v.BaseFromTradeGuangzhouIndexId)
+		//indexIdContract[v.BaseFromTradeGuangzhouIndexId] = k
+	}
+	if len(indexIds) == 0 {
+		return
 	}
-	return
-}
 
-func (g *GuangzhouTradeAnalysis) GetLastTradeDataByClassify(exchange string, classifyNames, contracts []string) (items []*tradeAnalysisModel.OriginTradeData, err error) {
-	classifyIdMap := map[string]int{"si": 7, "lc": 8}
-	for _, classifyName := range classifyNames {
-		classifyId := classifyIdMap[classifyName]
-		if classifyId == 0 {
-			err = fmt.Errorf("品种有误")
-			return
-		}
-		seatNameArr := []string{tradeAnalysisModel.GuangZhouSeatNameBuy, tradeAnalysisModel.GuangZhouSeatNameSold}
-
-		// 查询品种下所有指标
-		indexes, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouIndexByClassifyId(classifyId)
-		if e != nil {
-			err = fmt.Errorf("获取广期所指标失败, %v", e)
-			return
-		}
-
-		// 获取各合约下的指标
-		contractIndexIds := make(map[string][]int)
-		for _, v := range indexes {
-			// eg.永安期货_si2401_持买单量
-			nameArr := strings.Split(v.IndexName, "_")
-			if len(nameArr) != 3 {
-				continue
-			}
-			if !utils.InArrayByStr(contracts, nameArr[1]) {
-				continue
-			}
-			if !utils.InArrayByStr(seatNameArr, nameArr[2]) {
-				continue
-			}
-			if tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]] == 0 {
-				continue
-			}
-			k := fmt.Sprintf("%s-%d", nameArr[1], tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]])
-			contractIndexIds[k] = append(contractIndexIds[k], v.BaseFromTradeGuangzhouIndexId)
-		}
-
-		// ps.如果后面如果有空可以优化一下这里, 把末位数据每天写进一张表里面
-		for k, v := range contractIndexIds {
-			keyArr := strings.Split(k, "-")
-			contract := keyArr[0]
-			valType, _ := strconv.Atoi(keyArr[1])
-			lastVales, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouMinDataByIndexIds(v)
-			if e != nil {
-				err = fmt.Errorf("获取合约末位数据失败, %v", e)
-				return
-			}
-			for _, vv := range lastVales {
-				items = append(items, &tradeAnalysisModel.OriginTradeData{
-					Val:          int(vv.Value),
-					DataTime:     vv.DataTime,
-					ClassifyType: contract,
-					ValType:      valType,
-				})
+	// 查询指标数据
+	indexesData, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouDataByIndexIds(indexIds, startDate, endDate)
+	if e != nil {
+		err = fmt.Errorf("获取广期所指标数据失败, %v", e)
+		return
+	}
+	// 取出持仓数据、TOP20,比对末位数据
+	contractMinData := make(map[string]*tradeAnalysisModel.OriginTradeData) // 合约末位
+	for _, v := range indexesData {
+		info, ok := indexInfo[v.BaseFromTradeGuangzhouIndexId]
+		if !ok {
+			continue
+		}
+		t := &tradeAnalysisModel.OriginTradeData{
+			CompanyName:  info.CompanyName,
+			Val:          int(v.Value),
+			ValChange:    int(v.QtySub),
+			DataTime:     v.DataTime,
+			ClassifyName: info.ClassifyName,
+			ClassifyType: info.ClassifyType,
+			ValType:      info.ValType,
+		}
+
+		// 如果是TOP20的指标,查询公司中含有TOP20那么追加进items,否则仅追加进topItems, 且TOP20不参与末位数据的比对
+		if isTopIndex[v.BaseFromTradeGuangzhouIndexId] {
+			if hasTop {
+				items = append(items, t)
 			}
+			topItems = append(topItems, t)
+			continue
+		}
+		items = append(items, t)
+
+		// 比对末位数据
+		k := fmt.Sprintf("%s-%d", info.ClassifyType, info.ValType)
+		if contractMinData[k] == nil {
+			contractMinData[k] = t
+			continue
+		}
+		if t.Val < contractMinData[k].Val {
+			contractMinData[k] = t
 		}
 	}
+
+	// 末位数据
+	for _, v := range contractMinData {
+		lastItems = append(lastItems, v)
+	}
 	return
 }
 
-func (g *GuangzhouTradeAnalysis) GetContractTopRankData(exchange string, classifyNames []string, dataDate time.Time) (items []*tradeAnalysisModel.ContractTopRankData, err error) {
-	// TODO:
-	return tradeAnalysisModel.GetContractTopRankData(exchange, classifyNames, dataDate)
+func (g *GuangzhouTradeAnalysis) GetContractTopRankData(exchange string, classifyNames []string, dataTime time.Time) (items []*tradeAnalysisModel.ContractTopRankData, err error) {
+	items = make([]*tradeAnalysisModel.ContractTopRankData, 0)
+
+	// 取品种ID
+	classifyNameId := map[string]int{"si": 7, "lc": 8}
+	classifyIdName := map[int]string{7: "si", 8: "lc"}
+	var classifyIds []int
+	for _, v := range classifyNames {
+		if classifyNameId[v] > 0 {
+			classifyIds = append(classifyIds, classifyNameId[v])
+		}
+	}
+
+	// 查询TOP20指标
+	indexKeyword := fmt.Sprint("%", tradeAnalysisModel.GuangZhouTopCompanyAliasName, "%")
+	indexes, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouIndex(classifyIds, []string{}, indexKeyword)
+	if e != nil {
+		err = fmt.Errorf("获取广期所指标失败, %v", e)
+		return
+	}
+	var indexIds []int
+
+	indexIdContract := make(map[int]string)                                      // [指标ID-合约_方向]
+	contractRankData := make(map[string]*tradeAnalysisModel.ContractTopRankData) // [合约-合约TOP数据]
+	for _, v := range indexes {
+		// eg.永安期货_si2401_持买单量
+		nameArr := strings.Split(v.IndexName, "_")
+		if len(nameArr) != 3 {
+			continue
+		}
+		contractCode := nameArr[1]
+		indexIds = append(indexIds, v.BaseFromTradeGuangzhouIndexId)
+
+		// 指标对应的[合约+方向]
+		k := fmt.Sprintf("%s_%d", contractCode, tradeAnalysisModel.GuangzhouSeatNameValType[nameArr[2]])
+		indexIdContract[v.BaseFromTradeGuangzhouIndexId] = k
+
+		// 合约对应的数据
+		if contractRankData[contractCode] == nil {
+			contractRankData[contractCode] = new(tradeAnalysisModel.ContractTopRankData)
+			contractRankData[contractCode].Exchange = exchange
+			contractRankData[contractCode].ClassifyName = classifyIdName[v.BaseFromTradeGuangzhouClassifyId]
+			contractRankData[contractCode].ClassifyType = contractCode
+			contractRankData[contractCode].DataTime = dataTime
+		}
+	}
+	if len(indexIds) == 0 {
+		return
+	}
+
+	// 查询指标数据
+	indexesData, e := tradeAnalysisModel.GetBaseFromTradeGuangzhouDataByIndexIds(indexIds, dataTime, dataTime)
+	if e != nil {
+		err = fmt.Errorf("获取广期所指标数据失败, %v", e)
+		return
+	}
+	for _, v := range indexesData {
+		k := indexIdContract[v.BaseFromTradeGuangzhouIndexId]
+		if k == "" {
+			continue
+		}
+		nameArr := strings.Split(k, "_")
+		if len(nameArr) != 2 {
+			continue
+		}
+		contractCode := nameArr[0]
+		if contractRankData[contractCode] == nil {
+			continue
+		}
+
+		// 根据方向赋值:1-多单;2-空单;3-成交量
+		switch nameArr[1] {
+		case "1":
+			contractRankData[contractCode].BuyValue = int(v.Value)
+		case "2":
+			contractRankData[contractCode].SoldValue = int(v.Value)
+		case "3":
+			contractRankData[contractCode].DealValue = int(v.Value)
+		default:
+			continue
+		}
+	}
+
+	// 根据成交量排序并返回排名数据
+	for _, v := range contractRankData {
+		items = append(items, v)
+	}
+	sort.Slice(items, func(i, j int) bool {
+		return items[i].DealValue > items[j].DealValue
+	})
+	return
 }

+ 3 - 3
services/data/trade_analysis/trade_analysis_table.go

@@ -137,8 +137,8 @@ func CalculateTableRowData(exchange string, baseDate time.Time, topData []*trade
 		row.BuySoldRatio = math.Round(float64(cd.BuyVal)/float64(cd.BuyVal+cd.SoldVal)*100) / 100
 		row.BuyTopRatio = math.Round(float64(cd.BuyVal)/float64(td.BuyValue)*100) / 100
 		row.SoldTopRatio = math.Round(float64(cd.SoldVal)/float64(td.SoldValue)*100) / 100
-		row.TopPureBuy = td.PureBuyValue
-		row.TopPureBuyChange = td.PureBuyChange
+		row.TopPureBuy = td.BuyValue - td.SoldValue
+		row.TopPureBuyChange = int(math.Abs(float64(td.BuyChange))) + int(math.Abs(float64(td.SoldChange))) // 净多变化=Abs(多单变化)+Abs(空单变化)
 		row.TopBuySoldRatio = math.Round(float64(td.BuyValue)/float64(td.BuyValue+td.SoldValue)*100) / 100
 		rows = append(rows, row)
 	}
@@ -206,7 +206,7 @@ func GetTableRowsDataByConfig(tableConfig tradeAnalysisModel.TableExtraConfig) (
 			}
 		}
 
-		contractRowData, e := GetTableTradeData(exchange, classifyNames, classifyTypes, []string{tableConfig.CompanyName}, tableConfig.PredictRatio, baseDate, tableConfig.ContractType)
+		contractRowData, e := GetTableTradeData(exchange, classifyNames, classifyTypes, []string{tableConfig.CompanyName}, tableConfig.PredictRatio, baseDate.AddDate(0, 0, -5), baseDate.AddDate(0, 0, 5), tableConfig.ContractType)
 		if e != nil {
 			err = fmt.Errorf("获取公司合约多空单数据失败, %v", e)
 			return