Browse Source

持仓分析

xiexiaoyuan 2 years ago
parent
commit
9faa576fbe

+ 46 - 0
controller/trade_analysis/trade_analysis.go

@@ -0,0 +1,46 @@
+package trade_analysis
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/response"
+	model "hongze/hongze_yb/models/tables/trade_analysis"
+	"hongze/hongze_yb/services/trade_analysis"
+)
+
+// GetClassifyName 获取交易所合约列表
+func GetClassifyName(c *gin.Context) {
+	//userinfo := userService.GetInfoByClaims(c)
+	list, err, errMsg := trade_analysis.GetClassifyName()
+	if err !=nil {
+		response.FailMsg(errMsg, err.Error(), c)
+		return
+	}
+
+	response.OkData("获取成功", list, c)
+}
+
+// GetPositionTop 获取合约榜单详情
+func GetPositionTop(c *gin.Context) {
+	var req model.GetPositionTopReq
+	if err := c.Bind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.ClassifyName == "" {
+		response.Fail("请输入分类名称", c)
+		return
+	}
+	if req.ClassifyType == "" {
+		response.Fail("请输入合约名称", c)
+		return
+	}
+
+	//userinfo := userService.GetInfoByClaims(c)
+	list, err, errMsg := trade_analysis.GetPositionTopDetail(req)
+	if err !=nil {
+		response.FailMsg(errMsg, err.Error(), c)
+		return
+	}
+
+	response.OkData("获取成功", list, c)
+}

+ 2 - 0
init_serve/router.go

@@ -79,5 +79,7 @@ func InitRouter() (r *gin.Engine) {
 	routers.InitBulletChat(r)
 	// 我的图表
 	routers.InitMyChart(r)
+	// 持仓分析
+	routers.InitTradeAnalysis(r)
 	return
 }

+ 121 - 0
models/tables/trade_analysis/trade_analysis.go

