Browse Source

Merge branch 'chart/14.2'

Roc 1 year ago
parent
commit
35331cc4eb

+ 80 - 0
controllers/future_good/future_good_edb_info.go

@@ -2,11 +2,14 @@ package future_good
 
 import (
 	"encoding/json"
+	"fmt"
 	"hongze/hongze_edb_lib/controllers"
+	"hongze/hongze_edb_lib/logic"
 	"hongze/hongze_edb_lib/models"
 	"hongze/hongze_edb_lib/models/future_good"
 	"hongze/hongze_edb_lib/services"
 	"hongze/hongze_edb_lib/utils"
+	"strings"
 	"time"
 )
 
@@ -192,6 +195,83 @@ func (this *FutureGoodEdbInfoController) Refresh() {
 	br.Msg = "获取成功"
 }
 
+// RefreshRelation
+// @Title 刷新商品期货指标相关的接口
+// @Description 刷新商品期货指标相关的接口
+// @Success 200 {object} models.RefreshEdbInfoReq
+// @router /relation/refresh [post]
+func (this *FutureGoodEdbInfoController) RefreshRelation() {
+	br := new(models.BaseResponse).Init()
+	var cacheKey string
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req future_good.RefreshFutureEdbEdbInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.FutureGoodEdbInfoId <= 0 {
+		br.Msg = "请输入指标ID!"
+		br.ErrMsg = "请输入指标ID"
+		return
+	}
+	cacheKey = utils.CACHE_EDB_DATA_REFRESH + "_futuregood_relation_" + req.FutureGoodEdbCode
+
+	if utils.Rc.IsExist(cacheKey) {
+		br.Ret = 501
+		br.Success = true
+		br.Msg = "系统处理中,请稍后重试"
+		return
+	}
+
+	utils.Rc.SetNX(cacheKey, 1, 1*time.Minute)
+	defer func() {
+		utils.Rc.Delete(cacheKey)
+	}()
+
+	//获取指标信息
+	futureGoodEdbInfo, err := future_good.GetFutureGoodEdbInfo(req.FutureGoodEdbInfoId)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			br.Msg = "系统内找不到该指标"
+		} else {
+			br.Msg = "刷新失败"
+			br.ErrMsg = "添加失败,ERR:" + err.Error()
+		}
+		return
+	}
+
+	// 获取相关图表
+	list, err := models.GetGroupChartEdbMappingListByEdbInfoId(futureGoodEdbInfo.FutureGoodEdbInfoId, 2)
+	if err != nil {
+		br.Msg = "查找相关图表id失败"
+		br.ErrMsg = "添加失败,ERR:" + err.Error()
+		return
+	}
+
+	errMsgList := make([]string, 0)
+	for _, v := range list {
+		err, errMsg := logic.RefreshByChartId(v.ChartInfoId)
+		if err != nil {
+			errMsgList = append(errMsgList, fmt.Sprint(v.ChartInfoId, "更新失败,"+errMsg))
+		}
+	}
+
+	if len(errMsgList) > 0 {
+		br.Msg = "部分刷新失败"
+		br.ErrMsg = "部分刷新失败,Err:" + strings.Join(errMsgList, ";")
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "刷新成功"
+}
+
 //func init() {
 //
 //	list, err := future_good.GetFutureGoodEdbInfoList(" AND start_date = '0000-00-00' ", []interface{}{})

+ 852 - 0
logic/profit_chart_info.go

