You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

639 lines
20 KiB

2 months ago
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
}
}
}