package business import ( "encoding/json" "fmt" "github.com/shopspring/decimal" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go/types" "strings" "time" "wss-pool/config" "wss-pool/dictionary" "wss-pool/internal" "wss-pool/internal/data" "wss-pool/logging/applogger" "wss-pool/pkg/model/market" "wss-pool/pkg/model/stock" ) const ( MaxLimit int = 100 ) type SpotKlineResInfo struct { ID int64 `json:"id"` Open decimal.Decimal `json:"open"` Close decimal.Decimal `json:"close"` Low decimal.Decimal `json:"low"` High decimal.Decimal `json:"high"` Amount decimal.Decimal `json:"amount"` Vol decimal.Decimal `json:"vol"` Count decimal.Decimal `json:"count"` TradeTurnover string `json:"trade_turnover"` } type LinearlineResInfo struct { ID int64 `json:"id"` Open decimal.Decimal `json:"open"` Close decimal.Decimal `json:"close"` Low decimal.Decimal `json:"low"` High decimal.Decimal `json:"high"` Amount decimal.Decimal `json:"amount"` Vol decimal.Decimal `json:"vol"` Count decimal.Decimal `json:"count"` TradeTurnover decimal.Decimal `json:"trade_turnover"` } type LinearKlineRes struct { Ch string `json:"ch"` Status string `json:"status"` Ts int64 `json:"ts"` Data []LinearlineResInfo `json:"data"` } type SpotKlineWsRes struct { Ch string `json:"ch"` Status string `json:"status"` Ts int64 `json:"ts"` Tick SpotKlineResInfo `json:"tick"` } type SpotKlineRes struct { Ch string `json:"ch"` Status string `json:"status"` Ts int64 `json:"ts"` Data []SpotKlineResInfo `json:"data"` } type ContractKlineRes struct { Ch string `json:"ch"` Status string `json:"status"` Ts int64 `json:"ts"` Data []LinearlineResInfo `json:"data"` } type MarketTradeIDInfo struct { ID int64 `json:"id"` Ts int64 `json:"ts"` TradeId int64 `json:"trade-id"` Amount float64 `json:"amount"` Price float64 `json:"price"` Direction string `json:"direction"` TradeTurnover decimal.Decimal `json:"trade_turnover"` } type MarketTradeID struct { ID int64 `json:"id"` Ts int64 `json:"ts"` Data []MarketTradeIDInfo `json:"data"` } type MarketTrade struct { Ch string `json:"ch"` Status string `json:"status"` Ts int64 `json:"ts"` Data []MarketTradeID `json:"data"` } // UpdateStockKLSE Daily update of stock market list data【ws.eodhistoricaldata.com】 func UpdateStockKLSE() { var dataList []mongo.WriteModel yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02") before := time.Now().AddDate(0, 0, -2).Format("2006-01-02") filter := bson.M{"Country": "Malaysia", "YesterdayClose": bson.M{"$ne": ""}, "BeforeClose": bson.M{"$ne": ""}} dateList, err := data.MgoFind(data.StockList, filter) if err != nil { applogger.Error("MgoFind info err: %v", err) return } for _, value := range dateList.([]primitive.M) { code := TypeCheck(value["Code"]) yesterdayClose := TypeCheck(value["YesterdayClose"]) beforeClose := TypeCheck(value["BeforeClose"]) eodModel, _ := ShareData(code, "KLSE", yesterday, before) for _, eo := range eodModel { switch eo.Date { case yesterday: yesterdayClose = eo.Close.String() case before: beforeClose = eo.Close.String() default: } } applogger.Debug("data info:%v-----%v-----%v", code, yesterdayClose, beforeClose) filterD := bson.D{{"Code", bson.M{ "$eq": code, }}} updateData := bson.M{ "$set": bson.M{ "Code": code, "YesterdayClose": yesterdayClose, "BeforeClose": beforeClose}} models := mongo.NewUpdateOneModel().SetFilter(filterD).SetUpdate(updateData).SetUpsert(true) dataList = append(dataList, models) } applogger.Debug("update data info:%v", dataList) if len(dataList) > 0 { if err := data.MgoBulkWrite(data.StockList, dataList); err != nil { applogger.Error("MgoBulkWrite update err:%v", err) return } } } // U本位数据 func UpdateContractKline(period string) { for _, val := range dictionary.ContractCodeList { applogger.Info("UpdateContractKline") result := LinearKlineRes{} bodyStr, err := internal.HttpGet(fmt.Sprintf("https://api.hbdm.com/linear-swap-ex/market/history/kline?contract_code=%s&period=%s&size=2000", val, period)) applogger.Info(bodyStr) if err != nil { applogger.Error("Failed to query data:%v", err) continue } if err = json.Unmarshal([]byte(bodyStr), &result); err != nil { applogger.Error("Unmarshal err: %v---%v", err) continue } var dataList []mongo.WriteModel for _, eodValue := range result.Data { open := eodValue.Open.String() high := eodValue.High.String() low := eodValue.Low.String() close := eodValue.Close.String() vol := eodValue.Vol.String() amount := eodValue.Amount.String() count := eodValue.Count.String() tradeTurnover := eodValue.TradeTurnover.String() //applogger.Info("data: ", eodValue) filter := bson.M{"code": bson.M{"$eq": eodValue.ID}, "channel": bson.M{"$eq": result.Ch}} update := bson.D{{"$set", bson.D{ {"channel", result.Ch}, {"timestamp", eodValue.ID}, {"code", eodValue.ID}, {"open", open}, {"high", high}, {"low", low}, {"close", close}, {"vol", vol}, {"amount", amount}, {"count", count}, {"trade_turnover", tradeTurnover}, }}} models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true) dataList = append(dataList, models) } if len(dataList) > 0 { if err := data.MgoBulkWrite(data.GetContractKLineTableName(period), dataList); err != nil { applogger.Error("ContractKline MgoInsertMany err:%v", err) } } } } // 现货 func UpdateSpotKline(period string) { for _, val := range dictionary.Symbol { result := SpotKlineRes{} bodyStr, err := internal.HttpGet(fmt.Sprintf("https://api.huobi.pro/market/history/kline?period=%s&size=2000&symbol=%susdt", period, val)) if err != nil { applogger.Error("Failed to query data:%v", err) time.Sleep(2 * time.Second) continue } if err = json.Unmarshal([]byte(bodyStr), &result); err != nil { applogger.Error("Unmarshal err: %v---%v", err) continue } var dataList []mongo.WriteModel for _, eodValue := range result.Data { open := eodValue.Open.String() high := eodValue.High.String() low := eodValue.Low.String() close := eodValue.Close.String() vol := eodValue.Vol.String() amount := eodValue.Amount.String() count := eodValue.Count.String() applogger.Info("data: ", eodValue) filter := bson.M{"code": bson.M{"$eq": eodValue.ID}, "channel": bson.M{"$eq": result.Ch}} update := bson.D{{"$set", bson.D{ {"channel", result.Ch}, {"timestamp", eodValue.ID}, {"code", eodValue.ID}, {"open", open}, {"high", high}, {"low", low}, {"close", close}, {"vol", vol}, {"amount", amount}, {"count", count}, }}} models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true) dataList = append(dataList, models) } if len(dataList) > 0 { if err := data.MgoBulkWrite(data.GetStockKLineTableName(period), dataList); err != nil { applogger.Error(" SpotKline MgoInsertMany err:%v", err) } } } } func UpdatePriceKline(period string) { for _, val := range dictionary.ContractCodeList { result := SpotKlineRes{} bodyStr, err := internal.HttpGet(fmt.Sprintf("https://api.hbdm.com/index/market/history/linear_swap_mark_price_kline?contract_code=%s&period=%s&size=2000", val, period)) if err != nil { applogger.Error("Failed to query data:%v", err) time.Sleep(2 * time.Second) continue } if err = json.Unmarshal([]byte(bodyStr), &result); err != nil { applogger.Error("Unmarshal err: %v---%v", err) continue } var dataList []mongo.WriteModel for _, eodValue := range result.Data { open := eodValue.Open.String() high := eodValue.High.String() low := eodValue.Low.String() close := eodValue.Close.String() vol := eodValue.Vol.String() amount := eodValue.Amount.String() count := eodValue.Count.String() applogger.Info("data: ", eodValue) filter := bson.M{"code": bson.M{"$eq": eodValue.ID}, "channel": bson.M{"$eq": result.Ch}} update := bson.D{{"$set", bson.D{ {"channel", result.Ch}, {"timestamp", eodValue.ID}, {"code", eodValue.ID}, {"open", open}, {"high", high}, {"low", low}, {"close", close}, {"vol", vol}, {"amount", amount}, {"count", count}, {"trade_turnover", eodValue.TradeTurnover}, }}} models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true) dataList = append(dataList, models) } if len(dataList) > 0 { if err := data.MgoBulkWrite(data.GetContractPriceKLineTableName(period), dataList); err != nil { applogger.Error("PriceKline info err:%v", err) } } } } // 现货实时入库 func UpdateWsMgo(result market.SubscribeCandlestickResponse) { if result.Tick.Id <= 0 { applogger.Error("ws data is null %v", result) return } var dataList []mongo.WriteModel open := result.Tick.Open.String() high := result.Tick.High.String() low := result.Tick.Low.String() close := result.Tick.Close.String() vol := result.Tick.Vol.String() amount := result.Tick.Amount.String() //applogger.Info("data: ", result.Tick) filter := bson.M{"code": bson.M{"$eq": result.Tick.Id}, "channel": bson.M{"$eq": result.Channel}} update := bson.D{{"$set", bson.D{ {"channel", result.Channel}, {"timestamp", result.Tick.Id}, {"code", result.Tick.Id}, {"open", open}, {"high", high}, {"low", low}, {"close", close}, {"vol", vol}, {"amount", amount}, {"is_ba", result.Tick.IsBa}, {"count", result.Tick.Count}, }}} models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true) dataList = append(dataList, models) ch := strings.Split(result.Channel, ".") if len(ch) == 0 { applogger.Error("ch is null") return } period := ch[len(ch)-1] tableName := data.GetStockKLineTableName(period) if tableName == "" { applogger.Error("table info is null") return } if len(dataList) > 0 { if err := data.MgoBulkWrite(tableName, dataList); err != nil { applogger.Error("ContractKline MgoInsertMany err:%v", err) } } } // 现货实时入库 测试 func UpdateWsMgoTest(result market.SubscribeCandlestickResponse) { if result.Tick.Id <= 0 { applogger.Error("ws data is null %v", result) return } var dataList []mongo.WriteModel open := result.Tick.Open.String() high := result.Tick.High.String() low := result.Tick.Low.String() close := result.Tick.Close.String() vol := result.Tick.Vol.String() amount := result.Tick.Amount.String() applogger.Info("data: ", result.Tick) filter := bson.M{"code": bson.M{"$eq": result.Tick.Id}, "channel": bson.M{"$eq": result.Channel}} update := bson.D{{"$set", bson.D{ {"channel", result.Channel}, {"timestamp", result.Tick.Id}, {"code", result.Tick.Id}, {"open", open}, {"high", high}, {"low", low}, {"close", close}, {"vol", vol}, {"amount", amount}, {"is_ba", result.Tick.IsBa}, {"count", result.Tick.Count}, }}} models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true) dataList = append(dataList, models) ch := strings.Split(result.Channel, ".") if len(ch) == 0 { applogger.Error("ch is null") return } period := ch[len(ch)-1] tableName := data.GetStockKLineTestTableName(period) if tableName == "" { applogger.Error("table info is null") return } if len(dataList) > 0 { if err := data.MgoBulkWrite(tableName, dataList); err != nil { applogger.Error("ContractKline MgoInsertMany err:%v", err) } } } // 合约测试 func UpdateSubscribeCtKlineTest(result market.SubscribeCtKlineResponse) { if result.Tick.Id <= 0 { applogger.Error("ws data is null %v", result) return } var dataList []mongo.WriteModel open := result.Tick.Open.String() high := result.Tick.High.String() low := result.Tick.Low.String() close := result.Tick.Close.String() vol := result.Tick.Vol.String() amount := result.Tick.Amount.String() applogger.Info("data: ", result.Tick) filter := bson.M{"code": bson.M{"$eq": result.Tick.Id}, "channel": bson.M{"$eq": result.Channel}} update := bson.D{{"$set", bson.D{ {"channel", result.Channel}, {"timestamp", result.Tick.Id}, {"code", result.Tick.Id}, {"open", open}, {"high", high}, {"low", low}, {"close", close}, {"vol", vol}, {"amount", amount}, {"count", result.Tick.Count.String()}, {"trade_turnover", result.Tick.Rrade_Turnover.String()}, }}} models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true) dataList = append(dataList, models) ch := strings.Split(result.Channel, ".") if len(ch) == 0 { applogger.Error("ch is null") return } period := ch[len(ch)-1] tableName := data.GetContractKLineTestTableName(period) if tableName == "" { applogger.Error("table info is null") return } if len(dataList) > 0 { if err := data.MgoBulkWrite(tableName, dataList); err != nil { applogger.Error("ContractKline MgoInsertMany err:%v", err) } } } // 合约实时入库 func UpdateSubscribeCtKline(result market.SubscribeCtKlineResponse) { if result.Tick.Id <= 0 { applogger.Error("ws data is null %v", result) return } //fmt.Println("kline ",result) var dataList []mongo.WriteModel open := result.Tick.Open.String() high := result.Tick.High.String() low := result.Tick.Low.String() close := result.Tick.Close.String() vol := result.Tick.Vol.String() amount := result.Tick.Amount.String() //applogger.Info("data: ", result.Tick) filter := bson.M{"code": bson.M{"$eq": result.Tick.Id}, "channel": bson.M{"$eq": result.Channel}} update := bson.D{{"$set", bson.D{ {"channel", result.Channel}, {"timestamp", result.Tick.Id}, {"code", result.Tick.Id}, {"open", open}, {"high", high}, {"low", low}, {"close", close}, {"vol", vol}, {"amount", amount}, {"count", result.Tick.Count.String()}, {"trade_turnover", result.Tick.Rrade_Turnover.String()}, }}} models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true) dataList = append(dataList, models) ch := strings.Split(result.Channel, ".") if len(ch) == 0 { applogger.Error("ch is null") return } period := ch[len(ch)-1] tableName := data.GetContractKLineTableName(period) if tableName == "" { applogger.Error("table info is null") return } if len(dataList) > 0 { if err := data.MgoBulkWrite(tableName, dataList); err != nil { applogger.Error("ContractKline MgoInsertMany err:%v", err) } } } // ShareData Obtaining the closing price of Malaysian stocks through time【ws.eodhistoricaldata.com】 func ShareData(code, exchange, yesterday, before string) ([]stock.EodTimeMessage, error) { model := fmt.Sprintf("%v.%v", code, exchange) from := before to := yesterday urlHttp := fmt.Sprintf("https://%v/api/eod/%v?api_token=%v&fmt=json&period=D&order=d&from=%v&to=%v", config.Config.ShareGather.FinancialHost, model, config.Config.ShareGather.FinancialKey, from, to) //applogger.Debug("UrlHttp info: %v", urlHttp) bodyStr, err := internal.HttpGet(urlHttp) if err != nil { applogger.Error("Failed to query data:%v", err) return nil, err } var eodModel []stock.EodTimeMessage if err = json.Unmarshal([]byte(bodyStr), &eodModel); err != nil { applogger.Error("Unmarshal err: %v---%v", code, err) return nil, err } return eodModel, nil } // 获取给定时间段内该代码的收盘价 func PreviousClose(code string) (stock.PreviousCloseResponse, error) { var eodModel stock.PreviousCloseResponse url := fmt.Sprintf("https://%s/v2/aggs/ticker/%s/prev?adjusted=true&apiKey=%s", config.Config.ShareGather.PolygonHost, code, config.Config.ShareGather.PolygonKey) applogger.Debug("UrlHttp info: %v", url) bodyStr, err := internal.HttpGet(url) if err != nil { applogger.Error("Failed to query data:%v", err) return eodModel, err } if err = json.Unmarshal([]byte(bodyStr), &eodModel); err != nil { applogger.Error("Unmarshal err: %v---%v", code, err) return eodModel, err } return eodModel, nil } // 通过交易查询股票对应的交易所 func TradesTape(code string) (stock.TypeTradesResponse, error) { var eodModel stock.TypeTradesResponse url := fmt.Sprintf("https://%s/v3/trades/%s?apiKey=%s&limit=1", config.Config.ShareGather.PolygonHost, code, config.Config.ShareGather.PolygonKey) applogger.Debug("UrlHttp info: %v", url) bodyStr, err := internal.HttpGet(url) if err != nil { applogger.Error("Failed to query data:%v", err) return eodModel, err } if err = json.Unmarshal([]byte(bodyStr), &eodModel); err != nil { applogger.Error("Unmarshal err: %v---%v", code, err) return eodModel, err } return eodModel, nil } // TypeCheck Character determination func TypeCheck(m interface{}) string { switch m.(type) { case types.Nil: return "" case string: return m.(string) default: return "" } } // UpdateStockKLSEBak 马股列表闭盘数据更新--已废弃 func UpdateStockKLSEBak() { var dataList []mongo.WriteModel yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02") before := time.Now().AddDate(0, 0, -2).Format("2006-01-02") // TODO: 更改为从mongoDB中查数据源 var shareModel []stock.StockShare url := fmt.Sprintf("https://%v/api/exchange-symbol-list/KLSE?api_token=%v&fmt=json", config.Config.ShareGather.FinancialHost, config.Config.ShareGather.FinancialKey) applogger.Debug("url info:%v", url) bodyStr, err := internal.HttpGet(url) if err != nil { applogger.Error("Failed to query data:%v", err) return } if err := json.Unmarshal([]byte(bodyStr), &shareModel); err != nil { applogger.Error("Failed to parse stock list information:%v", err) return } // 赋值更新的数据 for _, value := range shareModel { applogger.Debug("share types info: %v", value) model := fmt.Sprintf("%v.KLSE", value.Code) from := before to := yesterday urlHttp := fmt.Sprintf("https://%v/api/eod/%v?api_token=%v&fmt=json&period=D&order=d&from=%v&to=%v", config.Config.ShareGather.FinancialHost, model, config.Config.ShareGather.FinancialKey, from, to) applogger.Debug("UrlHttp info: %v", urlHttp) bodyStr, err = internal.HttpGet(urlHttp) if err != nil { applogger.Error("Failed to query data:%v", err) } var eodModel []stock.EodTimeMessage if err = json.Unmarshal([]byte(bodyStr), &eodModel); err != nil { applogger.Error("Unmarshal err: %v---%v", value.Code, err) } for _, eo := range eodModel { switch eo.Date { case yesterday: value.YesterdayClose = eo.Close.String() case before: value.BeforeClose = eo.Close.String() default: } } filter := bson.D{{"Code", bson.M{ "$eq": value.Code, }}} update := bson.D{{"$set", bson.D{ {"Code", value.Code}, {"Name", value.Name}, {"Country", value.Country}, {"Exchange", value.Exchange}, {"Currency", value.Currency}, {"Type", value.Type}, {"Isin", value.Isin}, {"YesterdayClose", value.YesterdayClose}, {"BeforeClose", value.BeforeClose}}}} models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true) dataList = append(dataList, models) } applogger.Debug("update data info:%v", dataList) if len(dataList) > 0 { if err := data.MgoBulkWrite(data.StockList, dataList); err != nil { applogger.Error("MgoBulkWrite update err:%v", err) return } } }