|
@@ -0,0 +1,316 @@
|
|
|
+package services
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "errors"
|
|
|
+ "fmt"
|
|
|
+ "github.com/shopspring/decimal"
|
|
|
+ "hongze/hongze_edb_lib/services/alarm_msg"
|
|
|
+ "hongze/hongze_edb_lib/utils"
|
|
|
+ "io"
|
|
|
+ netHttp "net/http"
|
|
|
+ "reflect"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+var refreshToken = `eyJzaWduX3RpbWUiOiIyMDIzLTAzLTI0IDEzOjQ3OjExIn0=.eyJ1aWQiOiI1NzY2NDgxMDkifQ==.339B8D21168AC21A0F80840544E38378AB2D04A02D325F0CD1C44251915233F6`
|
|
|
+
|
|
|
+func GetEdbDataFromThsHttp(edbCode, startDate, endDate string) (item EdbDataFromThs, err error) {
|
|
|
+ thsUrl := `https://quantapi.51ifind.com/api/v1/edb_service`
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ dataMap := map[string]interface{}{
|
|
|
+ "indicators": edbCode,
|
|
|
+ "startdate": startDate,
|
|
|
+ "enddate": endDate,
|
|
|
+ }
|
|
|
+
|
|
|
+ body, err, _ := postCurl(thsUrl, dataMap, 0)
|
|
|
+
|
|
|
+ tmpItems := new(EdbDataFromThsInterface)
|
|
|
+ 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
|
|
|
+ }
|
|
|
+
|
|
|
+ tablesList := make([]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 := Tables{
|
|
|
+ ID: tableIdList,
|
|
|
+ Time: tableTimeList,
|
|
|
+ Value: tableValueList,
|
|
|
+ }
|
|
|
+ tablesList = append(tablesList, tmpTable)
|
|
|
+ }
|
|
|
+ item = EdbDataFromThs{
|
|
|
+ DataVol: tmpItems.DataVol,
|
|
|
+ Errmsg: tmpItems.Errmsg,
|
|
|
+ Errorcode: tmpItems.Errorcode,
|
|
|
+ Perf: tmpItems.Perf,
|
|
|
+ Tables: tablesList,
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func GetFutureGoodDataFromThsHttp(edbCode, startDate, endDate string) (item FutureGoodDataFromThs, err error) {
|
|
|
+
|
|
|
+ thsUrl := `https://quantapi.51ifind.com/api/v1/cmd_history_quotation`
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 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)
|
|
|
+
|
|
|
+ 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 = FutureGoodDataFromThs{
|
|
|
+ DataVol: tmpItems.DataVol,
|
|
|
+ Errmsg: tmpItems.Errmsg,
|
|
|
+ Errorcode: tmpItems.Errorcode,
|
|
|
+ Perf: tmpItems.Perf,
|
|
|
+ Tables: 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
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+type BaseThsInterface struct {
|
|
|
+ ErrMsg string `json:"errmsg"`
|
|
|
+ ErrorCode int64 `json:"errorcode"`
|
|
|
+ Tables interface{} `json:"tables"`
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func postCurl(urlStr string, dataMap map[string]interface{}, num int) (body []byte, err error, errMsg string) {
|
|
|
+ logMsg := ``
|
|
|
+ defer func() {
|
|
|
+ if err != nil {
|
|
|
+ if logMsg != `` {
|
|
|
+ errMsg = logMsg
|
|
|
+ go alarm_msg.SendAlarmMsg("post请求上海接口失败,ERR:"+err.Error()+";errMsg:"+errMsg, 3)
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ token, err := GetAccessToken(false)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ jsonStrByte, err := json.Marshal(dataMap)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ reqStr := string(jsonStrByte)
|
|
|
+ req, _ := netHttp.NewRequest("POST", urlStr, strings.NewReader(reqStr))
|
|
|
+ req.Header.Add("Content-Type", "application/json")
|
|
|
+ req.Header.Add("access_token", token)
|
|
|
+
|
|
|
+ res, _ := netHttp.DefaultClient.Do(req)
|
|
|
+ defer res.Body.Close()
|
|
|
+
|
|
|
+ body, err = io.ReadAll(res.Body)
|
|
|
+ if err != nil {
|
|
|
+ logMsg = fmt.Sprint("post err; request:", reqStr, "; errMsg:", err.Error())
|
|
|
+ utils.FileLog.Info(logMsg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ logMsg = fmt.Sprint("post request url:", urlStr, ";params:", reqStr, ";response:", string(body))
|
|
|
+
|
|
|
+ var response BaseThsInterface
|
|
|
+ err = json.Unmarshal(body, &response)
|
|
|
+ if err != nil {
|
|
|
+ utils.FileLog.Info("post Err:", err.Error(), ";url:", urlStr, ";params:", reqStr, ";response:", string(body))
|
|
|
+ err = errors.New("Unmarshal Err:" + err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ utils.FileLog.Info(fmt.Sprint("post request url:", urlStr, ";params:", reqStr, ";response:", string(body)))
|
|
|
+
|
|
|
+
|
|
|
+ if response.ErrorCode == -1010 && num <= 0 {
|
|
|
+
|
|
|
+ _, tmpErr := refreshAccessToken()
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ }
|
|
|
+ num++
|
|
|
+ return postCurl(urlStr, dataMap, num)
|
|
|
+ } else if response.ErrorCode != 1 {
|
|
|
+ utils.FileLog.Info(fmt.Sprint("post data err", ";url:", urlStr, ";params:", reqStr, ";response:", string(body)))
|
|
|
+ err = errors.New(response.ErrMsg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func GetAccessToken(isRefresh bool) (token string, err error) {
|
|
|
+ defer func() {
|
|
|
+ if err != nil {
|
|
|
+ go alarm_msg.SendAlarmMsg("获取上海的token失败,ERR:"+err.Error(), 3)
|
|
|
+
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ token, redisErr := utils.Rc.RedisString("SH_ACCESS_TOKEN")
|
|
|
+
|
|
|
+ if redisErr != nil || token == `` || isRefresh {
|
|
|
+ return refreshAccessToken()
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func refreshAccessToken() (token string, err error) {
|
|
|
+ defer func() {
|
|
|
+ if err != nil {
|
|
|
+ go alarm_msg.SendAlarmMsg("刷新上海的token失败;ERR:"+err.Error(), 3)
|
|
|
+
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ tokenInfo, tmpErr := getAccessToken()
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ token = tokenInfo.AccessToken
|
|
|
+
|
|
|
+ expireTime, err := time.ParseInLocation(utils.FormatDateTime, tokenInfo.ExpiredTime, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ go alarm_msg.SendAlarmMsg("获取同花顺的token失败;同花顺token截止日期转换失败,ERR:"+err.Error(), 3)
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ err = utils.Rc.Put("THS_SERVER_ACCESS_TOKEN", token, time.Duration(expireTime.Unix()-600)*time.Second)
|
|
|
+ if err != nil {
|
|
|
+ go alarm_msg.SendAlarmMsg("获取同花顺的token失败;同花顺token存入redis失败,ERR:"+err.Error(), 3)
|
|
|
+
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+type GetTokenResp struct {
|
|
|
+ ErrorCode int `json:"errorcode"`
|
|
|
+ ErrMsg string `json:"errmsg"`
|
|
|
+ Data TokenData `json:"data"`
|
|
|
+}
|
|
|
+
|
|
|
+type TokenData struct {
|
|
|
+ AccessToken string `json:"access_token"`
|
|
|
+
|
|
|
+ ExpiredTime string `json:"expired_time"`
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func getAccessToken() (tokenData TokenData, err error) {
|
|
|
+ defer func() {
|
|
|
+ if err != nil {
|
|
|
+ go alarm_msg.SendAlarmMsg("更新上海的token失败;ERR:"+err.Error(), 3)
|
|
|
+
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ getUrl := `https://quantapi.51ifind.com/api/v1/update_access_token`
|
|
|
+
|
|
|
+ req, _ := netHttp.NewRequest("GET", getUrl, nil)
|
|
|
+ req.Header.Add("Content-Type", "application/json")
|
|
|
+ req.Header.Add("refresh_token", refreshToken)
|
|
|
+
|
|
|
+ res, _ := netHttp.DefaultClient.Do(req)
|
|
|
+ defer res.Body.Close()
|
|
|
+ body, err := io.ReadAll(res.Body)
|
|
|
+ if err != nil {
|
|
|
+ err = errors.New("NewRequest Err:" + err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var tokenResp GetTokenResp
|
|
|
+ err = json.Unmarshal(body, &tokenResp)
|
|
|
+ if err != nil {
|
|
|
+ err = errors.New("Unmarshal Err:" + err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if tokenResp.ErrorCode != 0 {
|
|
|
+ err = errors.New("getAccessToken err:" + tokenResp.ErrMsg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ tokenData = tokenResp.Data
|
|
|
+ return
|
|
|
+}
|