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.

589 lines
17 KiB

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)
}