@@ -0,0 +1,121 @@
+package trade_analysis
+
+import (
+	"hongze/hongze_yb/global"
+	"time"
+)
+
+// TradePositionAnalysis 持仓数据汇总表
+type TradePositionAnalysis struct {
+	Id            uint64    `orm:"column(id);pk"`
+	ClassifyName  string    //分类名称
+	ClassifyType  string    //分类名称下的类型
+	DealShortName string    //成交量公司简称
+	DealValue     int    //成交量
+	DealChange    int    //成交变化量
+	DataTime      string    //数据日期
+	CreateTime    time.Time //插入时间
+	ModifyTime    time.Time //修改时间
+	DealType      int      //交易类型:1多单,2空单,3净多单,4净空单
+}
+
+
+// 持仓榜单表
+type TradePositionTop struct {
+	Id            uint64    `orm:"column(id);pk"`
+	ClassifyName  string    //分类名称
+	ClassifyType  string    //分类名称下的类型
+	DataTime      string    //数据日期
+	CreateTime    time.Time //插入时间
+	ModifyTime    time.Time //修改时间
+	DealShortName string    //成交量公司简称
+	DealValue     int    //成交量
+	DealChange    int    //成交变化量
+	DealType      int       //交易类型:1多单,2空单,3净多单,4净空单
+	AnalysisId    uint64    //持仓数据
+}
+
+type TradeClassifyNameList struct {
+	Exchange string                      `description:"交易所" json:"exchange"`
+	Items    []TradeClassifyNameListItem `description:"子类" json:"items"`
+}
+
+type TradeClassifyNameListItem struct {
+	ClassifyName string                          `description:"交易分类" json:"classify_name"`
+	Items        []TradeClassifyNameListItemItem `description:"合约代码" json:"items"`
+}
+
+type TradeClassifyNameListItemItem struct {
+	ClassifyType string `json:"classify_type"` //分类名称下的类型
+	Sort         int    `json:"sort"`
+}
+
+type TradeClassifyName struct {
+	ClassifyName  string    //分类名称
+	ClassifyType  string    //分类名称下的类型
+}
+
+func GetExchangeClassify(exchange string) (list []TradeClassifyName, err error) {
+	tableName := "base_from_trade_" + exchange + "_index"
+	orderStr := "CONVERT(classify_name using gbk) DESC, classify_type asc"
+	if exchange == "zhengzhou"{
+		orderStr = "classify_name asc"
+	}
+	err = global.MYSQL["data"].
+		Table(tableName).
+		Select("classify_name, classify_type").
+		Group("classify_name, classify_type").
+		Order(orderStr).Scan(&list).Error
+	return
+}
+
+type GetPositionTopReq struct {
+	Exchange     string `json:"exchange" form:"exchange"`      //交易所
+	ClassifyName string `json:"classify_name" form:"classify_name"` //分类名称
+	ClassifyType string `json:"classify_type" form:"classify_type"`  //具体合约名称
+	DataTime     string `json:"data_time" form:"data_time"`     //请求日期,如果为空,则返回最新的榜单日期
+}
+
+type GetPositionTopResp struct {
+	BuyList       GetPositionTopList `json:"buy_list"`        //多单列表
+	SoldList      GetPositionTopList `json:"sold_list"`       //空单列表
+	CleanBuyList  GetPositionTopList `json:"clean_buy_list"`  //净多单列表
+	CleanSoldList GetPositionTopList `json:"clean_sold_list"` //净空单列表
+	DataTime      string             `json:"data_time"`       //最新日期或者请求日期
+}
+
+type GetPositionTopList struct {
+	TotalDealValue  int                      `json:"total_deal_value"` //总计成交量
+	TotalDealChange int                      `json:"total_deal_change"` //校昨日变化
+	List            []GetPositionTopListItem `json:"list"`  //榜单详情列表
+}
+
+type GetPositionTopListItem struct {
+	DealShortName   string `json:"deal_short_name"`   //成交量公司简称
+	DealValue       int    `json:"deal_value"`        //成交量
+	DealChange      int    `json:"deal_change"`       //成交变化量
+	Rank            int    `json:"rank"`              //当前名次
+	Rate            string `json:"rate"`              //当前占比
+	BeforeAllRate   string `json:"before_all_rate"`   //排在前面的成交量总计占比(包含)
+	BeforeAllValue  int    `json:"before_all_value"`  //排在前面的成交量总计
+	BeforeAllChange int    `json:"before_all_change"` //排在前面的成交量增减总计
+}
+
+func GetTradePositionTop(exchange string, classifyName, classifyType, dataTime string)(list []TradePositionTop, err error) {
+	tableName := "trade_position_" + exchange + "_top"
+	err = global.MYSQL["data"].
+		Table(tableName).
+		Where("classify_name=? and classify_type=? and data_time=? ", classifyName, classifyType, dataTime).
+		Order("deal_value desc").Scan(&list).Error
+	return
+}
+
+func GetTradeTopLastDataTime(exchange string, classifyName, classifyType string)(item TradePositionTop, err error) {
+	tableName := "trade_position_" + exchange + "_top"
+	err = global.MYSQL["data"].
+		Table(tableName).
+		Where("classify_name=? and classify_type=?", classifyName, classifyType).
+		Order("data_time desc").First(&item).Error
+	return
+}
+

+ 15 - 0
routers/trade_analysis.go

@@ -0,0 +1,15 @@
+package routers
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/trade_analysis"
+	"hongze/hongze_yb/middleware"
+)
+
+func InitTradeAnalysis(r *gin.Engine) {
+	rGroup := r.Group("api/trade/analysis").Use(middleware.Token())
+	{
+		rGroup.GET("/classify", trade_analysis.GetClassifyName)
+		rGroup.GET("/top", trade_analysis.GetPositionTop)
+	}
+}

+ 289 - 0
services/trade_analysis/trade_analysis.go

