Преглед изворни кода

Merge branch 'ETA_1.4.4' into debug

zwxi пре 1 година
родитељ
комит
6e59c8f629

+ 13 - 13
controllers/base_auth.go

@@ -39,19 +39,19 @@ func (this *BaseAuthController) Prepare() {
 	fmt.Println("Url:", uri)
 	if method != "HEAD" {
 		if method == "POST" {
-			authorization := this.Ctx.Input.Header("authorization")
-			if authorization == "" {
-				this.JSON(models.BaseResponse{Ret: 408, Msg: "请重新授权!", ErrMsg: "请重新授权:authorization is empty "}, false, false)
-				this.StopRun()
-				return
-			}
-			checkAuthorization := utils.MD5(utils.APP_NAME_EN + utils.Md5Key)
-			fmt.Println(checkAuthorization)
-			if authorization != checkAuthorization {
-				this.JSON(models.BaseResponse{Ret: 408, Msg: "签名错误!", ErrMsg: "签名错误:authorization is err "}, false, false)
-				this.StopRun()
-				return
-			}
+			//authorization := this.Ctx.Input.Header("authorization")
+			//if authorization == "" {
+			//	this.JSON(models.BaseResponse{Ret: 408, Msg: "请重新授权!", ErrMsg: "请重新授权:authorization is empty "}, false, false)
+			//	this.StopRun()
+			//	return
+			//}
+			//checkAuthorization := utils.MD5(utils.APP_NAME_EN + utils.Md5Key)
+			//fmt.Println(checkAuthorization)
+			//if authorization != checkAuthorization {
+			//	this.JSON(models.BaseResponse{Ret: 408, Msg: "签名错误!", ErrMsg: "签名错误:authorization is err "}, false, false)
+			//	this.StopRun()
+			//	return
+			//}
 		} else {
 			this.JSON(models.BaseResponse{Ret: 408, Msg: "请求异常,请联系客服!", ErrMsg: "POST之外的请求,暂不支持"}, false, false)
 			this.StopRun()

+ 167 - 0
controllers/base_from_ths_ds.go

@@ -0,0 +1,167 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_index_lib/logic"
+	"eta/eta_index_lib/models"
+	"eta/eta_index_lib/services"
+	"eta/eta_index_lib/utils"
+	"strconv"
+	"time"
+)
+
+// 同花顺
+type ThsDsController struct {
+	BaseAuthController
+}
+
+// @Title 新增同花顺指标接口
+// @Description 新增同花顺指标接口
+// @Success 200 {object} models.AddEdbInfoReq
+// @router /ds/add [post]
+func (this *ThsDsController) Add() {
+	br := new(models.BaseResponse).Init()
+	var cacheKey string
+	defer func() {
+		utils.Rc.Delete(cacheKey)
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	source := utils.DATA_SOURCE_THS
+	var req models.AddEdbInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.EdbCode == "" {
+		br.Msg = "请输入指标编码!"
+		br.ErrMsg = "请输入指标编码,指标编码为空"
+		return
+	}
+	cacheKey = utils.CACHE_EDB_DATA_ADD + strconv.Itoa(source) + "_" + req.StockCode + req.EdbCode
+	if !utils.Rc.IsExist(cacheKey) {
+		utils.Rc.SetNX(cacheKey, 1, 1*time.Minute)
+		dataItem, err := services.GetEdbDataFromThsDs(req.StockCode, req.EdbCode, utils.BASE_START_DATE, utils.BASE_END_DATE, "")
+		if err != nil {
+			br.Msg = "获取指标信息失败!"
+			br.ErrMsg = "获取指标信息失败 GetEdbDataFromThsDs,Err:" + err.Error()
+			return
+		}
+		err = models.AddEdbDataFromThsDs(req.StockCode,req.EdbCode, dataItem)
+		if err != nil {
+			br.Msg = "获取指标信息失败!"
+			br.ErrMsg = "获取指标信息失败 AddEdbDataFromThs,Err:" + err.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+	} else {
+		br.Ret = 501
+		br.Success = true
+		br.Msg = "系统处理中,请稍后重试"
+	}
+}
+
+// @Title 刷新同花顺指标接口
+// @Description 刷新同花顺指标接口
+// @Success 200 {object} models.RefreshEdbInfoReq
+// @router /ds/refresh [post]
+func (this *ThsDsController) Refresh() {
+	br := new(models.BaseResponse).Init()
+	var cacheKey string
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	source := utils.DATA_SOURCE_THS
+	var req models.RefreshEdbInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.EdbCode == "" {
+		br.Msg = "请输入指标编码!"
+		br.ErrMsg = "请输入指标编码,指标编码为空"
+		return
+	}
+	if req.EdbInfoId <= 0 {
+		br.Msg = "请输入指标ID!"
+		br.ErrMsg = "请输入指标ID"
+		return
+	}
+
+	// 获取指标详情
+	edbInfo, err := models.GetEdbInfoByEdbCode(source, req.EdbCode)
+	if err != nil {
+		br.Msg = "指标不存在!"
+		br.ErrMsg = "指标不存在"
+		return
+	}
+	cacheKey = utils.CACHE_EDB_DATA_REFRESH + strconv.Itoa(source) + "_" + req.EdbCode
+	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)
+	}()
+	dataItem, err := services.GetEdbDataFromThsDs(edbInfo.StockCode, req.EdbCode, req.StartDate, utils.BASE_END_DATE, edbInfo.TerminalCode)
+	if err != nil {
+		br.Msg = "获取指标信息失败!"
+		br.ErrMsg = "获取指标信息失败 GetEdbDataFromThs,Err:" + err.Error()
+		return
+	}
+	err = models.RefreshEdbDataFromThsDs(req.EdbInfoId, req.EdbCode, req.StartDate, dataItem)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "刷新指标信息失败!"
+		br.ErrMsg = "刷新指标信息失败 RefreshEdbDataFromThs,Err:" + err.Error()
+		return
+	}
+	// 更新指标最大最小值
+	err, errMsg := models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	// 更新ES
+	go logic.UpdateEs(edbInfo.EdbInfoId)
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+//func init() {
+//	//?EdbCode=s005696248&StartDate=2023-02-03&EndDate=2027-03-23
+//	//edbCode := `s005696248`
+//	//startDate := `2023-02-03`
+//	//endDate := `2027-03-23`
+//	//EdbCode=S011292460&StartDate=1993-03-23&EndDate=2027-03-23
+//	edbCode := `S011292460`
+//	startDate := `1993-03-23`
+//	endDate := `2027-03-23`
+//	//edbCode := `@CL0W.NMX`
+//	//startDate := `20221218`
+//	//endDate := `20230118`
+//	list, err := services.GetEdbDataFromThsHttp(edbCode, startDate, endDate, 0)
+//	//list, err := services.GetFutureGoodDataFromThsHttp(edbCode, startDate, endDate)
+//
+//	//token, err := services.GetAccessToken()
+//	if err != nil {
+//		fmt.Println("err:", err)
+//		return
+//	}
+//	fmt.Println(list)
+//	//fmt.Println(token)
+//}

+ 167 - 0
models/base_from_ths_ds.go

@@ -0,0 +1,167 @@
+package models
+
+import (
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strconv"
+	"strings"
+	"time"
+)
+
+var thsds = "thsds"
+
+// 新增同花顺指标数据
+func AddEdbDataFromThsDs(stockCode,edbCode string, item EdbDataFromThs) (err error) {
+	o := orm.NewOrm()
+
+	edbCodeList := strings.Split(edbCode, ",")
+	indexCodeMap := make(map[string]string)
+	if len(item.Tables) > 0 {
+		var isAdd bool
+		addSql := ` INSERT INTO edb_data_ths_ds(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+		for k, table := range item.Tables {
+			dataLen := len(table.Time)
+			for i := 0; i < dataLen; i++ {
+				eDate := table.Time[i]
+				var sValue float64
+				if len(table.Value) != 0 {
+					sValue = table.Value[i]
+				}
+				code := edbCodeList[k]
+				dataTime, err := time.ParseInLocation(utils.FormatDate, eDate, time.Local)
+				if err != nil {
+					return err
+				}
+				timestamp := dataTime.UnixNano() / 1e6
+				timeStr := fmt.Sprintf("%d", timestamp)
+				indexCode := thsds+stockCode+code
+				indexCodeMap[indexCode] = indexCode
+				addSql += GetAddSql("0", indexCode, eDate, timeStr, utils.SubFloatToString(sValue, 20))
+				isAdd = true
+			}
+		}
+		if isAdd {
+			for _, v := range indexCodeMap {
+				var count int
+				sql := ` SELECT COUNT(1) FROM edb_data_ths_ds WHERE edb_code=? `
+				err = o.Raw(sql, v).QueryRow(&count)
+				if err != nil {
+					return err
+				}
+				if count > 0 {
+					sql = ` DELETE FROM edb_data_ths_ds WHERE edb_code=? `
+					_, err = o.Raw(sql, v).Exec()
+					if err != nil {
+						return err
+					}
+				}
+			}
+
+			addSql = strings.TrimRight(addSql, ",")
+			_, err = o.Raw(addSql).Exec()
+			if err != nil {
+				return
+			}
+		}
+	}
+	return
+}
+
+// 刷新同花顺指标数据
+func RefreshEdbDataFromThsDs(edbInfoId int, edbCode, startDate string, item EdbDataFromThs) (err error) {
+	o := orm.NewOrm()
+	source := utils.DATA_SOURCE_THS
+	subSource := utils.DATA_SUB_SOURCE_DATE
+
+	// 真实数据的最大日期  , 插入规则配置的日期
+	var realDataMaxDate, edbDataInsertConfigDate time.Time
+	var edbDataInsertConfig *EdbDataInsertConfig
+	var isFindConfigDateRealData bool //是否找到配置日期的实际数据的值
+	{
+		edbDataInsertConfig, err = GetEdbDataInsertConfigByEdbId(edbInfoId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			return
+		}
+		if edbDataInsertConfig != nil {
+			edbDataInsertConfigDate = edbDataInsertConfig.Date
+		}
+	}
+
+	if len(item.Tables) > 0 {
+		var condition string
+		var pars []interface{}
+
+		condition += " AND edb_info_id=? "
+		pars = append(pars, edbInfoId)
+		if startDate != "" {
+			condition += " AND data_time>=? "
+			pars = append(pars, startDate)
+		}
+
+		existList, err := GetEdbDataByCondition(source, subSource, condition, pars)
+		if err != nil {
+			return err
+		}
+
+		existMap := make(map[string]*EdbInfoSearchData)
+		for _, v := range existList {
+			existMap[v.DataTime] = v
+		}
+
+		table := item.Tables[0]
+		dataLen := len(table.Time)
+		addSql := ` INSERT INTO edb_data_ths_ds(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+		var isAdd bool
+		addMap := make(map[string]string)
+		edbInfoIdStr := strconv.Itoa(edbInfoId)
+		for i := 0; i < dataLen; i++ {
+			eDate := table.Time[i]
+			sValue := table.Value[i]
+			sValueStr := utils.SubFloatToString(sValue, 30)
+
+			dataTime, err := time.ParseInLocation(utils.FormatDate, eDate, time.Local)
+			if err != nil {
+				return err
+			}
+			if findItem, ok := existMap[eDate]; !ok {
+				if _, addOk := addMap[eDate]; !addOk {
+					timestamp := dataTime.UnixNano() / 1e6
+					timeStr := fmt.Sprintf("%d", timestamp)
+					addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, sValueStr)
+					isAdd = true
+					addMap[eDate] = sValueStr
+				}
+			} else {
+				if findItem != nil && utils.SubFloatToString(findItem.Value, 30) != utils.SubFloatToString(sValue, 30) {
+					err = ModifyEdbDataById(source, subSource, findItem.EdbDataId, sValueStr)
+					if err != nil {
+						return err
+					}
+				}
+			}
+
+			// 下面代码主要目的是处理掉手动插入的数据判断
+			{
+				if realDataMaxDate.IsZero() || dataTime.After(realDataMaxDate) {
+					realDataMaxDate = dataTime
+				}
+				if edbDataInsertConfigDate.IsZero() || dataTime.Equal(edbDataInsertConfigDate) {
+					isFindConfigDateRealData = true
+				}
+			}
+		}
+
+		// 处理手工数据补充的配置
+		HandleConfigInsertEdbData(realDataMaxDate, edbDataInsertConfig, edbInfoId, source, subSource, existMap, isFindConfigDateRealData)
+
+		if isAdd {
+			addSql = strings.TrimRight(addSql, ",")
+			_, err = o.Raw(addSql).Exec()
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return
+}

+ 5 - 0
models/edb_data_table.go

@@ -9,6 +9,11 @@ func GetEdbDataTableName(source, subSource int) (tableName string) {
 	switch source {
 	case utils.DATA_SOURCE_THS:
 		tableName = "edb_data_ths"
+		if subSource == utils.DATA_SUB_SOURCE_DATE {
+			tableName = "edb_data_wind_wsd"
+		} else {
+			tableName = "edb_data_wind"
+		}
 	case utils.DATA_SOURCE_WIND:
 		if subSource == utils.DATA_SUB_SOURCE_DATE {
 			tableName = "edb_data_wind_wsd"

+ 18 - 0
routers/commentsRouter.go

@@ -970,6 +970,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_index_lib/controllers:ThsDsController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers:ThsDsController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/ds/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_index_lib/controllers:ThsDsController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers:ThsDsController"],
+        beego.ControllerComments{
+            Method: "Refresh",
+            Router: `/ds/refresh`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_index_lib/controllers:WindController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers:WindController"],
         beego.ControllerComments{
             Method: "Add",

+ 1 - 0
routers/router.go

@@ -20,6 +20,7 @@ func init() {
 		beego.NSNamespace("/ths",
 			beego.NSInclude(
 				&controllers.ThsController{},
+				&controllers.ThsDsController{},
 			),
 		),
 		beego.NSNamespace("/pb",

+ 15 - 0
services/base_from_ths.go

@@ -269,3 +269,18 @@ func getFutureGoodDataFromThsApp(edbCode, startDate, endDate string, num int, se
 	}
 	return
 }
+
+type StockDatas struct {
+	Time    string `json:"time"`
+	ThsCode string `json:"thscode"`
+	//OpenPriceStock   *float64 `json:"ths_open_price_stock"`
+	//HighPriceStock   *float64 `json:"ths_high_price_stock"`
+	//LowStock         *float64 `json:"ths_low_stock,omitempty"`
+	Value *float64
+}
+
+type TerminalResponse struct {
+	ErrorCode int          `json:"errorcode"`
+	ErrMsg    string       `json:"errmsg"`
+	Data      []map[string]interface{} `json:"data"`
+}

+ 226 - 0
services/base_from_ths_ds.go

@@ -0,0 +1,226 @@
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_index_lib/models"
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/http"
+)
+
+func GetEdbDataFromThsDs(stockCode, edbCode, startDate, endDate, edbTerminalCode string) (item models.EdbDataFromThs, err error) {
+	terminal, err := GetTerminal(utils.DATA_SOURCE_THS, edbTerminalCode)
+	if err != nil {
+		err = fmt.Errorf("获取同花顺接口配置出错 Err: %s", err)
+		return
+	}
+	if terminal.ServerUrl == "" {
+		err = fmt.Errorf("同花顺接口未配置")
+		return
+	}
+
+	if edbTerminalCode == "" {
+		// 设置指标与终端关系的缓存
+		terminalCodeCacheKey := utils.CACHE_EDB_TERMINAL_CODE_URL + stockCode
+		_ = utils.Rc.Put(terminalCodeCacheKey, terminal.TerminalCode, utils.GetTodayLastSecond())
+	}
+
+	// 如果没有配置,获取配置的方式是api,那么就走官方接口
+	if utils.ThsDataMethod == "" || utils.ThsDataMethod == "api" {
+		var token string
+		token, err = GetAccessToken(false, terminal.Value)
+		if err != nil {
+			return
+		}
+		return getEdbDataFromThsDsHttp(stockCode, edbCode, startDate, endDate, terminal.Value, token)
+	}
+
+	return getEdbDataFromThsDsApp(stockCode,edbCode, startDate, endDate, 0, terminal.ServerUrl)
+}
+
+type EdbDataFromThsSdInterface struct {
+	Errorcode   int      `json:"errorcode"`
+	Errmsg      string   `json:"errmsg"`
+	Tables      []Table  `json:"tables"`
+	Datatype    []Type   `json:"datatype"`
+	InputParams interface{}   `json:"inputParams"`
+	DataVol     int      `json:"dataVol"`
+	Perf        int      `json:"perf"`
+}
+
+type Table struct {
+	Thscode string    `json:"thscode"`
+	Time    []string  `json:"time"`
+	Table   map[string]interface{} `json:"table"`
+}
+
+type StockData struct {
+	THSOpenPriceStock      []float64 `json:"ths_open_price_stock"`
+	THSHighPriceStock      []float64 `json:"ths_high_price_stock"`
+	THSLowStock            []float64 `json:"ths_low_stock"`
+	THSClosePriceStock     []float64 `json:"ths_close_price_stock"`
+	THSChgRatioStock       []float64 `json:"ths_chg_ratio_stock"`
+	THSChgStock            []float64 `json:"ths_chg_stock"`
+	THSVolStock            []float64 `json:"ths_vol_stock"`
+	THSPreCloseStock       []float64 `json:"ths_pre_close_stock"`
+	THSSwingStock          []float64 `json:"ths_swing_stock"`
+	THSTurnoverRatioStock  []float64 `json:"ths_turnover_ratio_stock"`
+	THSAmtStock            []float64 `json:"ths_amt_stock"`
+}
+
+type Type struct {
+	Itemid string `json:"itemid"`
+	Type   string `json:"type"`
+}
+//
+//type Params struct {
+//	Jsonrpc bool     `json:"jsonrpc"`
+//	Params  []Param  `json:"params"`
+//}
+//
+//type Param struct {
+//	Function string   `json:"function"`
+//	ID       string   `json:"id"`
+//	Params   []Param2 `json:"params"`
+//}
+//
+//type Param2 struct {
+//	Name   string `json:"name"`
+//	System string `json:"system"`
+//	Value  string `json:"value"`
+//}
+
+// getEdbDataFromThsDs 获取同花顺接口数据
+func getEdbDataFromThsDsApp(stockCode, edbCode, startDate, endDate string, num int, serverUrl string) (item models.EdbDataFromThs, err error) {
+	if serverUrl == `` {
+		err = errors.New("同花顺接口未配置")
+		return
+	}
+	thsUrl := serverUrl + `edbInfo/ths/ds?StockCode=%s&EdbCode=%s&StartDate=%s&EndDate=%s`
+	thsUrl = fmt.Sprintf(thsUrl, stockCode, edbCode, "2023-11-01", "2023-11-05")
+	utils.FileLog.Info("thsUrl:" + thsUrl)
+	body, err := http.Get(thsUrl)
+	utils.FileLog.Info("ths result:" + string(body))
+	if err != nil {
+		err = errors.New(" Err:" + err.Error() + ";result:" + string(body))
+		return
+	}
+	if string(body) == "null" {
+		err = errors.New("同花顺数据获取异常:" + err.Error() + ";result:" + string(body))
+		return
+	}
+println(string(body))
+
+	var jsonArray []string
+	if err = json.Unmarshal(body, &jsonArray); err != nil {
+		fmt.Println("json.Unmarshal Err:", err)
+		return
+	}
+	tablesList := make([]models.Tables, 0)
+
+	// 解码数组内的每个 JSON 字符串
+	//var responses []TerminalResponse
+	var errCode int64
+	for _, data := range jsonArray {
+		tableTimeList := make([]string, 0)
+		tableValueList := make([]float64, 0)
+		var response TerminalResponse
+		if err = json.Unmarshal([]byte(data), &response); err != nil {
+			fmt.Println("json.Unmarshal Err:", err)
+			return
+		}
+
+		errCode = int64(response.ErrorCode)
+		if response.ErrorCode != 0 {
+			//session has expired,please re-login after using the system
+			//如果是同花顺登录session失效了,那么就重新请求获取数据
+			if response.ErrorCode == -1020 && num == 0 {
+				return getEdbDataFromThsDsApp(stockCode, edbCode, startDate, endDate, 1, serverUrl)
+			}
+			err = errors.New(string(body))
+			return
+		}
+
+		for _, stockData := range response.Data {
+			time := stockData["time"].(string)
+			//thsCode := stockData["thscode"].(string)
+			tableTimeList = append(tableTimeList, time)
+
+			for k, v := range stockData {
+				if k != "time" && k != "thscode" {
+					tableValueList = append(tableValueList,  v.(float64))
+				}
+			}
+		}
+		tmpTable := models.Tables{
+			ID:  []string{},
+			Time:  tableTimeList,
+			Value: tableValueList,
+		}
+		tablesList = append(tablesList, tmpTable)
+	}
+	item = models.EdbDataFromThs{
+		DataVol:   0,
+		Errmsg:    "",
+		Errorcode: errCode,
+		Perf:      "",
+		Tables:    tablesList,
+	}
+	//tmpItems := new([]TerminalResponse)
+	//err = json.Unmarshal(body, &tmpItems)
+	//if err != nil {
+	//	err = errors.New("GetEdbDataFromThs json.Unmarshal Err:" + err.Error())
+	//	return
+	//}
+
+
+
+	//// 因为table里面的value有的时候返回的是string,有的是float64,所以需要用interface来反射取值
+	//tablesList := make([]models.Tables, 0)
+	//for _, table := range tmpItems.Tables {
+	//	tableIdList := make([]string, 0)
+	//	tableTimeList := make([]string, 0)
+	//	tableValueList := make([]float64, 0)
+	//
+	//	for _, tableId := range table.ID {
+	//		tableIdList = append(tableIdList, tableId)
+	//	}
+	//	for _, tableTime := range table.Time {
+	//		tableTimeList = append(tableTimeList, tableTime)
+	//	}
+	//
+	//	//指标数据
+	//	for _, tmpValue := range table.Value {
+	//		var tableValue float64
+	//		if reflect.TypeOf(tmpValue).Kind() == reflect.Float64 {
+	//			tableValue = reflect.ValueOf(tmpValue).Float()
+	//		} else if reflect.TypeOf(tmpValue).Kind() == reflect.String {
+	//			tmpTableValue, tmpErr := decimal.NewFromString(reflect.ValueOf(tmpValue).String())
+	//			if tmpErr != nil {
+	//				err = tmpErr
+	//				return
+	//			}
+	//			tableValue, _ = tmpTableValue.Truncate(4).Float64()
+	//		} else {
+	//			err = errors.New("错误的数据类型" + reflect.TypeOf(tmpValue).String())
+	//			return
+	//		}
+	//		tableValueList = append(tableValueList, tableValue)
+	//	}
+	//	tmpTable := models.Tables{
+	//		ID:    tableIdList,
+	//		Time:  tableTimeList,
+	//		Value: tableValueList,
+	//	}
+	//	tablesList = append(tablesList, tmpTable)
+	//}
+	//item = models.EdbDataFromThs{
+	//	DataVol:   tmpItems.DataVol,
+	//	Errmsg:    tmpItems.Errmsg,
+	//	Errorcode: tmpItems.Errorcode,
+	//	Perf:      tmpItems.Perf,
+	//	Tables:    tablesList,
+	//}
+	return item, nil
+}

+ 204 - 0
services/base_from_ths_ds_http.go

@@ -0,0 +1,204 @@
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_index_lib/models"
+	"fmt"
+	"reflect"
+	"strings"
+)
+
+// getEdbDataFromThsDsHttp 通过url获取同花顺的日期序列数据
+func getEdbDataFromThsDsHttp(stockCode, edbCode, startDate, endDate, thsRefreshToken, token string) (item models.EdbDataFromThs, err error) {
+	thsUrl := "https://quantapi.51ifind.com/api/v1/date_sequence"
+	//indicators 是 半角逗号分隔的所有指标,宏观指标过多,推荐使用Windows超级命令生成。 "indicators":"M001620326,M002822183"
+	//functionpara 否 key-value格式,省略时不进行更新时间筛选。两个时间控件更新起始时间(startrtime)和更新结束时间(endrtime),不勾选时省略见下方代码块
+	//startdate 是 开始日期,支持”YYYYMMDD"”YYYY-MM-DD"”YYYY/MM/DD"三种时间格式 "startdate":"2018-01-01"
+	//enddate 是 结束日期,支持”YYYYMMDD"”YYYY-MM-DD"”YYYY/MM/DD"三种日期格式 "enddate":"2018-01-01
+	//发送创建请求
+	// 分割字符串
+	paramList := strings.Split(edbCode, ",")
+
+	// 创建一个包含映射的切片
+	var indipara []map[string]interface{}
+
+	// 遍历分割后的参数列表
+	for _, param := range paramList {
+		// 创建一个映射
+		paramMap := map[string]interface{}{
+			"indicator": param,
+		}
+
+		// 将映射添加到切片中
+		indipara = append(indipara, paramMap)
+	}
+	dataMap := map[string]interface{}{
+		"codes":     stockCode,
+		"startdate": "2023-11-06",
+		"enddate":   "2023-12-06",
+		"indipara":  indipara,
+	}
+
+	body, err, _ := postCurl(thsUrl, dataMap, 0, thsRefreshToken, token)
+	if err != nil {
+		return
+	}
+
+	tmpItems := new(EdbDataFromThsSdInterface)
+	err = json.Unmarshal(body, &tmpItems)
+	if err != nil {
+		err = errors.New("GetEdbDataFromThs json.Unmarshal Err:" + err.Error())
+		return
+	}
+	if tmpItems.Errorcode != 0 {
+		err = errors.New(tmpItems.Errmsg)
+		return
+	}
+
+	// 请求的字段名
+	edbCodeList := strings.Split(edbCode, ",")
+
+	// 遍历请求的字段,并从 map 中获取对应的结构体字段
+	// 证券代码为多个时有多个table,目前只有一个
+	tablesList := make([]models.Tables, 0)
+	tableTimeList := make([]string, 0)
+	if len(tmpItems.Tables) > 0 {
+		for _, time := range tmpItems.Tables[0].Time{
+			tableTimeList = append(tableTimeList, time)
+		}
+		for _, field := range edbCodeList {
+			tableValueList := make([]float64, 0)
+
+			if values, ok := tmpItems.Tables[0].Table[field]; ok {
+				// 在这里,value 是一个接口类型,需要使用反射获取切片的值
+				sliceValue := reflect.ValueOf(values)
+				for i := 0; i < sliceValue.Len(); i++ {
+					fmt.Printf("%s: %v\n", field, sliceValue.Index(i).Interface())
+
+					var tableValue float64
+					value := reflect.ValueOf(sliceValue.Index(i).Interface())
+					if value.Kind() == reflect.Float64 {
+						tableValue = value.Float()
+						tableValueList = append(tableValueList, tableValue)
+					}
+				}
+			} else {
+				fmt.Printf("Field '%s' not found\n", field)
+			}
+			tmpTable := models.Tables{
+				ID:  []string{},
+				Time:  tableTimeList,
+				Value: tableValueList,
+			}
+			tablesList = append(tablesList, tmpTable)
+		}
+
+		//// 因为table里面的value有的时候返回的是string,有的是float64,所以需要用interface来反射取值
+		//tablesList := make([]models.Tables, 0)
+		//for _, table := range tmpItems.Tables[0].Time {
+		//	//tableCodeList := make([]string, 0)
+		//	tableTimeList := make([]string, 0)
+		//	tableValueList := make([]float64, 0)
+		//
+		//	//for _, code := range table.Thscode {
+		//	//	tableCodeList = append(tableCodeList, code)
+		//	//}
+		//	for _, tableTime := range table {
+		//		tableTimeList = append(tableTimeList, tableTime)
+		//	}
+		//
+		//	//指标数据
+		//	for _, tmpValue := range table {
+		//		var tableValue float64
+		//		if reflect.TypeOf(tmpValue).Kind() == reflect.Float64 {
+		//			tableValue = reflect.ValueOf(tmpValue).Float()
+		//		} else if reflect.TypeOf(tmpValue).Kind() == reflect.String {
+		//			tmpTableValue, tmpErr := decimal.NewFromString(reflect.ValueOf(tmpValue).String())
+		//			if tmpErr != nil {
+		//				err = tmpErr
+		//				return
+		//			}
+		//			tableValue, _ = tmpTableValue.Truncate(4).Float64()
+		//		} else {
+		//			err = errors.New("错误的数据类型" + reflect.TypeOf(tmpValue).String())
+		//			return
+		//		}
+		//		tableValueList = append(tableValueList, tableValue)
+		//	}
+		//	tmpTable := models.Tables{
+		//		ID:    []string{},
+		//		Time:  tableTimeList,
+		//		Value: tableValueList,
+		//	}
+		//	tablesList = append(tablesList, tmpTable)
+		//}
+	}
+
+	item = models.EdbDataFromThs{
+		DataVol:   int64(tmpItems.DataVol),
+		Errmsg:    tmpItems.Errmsg,
+		Errorcode: int64(tmpItems.Errorcode),
+		Perf:      tmpItems.Perf,
+		Tables:    tablesList,
+	}
+	return
+}
+
+// getFutureGoodDataFromThsHttp 通过url获取同花顺的商品数据
+//func getFutureGoodDataFromThsHttp(edbCode, startDate, endDate, thsRefreshToken, token string) (item future_good.FutureGoodDataFromThs, err error) {
+//	thsUrl := `https://quantapi.51ifind.com/api/v1/cmd_history_quotation`
+//
+//	//codes 是 半角逗号分隔的所有代码 "codes":"300033.SZ,600030.SH"
+//	//indicators 是 半角逗号分隔的所有指标 "indicators":"preClose,open"
+//	//functionpara 否 /key-value格式。所有key均取默认时,functionpara省略。 见下方说明
+//	//startdate 是 开始日期,支持"YYYYMMDD""YYYY-MMDD""YYYY/MM/DD"三种日期格式
+//	//"startdate":"2018-01-01"
+//	//enddate 是 结束日期,支持"YYYYMMDD""YYYY-MMDD""YYYY/MM/DD"三种日期格式
+//	//发送创建请求
+//	dataMap := map[string]interface{}{
+//		"codes":      edbCode,
+//		"indicators": `lastclose,open,high,low,close,avgprice,change,changeper,volume,amount,hsl,lastsettlement,settlement,zdsettlement,zdfsettlement,ccl,ccbd,zf,zjlx,zjcd`,
+//		"startdate":  startDate,
+//		"enddate":    endDate,
+//	}
+//
+//	body, err, _ := postCurl(thsUrl, dataMap, 0, thsRefreshToken, token)
+//	if err != nil {
+//		return
+//	}
+//
+//	tmpItems := new(FutureGoodDataFromThsInterface)
+//	err = json.Unmarshal(body, &tmpItems)
+//	if err != nil {
+//		err = errors.New("GetEdbDataFromThs json.Unmarshal Err:" + err.Error())
+//		return
+//	}
+//	if tmpItems.Errorcode != 0 {
+//		err = errors.New(tmpItems.Errmsg)
+//		return
+//	}
+//
+//	if len(tmpItems.Tables) <= 0 {
+//		return
+//	}
+//	table := tmpItems.Tables[0]
+//	item = future_good.FutureGoodDataFromThs{
+//		DataVol:   tmpItems.DataVol,
+//		Errmsg:    tmpItems.Errmsg,
+//		Errorcode: tmpItems.Errorcode,
+//		Perf:      tmpItems.Perf,
+//		Tables: future_good.FutureGoodDataTables{
+//			Time:       table.Time,
+//			Open:       table.Table.Open,
+//			High:       table.Table.High,
+//			Low:        table.Table.Low,
+//			Close:      table.Table.Close,
+//			Volume:     table.Table.Volume,
+//			Amount:     table.Table.Amount,
+//			Ccl:        table.Table.Ccl,
+//			Settlement: table.Table.Settlement,
+//		},
+//	}
+//	return
+//}

+ 36 - 0
utils/common.go

@@ -24,6 +24,7 @@ import (
 	"strconv"
 	"strings"
 	"time"
+	"unicode"
 )
 
 // 随机数种子
@@ -1127,3 +1128,38 @@ func CheckFrequency(leftFrequency, rightFrequency string) int {
 
 	return frequencyMap[leftFrequency] - frequencyMap[rightFrequency]
 }
+
+// 将下划线命名转为驼峰命名
+func SnakeToCamel(s string) string {
+	var result string
+	upper := true
+	for _, c := range s {
+		if c == '_' {
+			upper = true
+			continue
+		}
+		if upper {
+			result += string(unicode.ToUpper(c))
+			upper = false
+		} else {
+			result += string(c)
+		}
+	}
+	return result
+}
+
+// 将驼峰命名转为下划线命名
+func CamelToSnake(s string) string {
+	var result string
+	for i, c := range s {
+		if unicode.IsUpper(c) {
+			if i > 0 {
+				result += "_"
+			}
+			result += string(unicode.ToLower(c))
+		} else {
+			result += string(c)
+		}
+	}
+	return result
+}