|
|
@@ -139,7 +139,7 @@ type QueryTSDataRsp struct {
|
|
|
TradeDate string `json:"tradeDate"` // 交易日
|
|
|
StartTime time.Time `json:"startTime"` // 开始时间
|
|
|
EndTime time.Time `json:"endTime"` // 结束时间
|
|
|
- PreSettle float32 `json:"preSettle"` // 昨结
|
|
|
+ PreSettle float64 `json:"preSettle"` // 昨结
|
|
|
HistoryDatas []HistoryData `json:"historyDatas"` // 历史数据
|
|
|
}
|
|
|
|
|
|
@@ -163,6 +163,14 @@ func QueryTSData(c *gin.Context) {
|
|
|
}
|
|
|
|
|
|
// FIXME: - 一些不常变化的数据(如市场信息、商品信息等)应缓存到Redis中, 或缓存到服务内存
|
|
|
+ // 获取商品信息
|
|
|
+ goods, err := models.GetGoodsByGoodsCode(req.GoodsCode)
|
|
|
+ if goods == nil {
|
|
|
+ logger.GetLogger().Errorf("QueryTSData failed: %s", err.Error())
|
|
|
+ appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 获取市场
|
|
|
market, err := models.GetMarketByGoodsCode(req.GoodsCode)
|
|
|
if err != nil {
|
|
|
logger.GetLogger().Errorf("QueryTSData failed: %s", err.Error())
|
|
|
@@ -190,13 +198,13 @@ func QueryTSData(c *gin.Context) {
|
|
|
// 通道交易外部市场开休市计划表 - QuoteSourceGroupRunStep; 其它市场的 - MarketRunStepDetail
|
|
|
if market.Trademode == 15 {
|
|
|
// 外部市场
|
|
|
- sourceRunSteps, err := models.FindQuoteSourceGroupRunStepsByMarket(*market)
|
|
|
+ sourceRunSteps, err := models.FindQuoteSourceGroupRunSteps(*goods)
|
|
|
if err != nil {
|
|
|
logger.GetLogger().Errorf("QueryTSData failed: %s", err.Error())
|
|
|
appG.Response(http.StatusBadRequest, e.ERROR_GET_RUNSTEP_FAILED, nil)
|
|
|
return
|
|
|
}
|
|
|
- for v := range sourceRunSteps {
|
|
|
+ for _, v := range sourceRunSteps {
|
|
|
// struct -> json
|
|
|
if jsonBytes, err := json.Marshal(v); err == nil {
|
|
|
// json -> struct
|
|
|
@@ -227,13 +235,25 @@ func QueryTSData(c *gin.Context) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 获取商品信息
|
|
|
- goods, err := models.GetGoodsByGoodsCode(req.GoodsCode)
|
|
|
- if goods == nil {
|
|
|
+ // 获取目标商品的盘面信息
|
|
|
+ quoteDays, err := models.GetQuoteDays("'" + goods.Outgoodscode + "'")
|
|
|
+ if err != nil {
|
|
|
logger.GetLogger().Errorf("QueryTSData failed: %s", err.Error())
|
|
|
appG.Response(http.StatusBadRequest, e.ERROR_GET_GOODS_FAILED, nil)
|
|
|
return
|
|
|
}
|
|
|
+ var preSettle float64
|
|
|
+ var preSettleInt int
|
|
|
+ if len(quoteDays) > 0 {
|
|
|
+ if quoteDays[0].Presettle != 0 {
|
|
|
+ preSettleInt = int(quoteDays[0].Presettle)
|
|
|
+ preSettle = utils.IntToFloat64(preSettleInt, int(goods.Decimalplace))
|
|
|
+ }
|
|
|
+ if preSettle == 0 && quoteDays[0].Preclose != 0 {
|
|
|
+ preSettleInt = int(quoteDays[0].Preclose)
|
|
|
+ preSettle = utils.IntToFloat64(preSettleInt, int(goods.Decimalplace))
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// 构建返回数据
|
|
|
queryTSDataRsp := QueryTSDataRsp{
|
|
|
@@ -241,6 +261,7 @@ func QueryTSData(c *gin.Context) {
|
|
|
OutGoodsCode: goods.Outgoodscode,
|
|
|
TradeDate: marketRun.Tradedate,
|
|
|
DecimalPlace: int(goods.Decimalplace),
|
|
|
+ PreSettle: preSettle,
|
|
|
}
|
|
|
|
|
|
// 构建分时图可直接使用的开休市数据
|
|
|
@@ -253,6 +274,7 @@ func QueryTSData(c *gin.Context) {
|
|
|
appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
|
|
|
return
|
|
|
}
|
|
|
+ // !!!开休市计划明细
|
|
|
curWeekRunSteps := make([]map[string]interface{}, 0)
|
|
|
for _, v := range runSteps {
|
|
|
tradeWeekDay := int(v["tradeweekday"].(float64))
|
|
|
@@ -290,7 +312,7 @@ func QueryTSData(c *gin.Context) {
|
|
|
duration, _ := time.ParseDuration(fmt.Sprintf("%dh", endInterval*24))
|
|
|
queryTSDataRsp.EndTime = queryTSDataRsp.EndTime.Add(duration)
|
|
|
}
|
|
|
- fmt.Printf("开始时间:%s 结束时间:%s\n", queryTSDataRsp.StartTime.Format(timeFormat), queryTSDataRsp.EndTime.Format(timeFormat))
|
|
|
+ // fmt.Printf("开始时间:%s 结束时间:%s\n", queryTSDataRsp.StartTime.Format(timeFormat), queryTSDataRsp.EndTime.Format(timeFormat))
|
|
|
|
|
|
// 获取目标时间段的历史数据
|
|
|
// 这里要注意:由于交易库和行情库由于GoodsCode大小写不一定对得上,所以在使用交易库的商品查询行情数据时间,都要使用OutGoodsCode字段
|
|
|
@@ -301,8 +323,8 @@ func QueryTSData(c *gin.Context) {
|
|
|
return
|
|
|
}
|
|
|
// ==================== 补数据(补休市数据和缺少的数据)====================
|
|
|
- // 补数据第一步:如果第一数据不是开始时间的,需要补数据
|
|
|
if len(cycleDatas) > 0 {
|
|
|
+ // 补数据第一步:如果第一数据不是开始时间的,需要补数据
|
|
|
sources := time.Unix(int64(cycleDatas[0].ST), 0)
|
|
|
diff := sources.Sub(queryTSDataRsp.StartTime)
|
|
|
if diff.Minutes() > 0 {
|
|
|
@@ -322,6 +344,7 @@ func QueryTSData(c *gin.Context) {
|
|
|
SP: cycleDatas[0].SP,
|
|
|
ST: st,
|
|
|
SST: stt,
|
|
|
+ FI: true,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
@@ -329,19 +352,23 @@ func QueryTSData(c *gin.Context) {
|
|
|
sort.Slice(cycleDatas, func(i int, j int) bool {
|
|
|
return cycleDatas[i].ST < cycleDatas[j].ST
|
|
|
})
|
|
|
- }
|
|
|
- // 补数据第二步:按尾部的时间(当前服务器时间或最后休市时间)进行全补
|
|
|
- if len(cycleDatas) > 0 {
|
|
|
+
|
|
|
+ // 补数据第二步:按尾部的时间(当前服务器时间或最后休市时间)进行全补
|
|
|
+ // 获取服务器时间
|
|
|
s, _ := models.GetServerTime()
|
|
|
- endTime, _ := time.ParseInLocation("2006/01/02 15:04:05", *s, time.Local)
|
|
|
+ endTime, err := time.ParseInLocation("2006-01-02T15:04:05Z", *s, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ logger.GetLogger().Errorf("QueryTSData failed: %s", err.Error())
|
|
|
+ appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
|
|
|
+ return
|
|
|
+ }
|
|
|
if endTime.After(queryTSDataRsp.EndTime) {
|
|
|
endTime = queryTSDataRsp.EndTime
|
|
|
}
|
|
|
|
|
|
- // 判断是否需要补数据,与上一条数据的间距不是一分钟
|
|
|
index := len(cycleDatas) - 1
|
|
|
- sources := time.Unix(int64(cycleDatas[index].ST), 0)
|
|
|
- diff := sources.Sub(endTime)
|
|
|
+ sources = time.Unix(int64(cycleDatas[index].ST), 0)
|
|
|
+ diff = endTime.Sub(sources)
|
|
|
if diff.Minutes() > 0 {
|
|
|
minute := int(diff.Minutes())
|
|
|
for i := 0; i < minute; i++ {
|
|
|
@@ -359,6 +386,7 @@ func QueryTSData(c *gin.Context) {
|
|
|
SP: cycleDatas[index].SP,
|
|
|
ST: st,
|
|
|
SST: stt,
|
|
|
+ FI: true,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
@@ -366,8 +394,135 @@ func QueryTSData(c *gin.Context) {
|
|
|
sort.Slice(cycleDatas, func(i int, j int) bool {
|
|
|
return cycleDatas[i].ST < cycleDatas[j].ST
|
|
|
})
|
|
|
+
|
|
|
+ // 补数据第三步:补中间数据
|
|
|
+ fillDatas := make([]models.CycleData, 0)
|
|
|
+ for i := range cycleDatas {
|
|
|
+ // 第一条记录跳过
|
|
|
+ if i == 0 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ current := time.Unix(int64(cycleDatas[i].ST), 0)
|
|
|
+ prev := time.Unix(int64(cycleDatas[i-1].ST), 0)
|
|
|
+ diff := current.Sub(prev)
|
|
|
+ if diff.Minutes() > 0 {
|
|
|
+ minute := int(diff.Minutes())
|
|
|
+ // 判断是否需要补数据,与上一条数据的间距不是一分钟
|
|
|
+ if minute > 1 {
|
|
|
+ for j := 1; j < minute; j++ {
|
|
|
+ st := cycleDatas[i-1].ST + j*60
|
|
|
+ stt := time.Unix(int64(st), 0).Format("2006-01-02 15:04:05")
|
|
|
+ fillDatas = append(fillDatas, models.CycleData{
|
|
|
+ GC: cycleDatas[i-1].GC,
|
|
|
+ Open: cycleDatas[i-1].Open,
|
|
|
+ High: cycleDatas[i-1].High,
|
|
|
+ Low: cycleDatas[i-1].Low,
|
|
|
+ Close: cycleDatas[i-1].Close,
|
|
|
+ TV: cycleDatas[i-1].TV,
|
|
|
+ TT: cycleDatas[i-1].TT,
|
|
|
+ HV: cycleDatas[i-1].HV,
|
|
|
+ SP: cycleDatas[i-1].SP,
|
|
|
+ ST: st,
|
|
|
+ SST: stt,
|
|
|
+ FI: true,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 加入到源数据
|
|
|
+ cycleDatas = append(cycleDatas, fillDatas...)
|
|
|
+ // 接时间戳排序
|
|
|
+ sort.Slice(cycleDatas, func(i int, j int) bool {
|
|
|
+ return cycleDatas[i].ST < cycleDatas[j].ST
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // TODO: - 下面这块操作需求确认
|
|
|
+ // 如果查询结果是空数据,则使用昨结价补到服务器时间(或最后休市时间)
|
|
|
+ // 获取服务器时间
|
|
|
+ s, _ := models.GetServerTime()
|
|
|
+ endTime, err := time.ParseInLocation("2006-01-02T15:04:05Z", *s, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ logger.GetLogger().Errorf("QueryTSData failed: %s", err.Error())
|
|
|
+ appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if endTime.After(queryTSDataRsp.EndTime) {
|
|
|
+ endTime = queryTSDataRsp.EndTime
|
|
|
+ }
|
|
|
+
|
|
|
+ diff := endTime.Sub(queryTSDataRsp.StartTime)
|
|
|
+ minute := int(diff.Minutes())
|
|
|
+ for i := 0; i < minute; i++ {
|
|
|
+ st := int(queryTSDataRsp.StartTime.Unix()) + i*60
|
|
|
+ stt := time.Unix(int64(st), 0).Format("2006-01-02 15:04:05")
|
|
|
+ cycleDatas = append(cycleDatas, models.CycleData{
|
|
|
+ GC: queryTSDataRsp.GoodsCode,
|
|
|
+ Open: preSettleInt,
|
|
|
+ High: preSettleInt,
|
|
|
+ Low: preSettleInt,
|
|
|
+ Close: preSettleInt,
|
|
|
+ TV: 0,
|
|
|
+ TT: 0,
|
|
|
+ HV: 0,
|
|
|
+ SP: 0,
|
|
|
+ ST: st,
|
|
|
+ SST: stt,
|
|
|
+ FI: true,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ // 接时间戳排序
|
|
|
+ sort.Slice(cycleDatas, func(i int, j int) bool {
|
|
|
+ return cycleDatas[i].ST < cycleDatas[j].ST
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 补数据第四步:清除掉开市计划外的数据
|
|
|
+ // 先计算出每条计划明细的真正开始与结束时间
|
|
|
+ for _, v := range curWeekRunSteps {
|
|
|
+ // 开始时间
|
|
|
+ startInterval := getTradeDay(int(v["tradeweekday"].(float64)), int(v["startweekday"].(float64)))
|
|
|
+ v["start"], _ = time.ParseInLocation(timeFormat, fmt.Sprintf("%s %s", marketRun.Tradedate, v["starttime"].(string)), time.Local)
|
|
|
+ if startInterval != 0 {
|
|
|
+ duration, _ := time.ParseDuration(fmt.Sprintf("%dh", startInterval*24))
|
|
|
+ v["start"] = v["start"].(time.Time).Add(duration)
|
|
|
+ }
|
|
|
+ // 结束时间
|
|
|
+ endInterval := getTradeDay(int(v["tradeweekday"].(float64)), int(v["endweekday"].(float64)))
|
|
|
+ v["end"], _ = time.ParseInLocation(timeFormat, fmt.Sprintf("%s %s", marketRun.Tradedate, v["endtime"].(string)), time.Local)
|
|
|
+ if endInterval != 0 {
|
|
|
+ duration, _ := time.ParseDuration(fmt.Sprintf("%dh", endInterval*24))
|
|
|
+ v["end"] = v["end"].(time.Time).Add(duration)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 最终返回的历史数据
|
|
|
+ historyDatas := make([]HistoryData, 0)
|
|
|
+ for _, cycleData := range cycleDatas {
|
|
|
+ needAdd := false
|
|
|
+ for _, runStep := range curWeekRunSteps {
|
|
|
+ // 判断是否在开市计划内
|
|
|
+ if cycleData.ST >= int(runStep["start"].(time.Time).Unix()) && cycleData.ST <= int(runStep["end"].(time.Time).Unix()) {
|
|
|
+ needAdd = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if needAdd {
|
|
|
+ historyDatas = append(historyDatas, HistoryData{
|
|
|
+ Opened: utils.IntToFloat64(cycleData.Open, int(goods.Decimalplace)),
|
|
|
+ Highest: utils.IntToFloat64(cycleData.High, int(goods.Decimalplace)),
|
|
|
+ Lowest: utils.IntToFloat64(cycleData.Low, int(goods.Decimalplace)),
|
|
|
+ Closed: utils.IntToFloat64(cycleData.Close, int(goods.Decimalplace)),
|
|
|
+ TotleVolume: cycleData.TV,
|
|
|
+ TotleTurnover: float64(cycleData.TT),
|
|
|
+ HoldVolume: cycleData.HV,
|
|
|
+ Settle: utils.IntToFloat64(cycleData.SP, int(goods.Decimalplace)),
|
|
|
+ TimeStamp: time.Unix(int64(cycleData.ST), 0),
|
|
|
+ IsFill: cycleData.FI,
|
|
|
+ })
|
|
|
+ }
|
|
|
}
|
|
|
- // 补数据第三步:补中间数据
|
|
|
+ queryTSDataRsp.HistoryDatas = historyDatas
|
|
|
|
|
|
// 查询成功
|
|
|
logger.GetLogger().Debugln("QueryTSData successed: %v", queryTSDataRsp)
|