@@ -0,0 +1,852 @@
+package logic
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/shopspring/decimal"
+	"github.com/yidane/formula"
+	"hongze/hongze_edb_lib/models"
+	"hongze/hongze_edb_lib/models/future_good"
+	"hongze/hongze_edb_lib/utils"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// ChartInfoDateReq 图表的日期数据(日期相关)
+type ChartInfoDateReq struct {
+	Type  int    `description:"配置类型"`
+	Date  string `description:"固定日期"`
+	Value int    `description:"N天的值"`
+	Color string `description:"颜色"`
+	Name  string `description:"别名"`
+}
+
+// SectionScatterReq 截面散点请求
+type SectionScatterReq struct {
+	XName       string `description:"x轴名称"`
+	XNameEn     string `description:"x轴名称(英文)"`
+	XUnitName   string `description:"x轴单位名称"`
+	XUnitNameEn string `description:"x轴单位名称(英文)"`
+	YName       string `description:"y轴名称"`
+	YNameEn     string `description:"y轴名称(英文)"`
+	YUnitName   string `description:"y轴单位名称"`
+	YUnitNameEn string `description:"y轴单位名称(英文)"`
+	XMinValue   string `description:"X轴的最小值"`
+	XMaxValue   string `description:"X轴的最大值"`
+	YMinValue   string `description:"Y轴的最小值"`
+	YMaxValue   string `description:"Y轴的最大值"`
+	//EdbList     []SectionScatterEdbItemReq    `description:"指标数据"`
+	SeriesList []SectionScatterSeriesItemReq `description:"系列数据"`
+}
+
+// SectionScatterSeriesItemReq 系列的请求
+type SectionScatterSeriesItemReq struct {
+	Name            string `description:"系列名"`
+	NameEn          string `description:"系列名(英文名)"`
+	Color           string `description:"颜色"`
+	EdbInfoList     []SectionScatterEdbItemReq
+	ShowTrendLine   bool `description:"是否展示趋势线"`
+	ShowFitEquation bool `description:"是否展示方程式"`
+	ShowRSquare     bool `description:"是否展示R平方"`
+}
+
+// SectionScatterEdbItemReq 截面散点请求的指标
+type SectionScatterEdbItemReq struct {
+	XEdbInfoId int    `description:"X轴的指标ID"`
+	YEdbInfoId int    `description:"Y轴的指标ID"`
+	Name       string `description:"别名"`
+	NameEn     string `description:"英文别名"`
+	XDateType  int    `description:"X轴的日期配置类型"`
+	XDate      string `description:"X轴的日期固定日期"`
+	XDateValue int    `description:"X轴的日期N天的值"`
+	YDateType  int    `description:"Y轴的日期配置类型"`
+	YDate      string `description:"Y轴的日期固定日期"`
+	YDateValue int    `description:"Y轴的日期N天的值"`
+	IsShow     bool   `description:"是否展示"`
+}
+
+// XData 商品价格曲线的的x轴数据
+type XData struct {
+	Name   string `description:"别名"`
+	NameEn string `description:"英文别名"`
+}
+
+// YData 柱方图的y轴数据
+type YData struct {
+	Date           string          `description:"数据日期"`
+	ConfigDate     time.Time       `description:"配置的日期" json:"-"`
+	Color          string          `description:"数据颜色"`
+	Name           string          `description:"别名"`
+	NameEn         string          `description:"英文别名"`
+	Value          []float64       `description:"每个指标的值"`
+	NoDataEdbList  []int           `description:"没有数据的指标列表"`
+	XEdbInfoIdList []int           `description:"对应X轴的指标id列表"`
+	NameList       []string        `description:"每个值对应的名称"`
+	EnNameList     []string        `description:"每个值对应的英文名称"`
+	EdbValMap      map[int]float64 `description:"指标与值的对应" json:"-"`
+	M              []int           `description:"对应开始日期的间隔值" json:"-"`
+}
+
+// BarChartInfoEdbItemReq 柱方图预览请求数据(指标相关)
+type BarChartInfoEdbItemReq struct {
+	EdbInfoId int    `description:"指标ID"`
+	Name      string `description:"别名"`
+	NameEn    string `description:"英文别名"`
+	Source    int    `description:"1:ETA图库;2:商品价格"`
+}
+
+// ChartInfoReq 图表预览请求数据
+type ChartInfoReq struct {
+	FutureGoodEdbInfoIdList []models.EdbInfoFromTag `description:"指标信息"`
+	CalculateFormula        string                  `description:"计算公式"`
+	BaseEdbInfoId           int                     `description:"基础的指标id"`
+	DateList                []ChartInfoDateReq      `description:"日期配置"`
+	ProfitNameEn            string                  `description:"利润英文名称"`
+}
+
+// RefreshByChartId 根据图表id刷新图表
+func RefreshByChartId(chartInfoId int) (err error, errMsg string) {
+	// 查找图表
+	chartInfo, err := models.GetChartInfoById(chartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			err = nil
+		}
+		return
+	}
+	if chartInfo.Source != utils.CHART_SOURCE_FUTURE_GOOD_PROFIT {
+		return
+	}
+	var extraConf ChartInfoReq
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &extraConf)
+	if err != nil {
+		errMsg = "商品利润曲线图配置异常"
+		return
+	}
+
+	// 查找商品利润图表的扩展信息
+	chartInfoFutureGoodProfit := new(future_good.ChartInfoFutureGoodProfit)
+	if err = chartInfoFutureGoodProfit.GetItemById(chartInfoId); err != nil {
+		errMsg = "获取失败"
+		if err.Error() == utils.ErrNoRow() {
+			err = nil
+		}
+		return
+	}
+
+	baseEdbInfo, err := models.GetEdbInfoById(extraConf.BaseEdbInfoId)
+	if err != nil {
+		errMsg = "获取失败"
+		return
+	}
+	// 商品数据库指标
+	futureGoodEdbInfoMap := make(map[int]*future_good.FutureGoodEdbInfo)
+	zlFutureGoodEdbInfoList := make([]*future_good.FutureGoodEdbInfo, 0)
+	for _, v := range extraConf.FutureGoodEdbInfoIdList {
+		if _, ok := futureGoodEdbInfoMap[v.EdbInfoId]; ok {
+			continue
+		}
+
+		zlFutureGoodEdbInfo, tmpErr := future_good.GetFutureGoodEdbInfo(v.EdbInfoId)
+		if tmpErr != nil {
+			err = tmpErr
+			errMsg = "获取失败"
+			return
+		}
+
+		futureGoodEdbInfoMap[v.EdbInfoId] = zlFutureGoodEdbInfo
+		zlFutureGoodEdbInfoList = append(zlFutureGoodEdbInfoList, zlFutureGoodEdbInfo)
+	}
+
+	xDataList, yDataList, err := GetProfitChartEdbData(baseEdbInfo, zlFutureGoodEdbInfoList, extraConf.DateList, extraConf.CalculateFormula, extraConf.FutureGoodEdbInfoIdList)
+
+	xDataListByte, err := json.Marshal(xDataList)
+	if err != nil {
+		errMsg = "保存失败"
+		err = errors.New("X轴数据转换失败,ERR:" + err.Error())
+		return
+	}
+	yDataListByte, err := json.Marshal(yDataList)
+	if err != nil {
+		errMsg = "保存失败"
+		err = errors.New("Y轴数据转换失败,ERR:" + err.Error())
+		return
+	}
+
+	extraUpdateCol := make([]string, 0)
+	chartInfoFutureGoodProfit.XValue = string(xDataListByte)
+	chartInfoFutureGoodProfit.YValue = string(yDataListByte)
+	chartInfoFutureGoodProfit.ProfitName = zlFutureGoodEdbInfoList[0].FutureGoodEdbName + "盘面利润"
+	chartInfoFutureGoodProfit.ModifyTime = time.Now()
+	extraUpdateCol = []string{"XValue", "YValue", "ProfitName", "ModifyTime"}
+	err = chartInfoFutureGoodProfit.Update(extraUpdateCol)
+
+	return
+}
+
+// GetProfitChartEdbData 获取利润图表的指标数据
+func GetProfitChartEdbData(baseEdbInfo *models.EdbInfo, zlFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, chartInfoDateList []ChartInfoDateReq, formulaStr string, edbInfoFromTagList []models.EdbInfoFromTag) (xDataList []XData, yDataList []YData, err error) {
+	if baseEdbInfo == nil {
+		err = errors.New("ETA指标未选取")
+		return
+	}
+	if len(zlFutureGoodEdbInfoList) <= 0 {
+		err = errors.New("商品指标未选取")
+		return
+	}
+
+	// 标签与期货商品指标的关联关系
+	tagEdbIdMap := make(map[string]int)
+	// 有效的期货商品指标
+	futureGoodEdbInfoIdMap := make(map[int]int)
+	{
+		tmpTagEdbIdMap := make(map[string]int)
+		for _, v := range edbInfoFromTagList {
+			tmpTagEdbIdMap[v.FromTag] = v.EdbInfoId
+		}
+		formulaMap := CheckFormula(formulaStr)
+		for _, tag := range formulaMap {
+			tagEdbIdMap[tag] = tmpTagEdbIdMap[tag]
+			futureGoodEdbInfoIdMap[tmpTagEdbIdMap[tag]] = tmpTagEdbIdMap[tag]
+		}
+	}
+
+	// 普通的指标数据
+	baseDataList := make([]*models.EdbDataList, 0)
+	baseDataList, err = models.GetEdbDataList(baseEdbInfo.Source, baseEdbInfo.EdbInfoId, "", "")
+	if err != nil {
+		return
+	}
+
+	latestDate := zlFutureGoodEdbInfoList[0].EndDate
+	latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local)
+
+	earliestDateTime := latestDateTime // 数据的最早日期,目的是为了找出最早的合约
+	for _, barChartInfoDate := range chartInfoDateList {
+		var findDateTime time.Time
+		switch barChartInfoDate.Type {
+		case 1: //最新值
+			findDateTime = latestDateTime
+		case 2: //近期几天
+			findDateTime = latestDateTime.AddDate(0, 0, -barChartInfoDate.Value)
+		case 3: // 固定日期
+			//寻找固定日期的数据
+			tmpFindDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			findDateTime = tmpFindDateTime
+		default:
+			err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type))
+			return
+		}
+		if findDateTime.IsZero() {
+			err = errors.New("错误的日期")
+			return
+		}
+		if findDateTime.Before(earliestDateTime) {
+			earliestDateTime = findDateTime
+		}
+	}
+
+	monthNum := (latestDateTime.Year()-earliestDateTime.Year())*12 + int(latestDateTime.Month()-earliestDateTime.Month())
+
+	// 存储主力合约下的所有月份合约
+	futureGoodEdbInfoDateMap := make(map[int]map[string]*future_good.FutureGoodEdbInfo)
+	futureGoodDataListMap := make(map[int][]*models.EdbDataList, 0)
+	// 特殊的商品期货合约(只有M+N的合约,没有固定日期的合约)
+	specialFutureGoodEdbInfoMap := make(map[int]map[int]*future_good.FutureGoodEdbInfo, 0)
+
+	isAllChina := true // 是否都是国内的期货合约
+	for _, v := range zlFutureGoodEdbInfoList {
+		if v.RegionType != "国内" {
+			isAllChina = false
+			break
+		}
+	}
+
+	nMap := make(map[string]string)
+	var maxN int // 最大N值
+	for _, v := range zlFutureGoodEdbInfoList {
+		// 如果不是有效的商品期货指标,那么就过滤掉,不做数据查询处理,避免没必要的请求
+		if _, ok := futureGoodEdbInfoIdMap[v.FutureGoodEdbInfoId]; !ok {
+			continue
+		}
+		// 获取期货指标以及期货数据
+		tmpFutureGoodEdbInfoList, tmpErr := future_good.GetChildFutureGoodEdbInfoListByParentId(v.FutureGoodEdbInfoId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		childFutureGoodEdbInfoMap, tmpMaxN, tmpErr := getProfitFutureGoodEdbInfoList(earliestDateTime, v, tmpFutureGoodEdbInfoList, isAllChina, monthNum)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		if maxN < tmpMaxN {
+			maxN = tmpMaxN
+		}
+		futureGoodEdbInfoDateMap[v.FutureGoodEdbInfoId] = childFutureGoodEdbInfoMap
+
+		if v.FutureGoodEdbType == 2 {
+			specialFutureGoodEdbInfoMap[v.FutureGoodEdbInfoId] = make(map[int]*future_good.FutureGoodEdbInfo)
+		}
+		// 获取数据
+		for date, childFutureGoodEdbInfo := range childFutureGoodEdbInfoMap {
+			nMap[date] = date
+			dataList := make([]*models.EdbDataList, 0)
+
+			tmpDataList, tmpErr := future_good.GetFutureGoodEdbDataListByDate(childFutureGoodEdbInfo.FutureGoodEdbInfoId, "", "")
+			if tmpErr != nil {
+				return
+			}
+			for _, tmpData := range tmpDataList {
+				dataList = append(dataList, &models.EdbDataList{
+					EdbDataId:     tmpData.FutureGoodEdbDataId,
+					EdbInfoId:     tmpData.FutureGoodEdbInfoId,
+					DataTime:      tmpData.DataTime.Format(utils.FormatDate),
+					DataTimestamp: tmpData.DataTimestamp,
+					Value:         tmpData.Close,
+				})
+			}
+			futureGoodDataListMap[childFutureGoodEdbInfo.FutureGoodEdbInfoId] = dataList
+
+			if childFutureGoodEdbInfo.FutureGoodEdbType == 2 {
+				specialFutureGoodEdbInfoMap[v.FutureGoodEdbInfoId][childFutureGoodEdbInfo.Month] = childFutureGoodEdbInfo
+			}
+		}
+	}
+
+	// 找出所有的N值,并进行正序排列
+	dateList := make([]string, 0)
+	for _, n := range nMap {
+		dateList = append(dateList, n)
+	}
+	sort.Slice(dateList, func(i, j int) bool {
+		return dateList[i] < dateList[j]
+	})
+
+	_, yDataList, err = ProfitChartChartData(baseDataList, futureGoodEdbInfoDateMap, futureGoodDataListMap, chartInfoDateList, latestDate, specialFutureGoodEdbInfoMap, formulaStr, tagEdbIdMap, dateList)
+	if err != nil {
+		return
+	}
+
+	tmpXDataList, newYDataList, err := handleProfitResultData(baseEdbInfo, yDataList, earliestDateTime)
+	if err != nil {
+		return
+	}
+	xDataList = []XData{
+		{
+			Name:   "现货利润",
+			NameEn: "Spot Price",
+		},
+	}
+	xDataList = append(xDataList, tmpXDataList...)
+	yDataList = newYDataList
+
+	return
+}
+
+// ProfitChartChartData 获取数据
+func ProfitChartChartData(baseDataList []*models.EdbDataList, futureGoodEdbInfoMap map[int]map[string]*future_good.FutureGoodEdbInfo, futureGoodEdbDataListMap map[int][]*models.EdbDataList, chartInfoDateList []ChartInfoDateReq, latestDate string, specialFutureGoodEdbInfoMap map[int]map[int]*future_good.FutureGoodEdbInfo, formulaStr string, tagEdbIdMap map[string]int, dateList []string) (edbIdList []int, yDataList []YData, err error) {
+	// 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
+	//earliestDateTime time.Time
+	// ETA指标数据
+	baseEdbDateData := make(map[string]float64)
+	for _, edbData := range baseDataList {
+		baseEdbDateData[edbData.DataTime] = edbData.Value
+	}
+
+	// 商品指标数据
+	edbDataMap := make(map[int]map[string]float64)
+	for edbInfoId, edbDataList := range futureGoodEdbDataListMap {
+		edbDateData := make(map[string]float64)
+		for _, edbData := range edbDataList {
+			edbDateData[edbData.DataTime] = edbData.Value
+		}
+		edbDataMap[edbInfoId] = edbDateData
+	}
+
+	latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local)
+
+	yDataList = make([]YData, 0) //y轴的数据列表
+
+	// 将计算公式中的字母转大写
+	formulaStr = strings.ToUpper(formulaStr)
+
+	for _, barChartInfoDate := range chartInfoDateList {
+		yDataMap := make(map[int]float64)
+		var maxDate time.Time
+
+		var findDateTime time.Time
+		switch barChartInfoDate.Type {
+		case 1: //最新值
+			findDateTime = latestDateTime
+		case 2: //近期几天
+			findDateTime = latestDateTime.AddDate(0, 0, -barChartInfoDate.Value)
+		case 3: // 固定日期
+			//寻找固定日期的数据
+			tmpFindDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			findDateTime = tmpFindDateTime
+		default:
+			err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type))
+			return
+		}
+		if findDateTime.IsZero() {
+			err = errors.New("错误的日期")
+			return
+		}
+
+		findDataList := make([]float64, 0) // 当前日期的数据值
+		noDataIdList := make([]int, 0)     // 没有数据的指标id
+		xEdbInfoIdList := make([]int, 0)   // 当前数据的指标id列表
+
+		// 现货指标
+		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, baseDataList, baseEdbDateData)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		findDataList = append(findDataList, findDataValue)
+		yDataMap[0] = findDataValue
+		if isFind {
+			maxDate = realDateTime
+		}
+
+		xEdbInfoIdList = append(xEdbInfoIdList, 0)
+
+		mList := make([]int, 0) // 间隔月份
+
+		// 最小开始的n值
+		//minN := (findDateTime.Year()-earliestDateTime.Year())*12 + int(findDateTime.Month()-earliestDateTime.Month())
+		for _, date := range dateList {
+			currDate, _ := time.ParseInLocation(utils.FormatYearMonthDate, date, time.Local)
+			// 如果当前的n值小于最小开始的n值,那么就不处理
+			//if n < minN {
+			//	continue
+			//}
+			//findDateTime
+
+			tmpN := (currDate.Year()-findDateTime.Year())*12 + int(currDate.Month()-findDateTime.Month())
+			if tmpN <= 0 {
+				continue
+			}
+
+			zlAndChildEdbId := make(map[int]int)
+			childFutureGoodEdbInfoIdList := make([]int, 0)
+			for zlFutureGoodEdbInfoId, futureGoodEdbInfoList := range futureGoodEdbInfoMap {
+				// 判断是否特殊合约
+				if childFutureGoodEdbInfoIdMap, ok := specialFutureGoodEdbInfoMap[zlFutureGoodEdbInfoId]; ok {
+					if childFutureGoodEdbInfo, ok2 := childFutureGoodEdbInfoIdMap[tmpN]; ok2 {
+						childFutureGoodEdbInfoIdList = append(childFutureGoodEdbInfoIdList, childFutureGoodEdbInfo.FutureGoodEdbInfoId)
+						zlAndChildEdbId[zlFutureGoodEdbInfoId] = childFutureGoodEdbInfo.FutureGoodEdbInfoId
+					}
+
+				} else {
+					if childFutureGoodEdbInfo, ok2 := futureGoodEdbInfoList[date]; ok2 {
+						childFutureGoodEdbInfoIdList = append(childFutureGoodEdbInfoIdList, childFutureGoodEdbInfo.FutureGoodEdbInfoId)
+						zlAndChildEdbId[zlFutureGoodEdbInfoId] = childFutureGoodEdbInfo.FutureGoodEdbInfoId
+					}
+				}
+			}
+
+			// 合约不全,不参与计算
+			//if len(childFutureGoodEdbInfoIdList) != lenZlFutureGoodEdbInfo {
+			//	continue
+			//}
+
+			calculateMap := make(map[int]float64)
+			for _, childFutureGoodEdbInfoId := range childFutureGoodEdbInfoIdList {
+				tmpRealDateTime := findDateTime
+				tmpFindDataValue, tmpIsFind := edbDataMap[childFutureGoodEdbInfoId][findDateTime.Format(utils.FormatDate)]
+
+				if tmpIsFind {
+					calculateMap[childFutureGoodEdbInfoId] = tmpFindDataValue
+					if maxDate.IsZero() || maxDate.Before(tmpRealDateTime) {
+						maxDate = tmpRealDateTime
+					}
+				}
+			}
+			// 合约的数据不全,不参与计算
+			//if len(calculateMap) != lenZlFutureGoodEdbInfo {
+			//	continue
+			//}
+
+			newTagEdbIdMap := make(map[string]int)
+			for tag, zlEdbId := range tagEdbIdMap {
+				newTagEdbIdMap[tag] = zlAndChildEdbId[zlEdbId]
+			}
+			//, formulaStr string, tagEdbIdMap map[string]int
+			formulaFormStr := ReplaceFormula(newTagEdbIdMap, calculateMap, formulaStr)
+			//计算公式异常,那么就移除该指标
+			if formulaFormStr == `` {
+				//removeDateList = append(removeDateList, sk)
+				//fmt.Println("异常了")
+				continue
+			}
+
+			expression := formula.NewExpression(formulaFormStr)
+			calResult, evaluateErr := expression.Evaluate()
+			if evaluateErr != nil {
+				// 分母为0的报错
+				if strings.Contains(evaluateErr.Error(), "divide by zero") {
+					//removeDateList = append(removeDateList, sk)
+					continue
+				}
+				err = errors.New("计算失败:Err:" + evaluateErr.Error() + ";formulaStr:" + formulaFormStr)
+				fmt.Println(err)
+				continue
+			}
+			// 如果计算结果是NAN,那么就退出当前循环
+			if calResult.IsNan() {
+				continue
+			}
+			calVal, tmpErr := calResult.Float64()
+			if tmpErr != nil {
+				err = errors.New("计算失败:获取计算值失败 Err:" + tmpErr.Error() + ";formulaStr:" + formulaFormStr)
+				fmt.Println(err)
+				continue
+			}
+			//yDataMap[n] = calVal
+			//xEdbInfoIdList = append(xEdbInfoIdList, n)
+			yDataMap[tmpN] = calVal
+			xEdbInfoIdList = append(xEdbInfoIdList, tmpN)
+			findDataList = append(findDataList, calVal)
+		}
+		yName := barChartInfoDate.Name
+		yNameEn := barChartInfoDate.Name
+		if yName == `` {
+			if barChartInfoDate.Type == 2 {
+				yName = strconv.Itoa(barChartInfoDate.Value) + "天前"
+				if barChartInfoDate.Value == 1 {
+					yNameEn = strconv.Itoa(barChartInfoDate.Value) + "day ago"
+				} else {
+					yNameEn = strconv.Itoa(barChartInfoDate.Value) + " days ago"
+				}
+			} else {
+				yName = maxDate.Format(utils.FormatDate)
+				yNameEn = maxDate.Format(utils.FormatDate)
+			}
+		}
+		yDate := "0000-00-00"
+		if !maxDate.IsZero() {
+			yDate = maxDate.Format(utils.FormatDate)
+		}
+
+		yDataList = append(yDataList, YData{
+			Date:           yDate,
+			ConfigDate:     findDateTime,
+			Value:          findDataList,
+			NoDataEdbList:  noDataIdList,
+			XEdbInfoIdList: xEdbInfoIdList,
+			Color:          barChartInfoDate.Color,
+			Name:           yName,
+			NameEn:         yNameEn,
+			EdbValMap:      yDataMap,
+			M:              mList,
+		})
+	}
+
+	return
+}
+
+// getFutureGoodEdbInfoList 获取适用的指标列表
+func getProfitFutureGoodEdbInfoList(earliestDateTime time.Time, zlFutureGoodEdbInfo *future_good.FutureGoodEdbInfo, tmpFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, isAllChina bool, monthNum int) (futureGoodEdbInfoDateMap map[string]*future_good.FutureGoodEdbInfo, newMaxN int, err error) {
+	maxM := 32 //最大32期合约
+	futureGoodEdbInfoList := make([]*future_good.FutureGoodEdbInfo, 0)
+	futureGoodEdbInfoDateMap = make(map[string]*future_good.FutureGoodEdbInfo)
+
+	earliestDateTime = time.Date(earliestDateTime.Year(), earliestDateTime.Month(), 1, 0, 0, 0, 0, time.Local)
+	if zlFutureGoodEdbInfo.RegionType == "国内" {
+		startMonth := int(earliestDateTime.Month())
+		if startMonth == 1 {
+			futureGoodEdbInfoList = tmpFutureGoodEdbInfoList
+		} else {
+			// 因为是下标,所以对应想下标是需要-1的
+			index := startMonth - 1
+			futureGoodEdbInfoList = tmpFutureGoodEdbInfoList[index:]
+			futureGoodEdbInfoList = append(futureGoodEdbInfoList, tmpFutureGoodEdbInfoList[:index]...)
+		}
+
+		lenFutureGoodEdbInfoList := len(futureGoodEdbInfoList)
+		//futureGoodEdbInfoList
+		if isAllChina {
+			// 如果全是国内指标,那么只需要拼上多出的几期合约即可
+			maxM = lenFutureGoodEdbInfoList + monthNum
+		}
+
+		for i := 1; i < maxM; i++ {
+			k := i % lenFutureGoodEdbInfoList
+			futureGoodEdbInfoDateMap[earliestDateTime.AddDate(0, i, 0).Format(utils.FormatYearMonthDate)] = futureGoodEdbInfoList[k]
+			if i > newMaxN {
+				newMaxN = i
+			}
+		}
+
+		return
+	}
+
+	for _, v := range tmpFutureGoodEdbInfoList {
+		//海外的连续日期,目前
+		if v.FutureGoodEdbType == 2 {
+			if v.Month <= maxM {
+				futureGoodEdbInfoDateMap[earliestDateTime.AddDate(0, v.Month, 0).Format(utils.FormatYearMonthDate)] = v
+				if v.Month > newMaxN {
+					newMaxN = v.Month
+				}
+			}
+			continue
+		}
+
+		if v.Year < earliestDateTime.Year() {
+			continue
+		}
+		// 小于等于当前年,那么就肯定是ok的
+		if v.Year == earliestDateTime.Year() && v.Month <= int(earliestDateTime.Month()) {
+			continue
+		}
+
+		subYear := v.Year - earliestDateTime.Year()
+		subMonth := v.Month - int(earliestDateTime.Month())
+		// 如果(当前年-最新日期的年份) * 12个月 + (当前月-最新日期的月份) 小于总月份
+		tmpN := subYear*12 + subMonth
+		if tmpN < maxM {
+			earliestDateTime = time.Date(v.Year, time.Month(v.Month), 0, 0, 0, 0, 0, time.Local)
+			futureGoodEdbInfoDateMap[earliestDateTime.Format(utils.FormatYearMonthDate)] = v
+			if tmpN > newMaxN {
+				newMaxN = tmpN
+			}
+			continue
+		}
+	}
+
+	return
+}
+
+// handleProfitResultData 处理成最终的结果数据
+func handleProfitResultData(baseEdbInfo *models.EdbInfo, yDataList []YData, earliestDateTime time.Time) (xDataList []XData, newYDataList []YData, err error) {
+	xDataList = make([]XData, 0)
+	newYDataList = yDataList
+
+	nMap := make(map[int]int)
+
+	for _, v := range yDataList {
+		for _, n := range v.XEdbInfoIdList {
+			nMap[n] = n
+		}
+	}
+
+	// 找出所有的N值,并进行正序排列
+	nList := make([]int, 0)
+	for _, n := range nMap {
+		nList = append(nList, n)
+	}
+	sort.Slice(nList, func(i, j int) bool {
+		return nList[i] < nList[j]
+	})
+
+	for _, n := range nList {
+		if n == 0 {
+			continue
+		}
+		xDataList = append(xDataList, XData{
+			Name:   fmt.Sprint("M+", n),
+			NameEn: fmt.Sprint("M+", n),
+		})
+	}
+
+	for yIndex, yData := range yDataList {
+		newYDataList[yIndex].XEdbInfoIdList = []int{}
+		newYDataList[yIndex].Value = []float64{}
+		tmpNList := nList
+
+		xEdbInfoIdList := yData.XEdbInfoIdList
+		valIndex := 0
+		needNum := 0
+		for _, n := range tmpNList {
+			if len(xEdbInfoIdList) > 0 {
+				currN := xEdbInfoIdList[0]
+				// 当前距离最早的日期相差的N数
+				if n == currN {
+					if needNum > 0 {
+						currVal := yData.Value[valIndex]
+						preVal := yData.Value[valIndex-1]
+						hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(needNum + 1)))
+
+						for tmpNum := 0; tmpNum < needNum; tmpNum++ {
+							newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, 0)
+
+							// 赋值平均值
+							tmpVal, _ := decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(int64(tmpNum + 1)))).RoundCeil(4).Float64()
+							newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, tmpVal)
+						}
+					}
+
+					newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, currN+1)
+					newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[valIndex])
+					valIndex++
+					needNum = 0
+					if len(xEdbInfoIdList) > 0 {
+						xEdbInfoIdList = xEdbInfoIdList[1:]
+					}
+				} else {
+					needNum++
+				}
+			}
+		}
+	}
+
+	maxI := 0
+	for _, yData := range newYDataList {
+		lenEdb := len(yData.XEdbInfoIdList)
+		for i := 0; i < lenEdb; i++ {
+			if yData.XEdbInfoIdList[i] != 0 && !utils.InArrayByInt(yData.NoDataEdbList, yData.XEdbInfoIdList[i]) {
+				if maxI < i {
+					maxI = i
+				}
+			}
+		}
+	}
+
+	earliestDateTime = time.Date(earliestDateTime.Year(), earliestDateTime.Month(), 1, 0, 0, 0, 0, time.Local)
+	xDataList = xDataList[0:maxI]
+	for yIndex, yData := range newYDataList {
+		if len(yData.XEdbInfoIdList) > maxI+1 {
+			newYDataList[yIndex].XEdbInfoIdList = yData.XEdbInfoIdList[0 : maxI+1]
+		}
+		if len(yData.Value) > maxI+1 {
+			newYDataList[yIndex].Value = yData.Value[0 : maxI+1]
+		}
+
+		currDate, _ := time.ParseInLocation(utils.FormatDate, yData.Date, time.Local)
+
+		nameList := make([]string, 0)
+		enNameList := make([]string, 0)
+		for _, n := range newYDataList[yIndex].XEdbInfoIdList {
+			if n == 1 { // 现货价不处理
+				nameList = append(nameList, baseEdbInfo.EdbName)
+				enNameList = append(enNameList, baseEdbInfo.EdbNameEn)
+				continue
+			}
+			if n <= 0 {
+				nameList = append(nameList, `无合约`)
+				enNameList = append(enNameList, `no contract`)
+			} else {
+				var date string
+
+				currDateTime := currDate.AddDate(0, n-1, 0)
+				month := int(currDateTime.Month())
+				date = fmt.Sprintf("%d%d", currDateTime.Year(), month)
+				if month < 10 {
+					date = fmt.Sprintf("%d0%d", currDateTime.Year(), month)
+				}
+				nameList = append(nameList, date)
+				enNameList = append(enNameList, date)
+			}
+		}
+		newYDataList[yIndex].NameList = nameList
+		newYDataList[yIndex].EnNameList = enNameList
+	}
+	return
+}
+
+func CheckFormula(formula string) map[string]string {
+	mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN"}
+
+	str := strings.ToUpper(formula)
+	for _, v := range mathFormula {
+		str = strings.Replace(str, v, "", -1)
+	}
+	str = strings.Replace(str, "(", "", -1)
+	str = strings.Replace(str, ")", "", -1)
+
+	byteMap := make(map[string]string)
+	for i := 0; i < len(str); i++ {
+		byteInt := str[i]
+		if byteInt >= 65 && byteInt <= 90 {
+			byteStr := string(byteInt)
+			if _, ok := byteMap[byteStr]; !ok {
+				byteMap[byteStr] = byteStr
+			}
+		}
+	}
+	return byteMap
+}
+
+func ReplaceFormula(tagEdbIdMap map[string]int, valArr map[int]float64, formulaStr string) string {
+	funMap := GetFormulaMap()
+	for k, v := range funMap {
+		formulaStr = strings.Replace(formulaStr, k, v, -1)
+	}
+
+	replaceCount := 0
+	for tag, edbInfoId := range tagEdbIdMap {
+		if val, valOk := valArr[edbInfoId]; valOk { //值存在
+			dvStr := fmt.Sprintf("%v", val)
+			formulaStr = strings.Replace(formulaStr, tag, dvStr, -1)
+			replaceCount++
+		}
+	}
+	for k, v := range funMap {
+		formulaStr = strings.Replace(formulaStr, v, k, -1)
+	}
+	if replaceCount == len(tagEdbIdMap) {
+		return formulaStr
+	} else {
+		return ""
+	}
+}
+
+func GetFormulaMap() map[string]string {
+	funMap := make(map[string]string)
+	funMap["MAX"] = "[@@]"
+	funMap["MIN"] = "[@!]"
+	funMap["ABS"] = "[@#]"
+	funMap["CEIL"] = "[@$]"
+	funMap["COS"] = "[@%]"
+	funMap["FLOOR"] = "[@^]"
+	funMap["MOD"] = "[@&]"
+	funMap["POW"] = "[@*]"
+	funMap["ROUND"] = "[@(]"
+	return funMap
+}
+
+// GetNeedDateData 获取合约内需要的日期数据
+func GetNeedDateData(needDateTime time.Time, dataList []*models.EdbDataList, edbDataMap map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) {
+	//dataList := edbDataListMap[edbInfoId] //指标的所有数据值
+	if len(dataList) <= 0 {
+		// 没有数据的指标id
+		return
+	}
+
+	//最早的日期
+	minDateTime, err := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
+	if err != nil {
+		return
+	}
+
+	for tmpDateTime := needDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
+		tmpDate := tmpDateTime.Format(utils.FormatDate)
+		if tmpValue, ok := edbDataMap[tmpDate]; ok { //如果能找到数据,那么就返回
+			// 数据为0,也直接返回,做无值处理
+			if tmpValue == 0 {
+				return
+			}
+			findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
+			findDataValue = tmpValue
+			isFind = true
+			return
+		}
+	}
+
+	return
+}

