package marketwsscliert import ( "encoding/json" "fmt" "github.com/google/uuid" "github.com/gorilla/websocket" "github.com/shopspring/decimal" "io/ioutil" "log" "math/rand" "net/http" "testing" "time" "wss-pool/cmd/common" "wss-pool/internal" "wss-pool/logging/applogger" "wss-pool/pkg/model" ) type ConstructParameters struct { Trace string `json:"trace"` Data struct { Code string `json:"code"` KlineType int `json:"kline_type"` KlineTimestampEnd int `json:"kline_timestamp_end"` QueryKlineNum int `json:"query_kline_num"` AdjustType int `json:"adjust_type"` } `json:"data"` } type KlinePostReturnStruct struct { Ret int `json:"ret"` Msg string `json:"msg"` Trace string `json:"trace"` Data struct { KlineList []struct { Code string `json:"code"` KlineType int `json:"kline_type"` KlineData []struct { Timestamp string `json:"timestamp"` OpenPrice string `json:"open_price"` ClosePrice string `json:"close_price"` HighPrice string `json:"high_price"` LowPrice string `json:"low_price"` Volume string `json:"volume"` Turnover string `json:"turnover"` } `json:"kline_data"` } `json:"kline_list"` } `json:"data"` } type KlineGetReturnStruct struct { Ret int `json:"ret"` Msg string `json:"msg"` Trace string `json:"trace"` Data struct { Code string `json:"code"` KlineType int `json:"kline_type"` KlineList []struct { Timestamp string `json:"timestamp"` OpenPrice string `json:"open_price"` ClosePrice string `json:"close_price"` HighPrice string `json:"high_price"` LowPrice string `json:"low_price"` Volume string `json:"volume"` Turnover string `json:"turnover"` } `json:"kline_list"` } `json:"data"` } type Symbol struct { Code string `json:"code"` DepthLevel int `json:"depth_level"` } type DataList struct { SymbolList []Symbol `json:"symbol_list"` } type Request struct { CmdID int `json:"cmd_id"` SeqID int `json:"seq_id"` Trace string `json:"trace"` Data DataList `json:"data"` } type OrderBookOrTradeTick struct { Trace string `json:"trace"` Data struct { SymbolList []SymbolList `json:"symbol_list"` } `json:"data"` } type SymbolList struct { Code string `json:"code"` } type DepthTradeReturnStruct struct { Msg string `json:"msg"` Trace string `json:"trace"` Data struct { TickList []struct { Code string `json:"code"` Seq string `json:"seq"` TickTime string `json:"tick_time"` Bids []struct { Price string `json:"price"` Volume string `json:"volume"` } `json:"bids"` Asks []struct { Price string `json:"price"` Volume string `json:"volume"` } `json:"asks"` } `json:"tick_list"` } `json:"data"` } type TradeReturnStruct struct { Msg string `json:"msg"` Trace string `json:"trace"` Data struct { TickList []struct { Code string `json:"code"` Seq string `json:"seq"` TickTime string `json:"tick_time"` Price string `json:"price"` Volume string `json:"volume"` Turnover string `json:"turnover"` } `json:"tick_list"` } `json:"data"` } type Results struct { CmdID int `json:"cmd_id"` Data struct { Code string `json:"code"` Seq string `json:"seq"` TickTime string `json:"tick_time"` Bids []struct { Price string `json:"price"` Volume string `json:"volume"` } `json:"bids"` Asks []struct { Price string `json:"price"` Volume string `json:"volume"` } `json:"asks"` } `json:"data"` } type ResultsTrade struct { CmdID int `json:"cmd_id"` Data struct { Code string `json:"code"` Seq string `json:"seq"` TickTime string `json:"tick_time"` Price string `json:"price"` Volume string `json:"volume"` Turnover string `json:"turnover"` TradeDirection int `json:"trade_direction"` } `json:"data"` } func GenerateParameters(trace, code string, kline_type, query_kline_num int) string { queryStr := fmt.Sprintf("{'trace':'%v','data':{'data_list':[{'code':'%v','kline_type':%v,'kline_timestamp_end':0,'query_kline_num':%v,'adjust_type':0}]}}", trace, code, kline_type, query_kline_num) return queryStr } // GenerateRandomFloat64 在min和max之间生成一个随机浮点数 func GenerateRandomFloat64(min, max float64) float64 { return min + rand.Float64()*(max-min) } // 将两个时间区间划分成指定数量的等分区间 func TestTime(t *testing.T) { // 假设这是从MongoDB获取的时间戳(以秒为单位) timestamp := int64(1735064100000) // 将时间戳转换为time.Time类型 t1 := time.Unix(timestamp, 0) // 格式化时间 formattedTime := t1.Format(time.RFC3339) fmt.Println("时间戳:", timestamp) fmt.Println("转换后的时间:", formattedTime) return layoutStart := "2024-12-17 17:00:00" layoutEnd := "2024-12-17 17:09:00" startT := common.TimeStringToTime(layoutStart) endT := common.TimeStringToTime(layoutEnd) applogger.Debug("start:%v,end:%v", startT, endT) startF := 2658.33000 endF := 2652.33000 numIntervals := 5 msgTime := DivideTimeInterval(startT, endT, numIntervals) msgFloat := DivideFloatInterval(startF, endF, numIntervals) var msgTF = make(map[int]string) // 打印每个区间的时间 for i, mt := range msgTime { mf, ok := msgFloat[i] if ok { msgTF[i] = fmt.Sprintf("%v,%v", mt, mf) applogger.Debug("msgTF:%v,%v", i, msgTF[i]) } } } func TestGetKline(t *testing.T) { percentage := decimal.RequireFromString("1").Add(decimal.RequireFromString("1").Div(decimal.RequireFromString("10000"))) startValue := 2652.33000 // 起点值 2652.33000 938.20000 0.58464 endValue := 2658.33000 // 结束值 2658.33000 958.20000 0.68464 maxValue := decimal.NewFromFloat(endValue).Mul(percentage).InexactFloat64() var currentValue = startValue var currentValueS float64 for { if currentValue <= endValue { currentValue *= percentage.InexactFloat64() } else { min := currentValue currentValueS = RandomBetween(min, maxValue) } applogger.Debug("currentValue:%v,endSub:%v,Max:%v", currentValue, currentValueS, maxValue) time.Sleep(1 * time.Second) } //for currentValue := startValue; currentValue <= endValue; currentValue *= percentage.InexactFloat64() { // applogger.Debug("currentValue:", currentValue) //} } func TestGetKlineS(t *testing.T) { percentage := decimal.RequireFromString("1").Add(decimal.RequireFromString("1").Div(decimal.RequireFromString("10000"))) startValue := 2658.33000 // 起点值 endValue := 2652.33000 // 结束值 maxValue := decimal.NewFromFloat(endValue).Mul(percentage).InexactFloat64() var currentValue = startValue var currentValueS float64 for { if currentValue <= startValue { currentValue /= percentage.InexactFloat64() // 变化值小于结束值 if currentValue <= endValue { currentValueS = RandomBetween(endValue, maxValue) } } applogger.Debug("currentValue:%v,endSub:%v,Max:%v", currentValue, currentValueS, maxValue) time.Sleep(1 * time.Second) } } func TestMainList(t *testing.T) { url := "wss://quote.tradeswitcher.com/quote-b-ws-api?token=bf8f33c446c4494286eccaa57a2e6fac-c-app" c, _, err := websocket.DefaultDialer.Dial(url, nil) if err != nil { fmt.Println("dial:", err) } defer c.Close() // Send heartbeat every 10 seconds go func() { for range time.NewTicker(10 * time.Second).C { req := Request{ CmdID: 22000, SeqID: 123, Trace: "3380a7a-3e1f-c3a5-5ee3-9e5be0ec8c241692805462", Data: DataList{}, } messageBytes, err := json.Marshal(req) if err != nil { fmt.Println("json.Marshal error:", err) return } applogger.Debug("req data:", string(messageBytes)) err = c.WriteMessage(websocket.TextMessage, messageBytes) if err != nil { fmt.Println("write:", err) } } }() req := Request{ CmdID: 22002, SeqID: 123, Trace: uuid.New().String(), Data: DataList{SymbolList: []Symbol{ //{"GOLD", 5}, //{"AAPL.US", 5}, //{"700.HK", 5}, //{"GOLD", 1}, //{"Silver", 1}, {"GOLD", 1}, //{"Silver", 1}, }}, //Data: dataList, } messageBytes, err := json.Marshal(req) if err != nil { applogger.Debug("json.Marshal error:", err) return } applogger.Debug("req data:", string(messageBytes)) err = c.WriteMessage(websocket.TextMessage, messageBytes) if err != nil { fmt.Println("write:", err) } rece_count := 0 for { _, message, err := c.ReadMessage() if err != nil { applogger.Debug("read:", err) break } else { var messageToJson Results if err = json.Unmarshal(message, &messageToJson); err != nil { applogger.Error("SendAllClientTradeSwitcher err:%v", err) } switch messageToJson.CmdID { case 22001: // 心跳 // {"ret":200,"msg":"ok","cmd_id":22001,"seq_id":123,"trace":"3380a7a-3e1f-c3a5-5ee3-9e5be0ec8c241692805462"} applogger.Info("Heartbeat results:%v", string(message)) case 22999: // 数据解析 // {"cmd_id":22999,"data":{"code":"EURUSD","seq":"114101723","tick_time":"1732168153591","bids":[{"price":"1.05478","volume":"100000.00"}],"asks":[{"price":"1.05479","volume":"100000.00"}]}} applogger.Info("Received message:%v", string(message)) default: applogger.Info("Received message err:%v", string(message)) } } rece_count++ if rece_count%10000 == 0 { fmt.Println("count:", rece_count, " Received message:", string(message)) } } } func TestMainLists(t *testing.T) { url := "wss://quote.tradeswitcher.com/quote-b-ws-api?token=bf8f33c446c4494286eccaa57a2e6fac-c-app" c, _, err := websocket.DefaultDialer.Dial(url, nil) if err != nil { fmt.Println("dial:", err) } defer c.Close() // Send heartbeat every 10 seconds go func() { for range time.NewTicker(10 * time.Second).C { req := Request{ CmdID: 22000, SeqID: 123456, Trace: "3380a7a-3e1f-c3a5-5ee3-9e5be0ec8c241692805462787878", Data: DataList{}, } messageBytes, err := json.Marshal(req) if err != nil { fmt.Println("json.Marshal error:", err) return } applogger.Debug("req data:", string(messageBytes)) err = c.WriteMessage(websocket.TextMessage, messageBytes) if err != nil { fmt.Println("write:", err) } } }() req := Request{ CmdID: 22004, SeqID: 123456, Trace: uuid.New().String(), Data: DataList{SymbolList: []Symbol{ //{"GOLD", 5}, //{"AAPL.US", 5}, //{"700.HK", 5}, //{"GOLD", 1}, //{"Silver", 1}, {"GOLD", 1}, //{"Silver", 1}, }}, //Data: dataList, } messageBytes, err := json.Marshal(req) if err != nil { fmt.Println("json.Marshal error:", err) return } err = c.WriteMessage(websocket.TextMessage, messageBytes) if err != nil { fmt.Println("write:", err) } rece_count := 0 for { _, msg, err := c.ReadMessage() if err != nil { fmt.Println("read:", err) break } else { var messageToJson ResultsTrade if err = json.Unmarshal(msg, &messageToJson); err != nil { applogger.Error("json.Unmarshal error:%v", err) continue } switch messageToJson.CmdID { case 22001: // 处理心跳 // {"ret":200,"msg":"ok","cmd_id":22001,"seq_id":123456,"trace":"3380a7a-3e1f-c3a5-5ee3-9e5be0ec8c241692805462787878"} applogger.Debug("Heartbeat results:%v", string(msg)) case 22998: // 处理订阅数据 // {"cmd_id":22998,"data":{"code":"XAUUSD","seq":"65087341","tick_time":"1732267727182","price":"2694.84","volume":"95.00","turnover":"0.00","trade_direction":0}} code := model.Check_Code[messageToJson.Data.Code] if len(code) == 0 { code = messageToJson.Data.Code } tradeMsg := &[]model.ForexTrade{ { Ev: "T", Code: code, Seq: messageToJson.Data.Seq, TickTime: messageToJson.Data.TickTime, Price: messageToJson.Data.Price, Volume: messageToJson.Data.Volume, Turnover: messageToJson.Data.Turnover, TradeDirection: messageToJson.Data.TradeDirection, }, } msgStr, err := json.Marshal(tradeMsg) if err != nil { applogger.Error("json.Marshal error:%v", err) time.Sleep(5 * time.Second) continue } applogger.Info("Message processing result:%v", string(msgStr)) default: applogger.Debug("ReadMessage data info:%v", string(msg)) } } rece_count++ if rece_count%10000 == 0 { fmt.Println("count:", rece_count, " Received message:", string(msg)) } } } func TestGet(t *testing.T) { urlStr := "https://quote.tradeswitcher.com/quote-b-api/kline" log.Println("请求内容:", urlStr) req, err := http.NewRequest("GET", urlStr, nil) if err != nil { fmt.Println("Error creating request:", err) return } q := req.URL.Query() q.Add("token", "bf8f33c446c4494286eccaa57a2e6fac-c-app") var query ConstructParameters query.Trace = uuid.New().String() query.Data.Code = "AUDUSD" query.Data.KlineType = 8 query.Data.KlineTimestampEnd = 0 query.Data.QueryKlineNum = 3 query.Data.AdjustType = 0 byteStr, err := json.Marshal(&query) if err != nil { return } q.Add("query", string(byteStr)) req.URL.RawQuery = q.Encode() // 发送请求 resp, err := http.DefaultClient.Do(req) if err != nil { fmt.Println("Error sending request:", err) return } defer resp.Body.Close() bodyStr, err := ioutil.ReadAll(resp.Body) if err != nil { log.Println("读取响应失败:", err) return } var klineNew KlineGetReturnStruct if err = json.Unmarshal(bodyStr, &klineNew); err != nil { log.Println("解析失败:", err) return } log.Println("响应内容:", klineNew) } func TestPost(t *testing.T) { for { UrlBatchKline := "https://quote.tradeswitcher.com/quote-b-api/batch-kline?token=bf8f33c446c4494286eccaa57a2e6fac-c-app" bodyStr, err := internal.HttpPost(UrlBatchKline, GenerateParameters(uuid.New().String(), "GOLD", 1, 1)) if err != nil { log.Println("读取响应失败:", err) return } var klineNew KlinePostReturnStruct if err = json.Unmarshal([]byte(bodyStr), &klineNew); err != nil { log.Println("解析失败:", err) return } //applogger.Info("数据信息:%v", klineNew) ClosePrice := klineNew.Data.KlineList[0].KlineData[0].ClosePrice OpenPrice := klineNew.Data.KlineList[0].KlineData[0].OpenPrice HighPrice := klineNew.Data.KlineList[0].KlineData[0].HighPrice LowPrice := klineNew.Data.KlineList[0].KlineData[0].LowPrice Volume := klineNew.Data.KlineList[0].KlineData[0].Volume Timestamp := klineNew.Data.KlineList[0].KlineData[0].Timestamp Turnover := klineNew.Data.KlineList[0].KlineData[0].Turnover applogger.Debug("闭盘价:%v,开盘价:%v,最高价:%v,最低价:%v,交易量:%v,交易时间:%v,交易金额:%v", ClosePrice, OpenPrice, HighPrice, LowPrice, Volume, Timestamp, Turnover) time.Sleep(time.Second * 1) } } func TestGetOrderDepth(t *testing.T) { urlStr := "https://quote.tradeswitcher.com/quote-b-api/depth-tick" log.Println("请求内容:", urlStr) req, err := http.NewRequest("GET", urlStr, nil) if err != nil { fmt.Println("Error creating request:", err) return } q := req.URL.Query() q.Add("token", "bf8f33c446c4494286eccaa57a2e6fac-c-app") var query OrderBookOrTradeTick query.Trace = uuid.New().String() query.Data.SymbolList = []SymbolList{ {Code: "GOLD"}, } byteStr, err := json.Marshal(&query) if err != nil { return } q.Add("query", string(byteStr)) req.URL.RawQuery = q.Encode() // 发送请求 resp, err := http.DefaultClient.Do(req) if err != nil { fmt.Println("Error sending request:", err) return } defer resp.Body.Close() bodyStr, err := ioutil.ReadAll(resp.Body) if err != nil { log.Println("读取响应失败:", err) return } var klineNew DepthTradeReturnStruct if err = json.Unmarshal(bodyStr, &klineNew); err != nil { log.Println("解析失败:", err) return } log.Println("响应内容:", klineNew) } func TestGetOrderTrade(t *testing.T) { urlStr := "https://quote.tradeswitcher.com/quote-b-api/trade-tick" log.Println("请求内容:", urlStr) req, err := http.NewRequest("GET", urlStr, nil) if err != nil { fmt.Println("Error creating request:", err) return } q := req.URL.Query() q.Add("token", "bf8f33c446c4494286eccaa57a2e6fac-c-app") var query OrderBookOrTradeTick query.Trace = uuid.New().String() query.Data.SymbolList = []SymbolList{ {Code: "GOLD"}, } byteStr, err := json.Marshal(&query) if err != nil { return } q.Add("query", string(byteStr)) req.URL.RawQuery = q.Encode() // 发送请求 resp, err := http.DefaultClient.Do(req) if err != nil { fmt.Println("Error sending request:", err) return } defer resp.Body.Close() bodyStr, err := ioutil.ReadAll(resp.Body) if err != nil { log.Println("读取响应失败:", err) return } var klineNew TradeReturnStruct if err = json.Unmarshal(bodyStr, &klineNew); err != nil { log.Println("解析失败:", err) return } log.Println("响应内容:", klineNew) }