@@ -0,0 +1,289 @@
+package trade_analysis
+
+import (
+	"fmt"
+	"hongze/hongze_yb/models/tables/trade_analysis"
+	"hongze/hongze_yb/utils"
+	"strings"
+	"time"
+)
+
+func GetClassifyName() (list []trade_analysis.TradeClassifyNameList, err error, errMsg string) {
+	//定义交易所
+	exchanges := map[string]string{
+		"zhengzhou": "郑商所",
+		"dalian":    "大商所",
+		"shanghai":  "上期所",
+		"cffex":     "中金所",
+		"ine":       "上期能源",
+	}
+	//查询每个交易所下的classifyNameList
+	list = make([]trade_analysis.TradeClassifyNameList, 0)
+	i := 0
+	for k, v := range exchanges {
+		tmp := trade_analysis.TradeClassifyNameList{
+			Exchange: v,
+			Items:    nil,
+		}
+		nameList, tmpErr := trade_analysis.GetExchangeClassify(k)
+		if tmpErr != nil {
+			err = tmpErr
+			errMsg = "查询交易所分类信息失败"
+			return
+		}
+		classifyMap := make(map[string][]trade_analysis.TradeClassifyNameListItemItem)
+		if len(nameList) > 0 {
+			if k == "zhengzhou" {
+				for j, item := range nameList {
+					classifyName := getZhengzhouClassifyName(item.ClassifyName)
+					tmpItemItem := trade_analysis.TradeClassifyNameListItemItem{
+						ClassifyType: item.ClassifyName,
+						Sort: j+1000*i,
+					}
+					classifyMap[classifyName] = append(classifyMap[classifyName], tmpItemItem)
+				}
+			}else{
+				for j, item := range nameList {
+					tmpItemItem := trade_analysis.TradeClassifyNameListItemItem{
+						ClassifyType: item.ClassifyType,
+						Sort: j+1000*i,
+					}
+					classifyMap[item.ClassifyName] = append(classifyMap[item.ClassifyName], tmpItemItem)
+				}
+			}
+			for n, l := range classifyMap {
+				tmpItems := trade_analysis.TradeClassifyNameListItem{
+					ClassifyName: n,
+					Items:        l,
+				}
+				tmp.Items = append(tmp.Items, tmpItems)
+			}
+		}
+		list = append(list, tmp)
+		i ++
+	}
+	return
+}
+
+func getZhengzhouClassifyName(code string) (name string) {
+	if strings.HasPrefix(code,"TA") {
+		name = "PTA"
+		return
+	}
+	if strings.HasPrefix(code,"ZC") {
+		name="动力煤"
+		return
+	}
+	if strings.HasPrefix(code,"WH") {
+		name="强麦"
+		return
+	}
+	if strings.HasPrefix(code,"UR") {
+		name="尿素"
+		return
+	}
+	if strings.HasPrefix(code,"SR") {
+		name="白糖"
+		return
+	}
+	if strings.HasPrefix(code,"SM") {
+		name="锰硅"
+		return
+	}
+	if strings.HasPrefix(code,"SF") {
+		name="硅铁"
+		return
+	}
+	if strings.HasPrefix(code,"SA") {
+		name="纯碱"
+		return
+	}
+	if strings.HasPrefix(code,"RS") {
+		name="油菜籽"
+		return
+	}
+	if strings.HasPrefix(code,"RM") {
+		name="菜籽粕"
+		return
+	}
+	if strings.HasPrefix(code,"RI") {
+		name="早籼稻"
+		return
+	}
+	if strings.HasPrefix(code,"PM") {
+		name="普麦"
+		return
+	}
+	if strings.HasPrefix(code,"PK") {
+		name="花生"
+		return
+	}
+	if strings.HasPrefix(code,"PF") {
+		name="涤纶短纤"
+		return
+	}
+	if strings.HasPrefix(code,"OI") {
+		name="菜油"
+		return
+	}
+	if strings.HasPrefix(code,"MA") {
+		name="甲醇"
+		return
+	}
+	if strings.HasPrefix(code,"LR") {
+		name="晚籼稻"
+		return
+	}
+	if strings.HasPrefix(code,"JR") {
+		name="粳稻"
+		return
+	}
+	if strings.HasPrefix(code,"FG") {
+		name="玻璃"
+		return
+	}
+	if strings.HasPrefix(code,"CY") {
+		name="棉纱"
+		return
+	}
+	if strings.HasPrefix(code,"CJ") {
+		name="红枣"
+		return
+	}
+	if strings.HasPrefix(code,"CF") {
+		name="棉花"
+		return
+	}
+	if strings.HasPrefix(code,"AP") {
+		name="苹果"
+		return
+	}
+	return
+}
+
+func GetPositionTopDetail(req trade_analysis.GetPositionTopReq) (ret trade_analysis.GetPositionTopResp, err error, errMsg string) {
+	//定义交易所
+	exchanges := map[string]string{
+		"郑商所":"zhengzhou",
+		"大商所":"dalian",
+		"上期所":"shanghai",
+		"中金所":"cffex",
+		"上期能源":"ine",
+	}
+	exchange, ok := exchanges[req.Exchange]
+	if !ok {
+		errMsg = "请输入正确的交易所名称"
+		err = fmt.Errorf(errMsg)
+		return
+	}
+	dataTimeStr := req.DataTime
+	//查询最新的时间
+	if dataTimeStr == "" {
+		lastItem , tmpErr := trade_analysis.GetTradeTopLastDataTime(exchange, req.ClassifyName, req.ClassifyType)
+		if tmpErr != nil {
+			errMsg = "查询最新的榜单信息失败"
+			err = tmpErr
+			return
+		}
+		dataTimeStr = lastItem.DataTime
+	}
+	dataTime, err := time.ParseInLocation(utils.FormatDate, dataTimeStr, time.Local)
+	if err != nil {
+		errMsg = "请输入正确的时间格式"
+		return
+	}
+	//遇到周末则跳过当天
+	weekStr := dataTime.Weekday().String()
+	if weekStr == "Sunday" || weekStr == "Saturday" {
+		errMsg = "日期不正确"
+		err = fmt.Errorf(errMsg)
+		return
+	}
+	dataTimeStr = dataTime.Format(utils.FormatDate)
+	//查询当日榜单列表
+	dataList, tmpErr := trade_analysis.GetTradePositionTop(exchange, req.ClassifyName, req.ClassifyType, dataTimeStr)
+	if tmpErr != nil {
+		errMsg = "查询榜单列表失败"
+		err = tmpErr
+		return
+	}
+	if len(dataList) <= 0 {
+		return
+	}
+	totalMap := make(map[int]int)
+	totalChangeMap := make(map[int]int)
+	totalTmpMap := make(map[int]int)
+	totalChangeTmpMap := make(map[int]int)
+
+	detailList := make(map[int][]trade_analysis.GetPositionTopListItem)
+	//统计汇总数据
+	for _, v := range dataList {
+		if t, ok1 := totalMap[v.DealType]; ok1 {
+			totalMap[v.DealType] = t+v.DealValue
+		}else{
+			totalMap[v.DealType] = v.DealValue
+		}
+		if t, ok1 := totalChangeMap[v.DealType]; ok1 {
+			totalChangeMap[v.DealType] = t+v.DealChange
+		}else{
+			totalChangeMap[v.DealType] = v.DealChange
+		}
+	}
+	_, okTmp1 := totalMap[1]
+	_, okTmp2 := totalMap[2]
+	_, okTmp3 := totalMap[3]
+	_, okTmp4 := totalMap[4]
+
+	if !okTmp1 || !okTmp2 || !okTmp3 || !okTmp4 {
+		errMsg = "榜单数据缺失"
+		err = fmt.Errorf(errMsg)
+		return
+	}
+
+	for k, v := range dataList {
+		k++
+		if t, ok1 := totalTmpMap[v.DealType]; ok1 {
+			totalTmpMap[v.DealType] = t+v.DealValue
+		}else{
+			totalTmpMap[v.DealType] = v.DealValue
+		}
+		if t, ok1 := totalChangeTmpMap[v.DealType]; ok1 {
+			totalChangeTmpMap[v.DealType] = t+v.DealChange
+		}else{
+			totalChangeTmpMap[v.DealType] = v.DealChange
+		}
+
+		tmp := trade_analysis.GetPositionTopListItem{
+			DealShortName:   v.DealShortName,
+			DealValue:       v.DealValue,
+			DealChange:      v.DealChange,
+			Rank:            k,
+			BeforeAllValue:  totalTmpMap[v.DealType],
+			BeforeAllChange: totalChangeTmpMap[v.DealType],
+		}
+		//统计占比
+		rate := fmt.Sprintf("%.2f", float64(tmp.DealValue)/float64(totalMap[v.DealType])) // 保留2位小数
+		beforeAllRate := fmt.Sprintf("%.2f", float64(tmp.BeforeAllValue)/float64(totalMap[v.DealType])) // 保留2位小数
+		tmp.Rate = rate
+		tmp.BeforeAllRate = beforeAllRate
+		detailList[v.DealType] = append(detailList[v.DealType], tmp)
+	}
+	ret.BuyList.TotalDealValue = totalMap[1]
+	ret.BuyList.TotalDealChange = totalChangeMap[1]
+	ret.BuyList.List = detailList[1]
+
+	ret.SoldList.TotalDealValue = totalMap[2]
+	ret.SoldList.TotalDealChange = totalChangeMap[2]
+	ret.SoldList.List = detailList[2]
+
+	ret.CleanBuyList.TotalDealValue = totalMap[3]
+	ret.CleanBuyList.TotalDealChange = totalChangeMap[3]
+	ret.CleanBuyList.List = detailList[3]
+
+	ret.CleanSoldList.TotalDealValue = totalMap[4]
+	ret.CleanSoldList.TotalDealChange = totalChangeMap[4]
+	ret.CleanSoldList.List = detailList[4]
+
+	ret.DataTime = dataTimeStr
+	return
+}