+ 41 - 0
models/chart.go

@@ -3,7 +3,9 @@ package models
 import (
 	"encoding/json"
 	"fmt"
+	"github.com/beego/beego/v2/client/orm"
 	"hongze/hongze_edb_lib/utils"
+	"time"
 )
 
 type EdbInfoReq struct {
@@ -37,3 +39,42 @@ func GetChartInfoDataKey(chartInfoId int) string {
 	key := fmt.Sprint(utils.CACHE_CHART_INFO_DATA, chartInfoId)
 	return key
 }
+
+type ChartInfo struct {
+	ChartInfoId     int    `orm:"column(chart_info_id);pk"`
+	ChartName       string `description:"来源名称"`
+	ChartNameEn     string `description:"英文图表名称"`
+	ChartClassifyId int    `description:"图表分类id"`
+	SysUserId       int
+	SysUserRealName string
+	UniqueCode      string `description:"图表唯一编码"`
+	CreateTime      time.Time
+	ModifyTime      time.Time
+	DateType        int    `description:"日期类型:1:00年至今,2:10年至今,3:15年至今,4:年初至今,5:自定义时间"`
+	StartDate       string `description:"自定义开始日期"`
+	EndDate         string `description:"自定义结束日期"`
+	IsSetName       int    `description:"设置名称"`
+	EdbInfoIds      string `description:"指标id"`
+	ChartType       int    `description:"生成样式:1:曲线图,2:季节性图,3:面积图,4:柱状图,5:散点图,6:组合图,7:柱方图,8:商品价格曲线图,9:相关性图"`
+	Calendar        string `description:"公历/农历"`
+	SeasonStartDate string `description:"季节性图开始日期"`
+	SeasonEndDate   string `description:"季节性图开始日期"`
+	ChartImage      string `description:"图表图片"`
+	Sort            int    `description:"排序字段,数字越小越排前面"`
+	LeftMin         string `description:"图表左侧最小值"`
+	LeftMax         string `description:"图表左侧最大值"`
+	RightMin        string `description:"图表右侧最小值"`
+	RightMax        string `description:"图表右侧最大值"`
+	Disabled        int    `description:"是否禁用,0:启用,1:禁用,默认:0"`
+	BarConfig       string `description:"柱方图的配置,json数据"`
+	Source          int    `description:"1:ETA图库;2:商品价格曲线"`
+	ExtraConfig     string `description:"图表额外配置,json数据"`
+}
+
+// GetChartInfoById 通过id获取图表信息
+func GetChartInfoById(chartInfoId int) (item *ChartInfo, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT * FROM chart_info WHERE chart_info_id=? `
+	err = o.Raw(sql, chartInfoId).QueryRow(&item)
+	return
+}

+ 11 - 0
models/chart_edb_mapping.go

@@ -22,6 +22,7 @@ type ChartEdbMapping struct {
 	ChartStyle        string    `description:"图表类型"`
 	ChartColor        string    `description:"颜色"`
 	ChartWidth        float64   `description:"线条大小"`
+	Source            int       `description:"1:ETA图库;2:商品价格曲线"`
 }
 
 // GetChartEdbMappingListByEdbInfoId 根据指标id获取关联图表列表
@@ -34,3 +35,13 @@ func GetChartEdbMappingListByEdbInfoId(edbInfoId int) (list []*ChartEdbMapping,
 	_, err = o.Raw(sql, edbInfoId).QueryRows(&list)
 	return
 }
+
+// GetGroupChartEdbMappingListByEdbInfoId 根据指标id和来源分组获取关联图表列表
+func GetGroupChartEdbMappingListByEdbInfoId(edbInfoId, source int) (list []*ChartEdbMapping, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT *
+             FROM chart_edb_mapping AS a
+			 WHERE edb_info_id=? AND source = ?  GROUP BY chart_info_id `
+	_, err = o.Raw(sql, edbInfoId, source).QueryRows(&list)
+	return
+}

+ 3 - 2
models/db.go

@@ -66,8 +66,9 @@ func init() {
 func initFutureGood() {
 	//注册对象
 	orm.RegisterModel(
-		new(future_good.FutureGoodEdbInfo), //期货指标表
-		new(future_good.FutureGoodEdbData), //期货指标数据表
+		new(future_good.FutureGoodEdbInfo),         //期货指标表
+		new(future_good.FutureGoodEdbData),         //期货指标数据表
+		new(future_good.ChartInfoFutureGoodProfit), //商品期货利润图表相关的信息
 	)
 }
 

+ 37 - 2
models/edb_data_base.go

@@ -1,13 +1,15 @@
 package models
 
 import (
+	"errors"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"hongze/hongze_edb_lib/utils"
+	"strconv"
 	"time"
 )
 
-//指标检索数据
+// 指标检索数据
 type EdbDataItem struct {
 	EdbCode   string `description:"指标编码"`
 	StartDate string `description:"起始日期"`
@@ -141,7 +143,7 @@ func GetAllEdbDataListByTo(to orm.TxOrmer, edbInfoId, source int) (existDataList
 	return
 }
 
-//新版本
+// 新版本
 type EdbDataV1 struct {
 	EdbDataId     int `orm:"column(edb_data_id);pk"`
 	EdbInfoId     int
@@ -153,3 +155,36 @@ type EdbDataV1 struct {
 	ModifyTime    time.Time
 	DataTimestamp int64
 }
+
+type EdbDataList struct {
+	EdbDataId     int     `description:" 指标数据ID"`
+	EdbInfoId     int     `description:"指标ID"`
+	DataTime      string  //`json:"-" description:"数据日期"`
+	DataTimestamp int64   `description:"数据日期"`
+	Value         float64 `description:"数据值"`
+}
+
+func GetEdbDataList(source, endInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
+	tableName := GetEdbDataTableName(source)
+	if tableName == "" {
+		err = errors.New("无效的渠道:" + strconv.Itoa(source))
+		list = make([]*EdbDataList, 0)
+		return list, err
+	}
+	var pars []interface{}
+	sql := `SELECT edb_data_id,edb_info_id,data_time,value,data_timestamp FROM %s WHERE edb_info_id=? `
+	if startDate != "" {
+		sql += ` AND data_time>=? `
+		pars = append(pars, startDate)
+	}
+	if endDate != "" {
+		sql += ` AND data_time<=? `
+		pars = append(pars, endDate)
+	}
+
+	sql += ` ORDER BY data_time ASC `
+	sql = fmt.Sprintf(sql, tableName)
+	o := orm.NewOrm()
+	_, err = o.Raw(sql, endInfoId, pars).QueryRows(&list)
+	return
+}

+ 88 - 0
models/future_good/chart_info_future_good_profit.go

@@ -0,0 +1,88 @@
+package future_good
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// ChartInfoFutureGoodProfit 商品利润图表-扩展信息
+type ChartInfoFutureGoodProfit struct {
+	ChartInfoId  int       `orm:"column(chart_info_id);pk" description:"商品利润图表ID(chart_info表source=5的)"`
+	ProfitName   string    `description:"利润名称"`
+	ProfitNameEn string    `description:"利润英文名称"`
+	XValue       string    `description:"X轴数据值"`
+	YValue       string    `description:"Y轴数据值"`
+	CreateTime   time.Time `description:"创建时间"`
+	ModifyTime   time.Time `description:"更新时间"`
+}
+
+type CorrelationInfo struct {
+	LeadValue       int    `description:"领先值"`
+	LeadUnit        string `description:"领先单位"`
+	CalculateValue  int    `description:"计算窗口"`
+	CalculateUnit   string `description:"计算频度"`
+	StartDate       string `description:"开始日期"`
+	EndDate         string `description:"结束日期"`
+	EdbInfoIdFirst  int    `description:"A指标ID"`
+	EdbInfoIdSecond int    `description:"B指标ID"`
+	PeriodData      string `description:"X轴-期数数据"`
+	CorrelationData string `description:"Y轴-商品利润系数"`
+}
+
+func (m *ChartInfoFutureGoodProfit) TableName() string {
+	return "chart_info_future_good_profit"
+}
+
+func (m *ChartInfoFutureGoodProfit) Create() (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(m)
+	if err != nil {
+		return
+	}
+	//m.CorrelationChartInfoId = int(id)
+	return
+}
+
+func (m *ChartInfoFutureGoodProfit) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *ChartInfoFutureGoodProfit) Delete() (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE chart_info_id = ? LIMIT 1`, m.TableName())
+	_, err = o.Raw(sql, m.ChartInfoId).Exec()
+	return
+}
+
+func (m *ChartInfoFutureGoodProfit) GetItemById(id int) (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE chart_info_id = ? LIMIT 1`, m.TableName())
+	err = o.Raw(sql, id).QueryRow(&m)
+	return
+}
+
+func (m *ChartInfoFutureGoodProfit) GetItemByCondition(condition string, pars []interface{}) (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s LIMIT 1`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&m)
+	return
+}
+
+func (m *ChartInfoFutureGoodProfit) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*ChartInfoFutureGoodProfit, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}

+ 18 - 0
models/future_good/future_good_edb_data.go

@@ -271,3 +271,21 @@ func GetAddSql(futureGoodEdbInfoId, futureGoodEdbCode, dataTime, tradeCode, open
 	addSql = fmt.Sprintf("(%s,'%s','%s','%s',%s,%s,%s,%s,%s,%s,%s,%s,'%s','%s',%s),", futureGoodEdbInfoId, futureGoodEdbCode, dataTime, tradeCode, open, high, low, close, volume, amt, oi, settle, nowStr, nowStr, timestampStr)
 	return
 }
+
+func GetFutureGoodEdbDataListByDate(futureGoodEdbInfoId int, startDate, endDate string) (list []*FutureGoodEdbData, err error) {
+	var pars []interface{}
+	sql := `SELECT * FROM future_good_edb_data WHERE 1=1 AND future_good_edb_info_id = ? `
+	if startDate != "" {
+		sql += ` AND data_time>=? `
+		pars = append(pars, startDate)
+	}
+	if endDate != "" {
+		sql += ` AND data_time<=? `
+		pars = append(pars, endDate)
+	}
+
+	sql += ` ORDER BY data_time ASC `
+	o := orm.NewOrm()
+	_, err = o.Raw(sql, futureGoodEdbInfoId, pars).QueryRows(&list)
+	return
+}

+ 22 - 0
models/future_good/future_good_edb_info.go

@@ -11,8 +11,13 @@ type FutureGoodEdbInfo struct {
 	FutureGoodEdbInfoId int       `orm:"column(future_good_edb_info_id);pk"`
 	FutureGoodEdbCode   string    `description:"期货指标code"`
 	FutureGoodEdbName   string    `description:"期货指标名称"`
+	FutureGoodEdbNameEn string    `description:"期货指标英文名称"`
 	ParentId            int       `description:"上级期货id"`
+	RegionType          string    `description:"交易所来源,海外还是国内"`
 	Exchange            string    `description:"所属交易所"`
+	FutureGoodEdbType   int       `description:"指标类型,1:年月是固定的合约;2:只有M+N期的合约,未固定年月"`
+	DateSourceId        int       `description:"画图时,日期来源的指标id"`
+	Year                int       `description:"所属年份"`
 	Month               int       `description:"所属月份"`
 	StartDate           string    `description:"起始日期"`
 	EndDate             string    `description:"终止日期"`
@@ -25,6 +30,15 @@ type FutureGoodEdbInfo struct {
 	ModifyTime          time.Time
 }
 
+// GetFutureGoodEdbInfo 期货指标
+func GetFutureGoodEdbInfo(edbInfoId int) (item *FutureGoodEdbInfo, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM future_good_edb_info WHERE future_good_edb_info_id = ? `
+	sql += ` ORDER BY future_good_edb_info_id DESC `
+	err = o.Raw(sql, edbInfoId).QueryRow(&item)
+	return
+}
+
 // GetFutureGoodEdbInfoByCode 根据指标code获取指标信息
 func GetFutureGoodEdbInfoByCode(edbCode string) (item *FutureGoodEdbInfo, err error) {
 	o := orm.NewOrm()
@@ -64,6 +78,14 @@ func AddFutureGoodEdbInfo(item *FutureGoodEdbInfo) (err error) {
 	return
 }
 
+// GetChildFutureGoodEdbInfoListByParentId 根据父级ID获取下面所有的指标数据列表
+func GetChildFutureGoodEdbInfoListByParentId(parentId int) (list []*FutureGoodEdbInfo, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM future_good_edb_info WHERE parent_id = ? ORDER BY future_good_edb_info_id ASC `
+	_, err = o.Raw(sql, parentId).QueryRows(&list)
+	return
+}
+
 // Update 更新指标基础信息
 func (FutureGoodEdbInfo *FutureGoodEdbInfo) Update(cols []string) (err error) {
 	o := orm.NewOrm()

+ 9 - 0
routers/commentsRouter.go

@@ -25,6 +25,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers/future_good:FutureGoodEdbInfoController"] = append(beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers/future_good:FutureGoodEdbInfoController"],
+        beego.ControllerComments{
+            Method: "RefreshRelation",
+            Router: `/relation/refresh`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:BaiinfoController"] = append(beego.GlobalControllerRouter["hongze/hongze_edb_lib/controllers:BaiinfoController"],
         beego.ControllerComments{
             Method: "Add",

+ 10 - 0
utils/constants.go

@@ -14,6 +14,7 @@ const (
 	FormatDateTime             = "2006-01-02 15:04:05" //完整时间格式
 	FormatDateTimeUnSpace      = "20060102150405"      //完整时间格式
 	FormatShortDateTimeUnSpace = "060102150405"        //省去开头两位年份的时间格式
+	FormatYearMonthDate        = "2006-01"             //日期格式
 	PageSize15                 = 15                    //列表页每页数据量
 	PageSize5                  = 5
 	PageSize10                 = 10
@@ -197,3 +198,12 @@ const (
 	CACHE_CHART_INFO_DATA       = "chart:info:data:"             //图表数据
 	CACHE_STOCK_PLANT_CALCULATE = "CACHE_STOCK_PLANT_CALCULATE_" // 库存装置减产计算
 )
+
+// 图表类型
+const (
+	CHART_SOURCE_DEFAULT             = 1
+	CHART_SOURCE_FUTURE_GOOD         = 2
+	CHART_SOURCE_CORRELATION         = 3 // 相关性图表
+	CHART_SOURCE_ROLLING_CORRELATION = 4 // 滚动相关性图表
+	CHART_SOURCE_FUTURE_GOOD_PROFIT  = 5 // 商品利润曲线
+)