沪深websocket level2/level1行情推送接入示例

ops/2024/12/22 14:11:25/

行情接入包

golang packge:

package hangqingimport ("bufio""bytes""compress/flate""encoding/json""github.com/gorilla/websocket""io/ioutil""log""net/http""net/url""strings""sync""time"
)type ServerAddrRsp struct {Code   string `json:"code"`Server string `json:"server"`
}type Hq struct {token    string          //jvQuant Tokenserver   string          //websocket服务器地址conn     *websocket.Conn //websocket连接cmdChan  chan stringexitChan chan intlv1Deal  func(string string) //level1行情处理方法lv2Deal  func(string string) //level2行情处理方法wg       *sync.WaitGroup
}//实例初始化
func (hq *Hq) Construct(token, serAddr string, lv1Handle, lv2Handle func(string string)) {hq.token = tokenif serAddr == "" {hq.server = hq.initServer()}hq.lv1Deal = lv1Handlehq.lv2Deal = lv2Handlehq.conn = hq.connect()hq.wg = &sync.WaitGroup{}hq.cmdChan = make(chan string, 128)hq.exitChan = make(chan int)//接收协程hq.wg.Add(2)go func() {hq.receive()hq.wg.Done()}()//发送协程go func() {hq.cmd()hq.wg.Done()}()
}//获取行情服务器地址
func (hq *Hq) initServer() (server string) {params := url.Values{"market": []string{"ab"},"type":   []string{"websocket"},"token":  []string{hq.token},}req := "http://jvquant.com/query/server?" + params.Encode()rb, err := HttpOnce(req, nil, nil, 3000)if err != nil {log.Fatalln("获取行情服务器地址失败:", req, err)}rspMap := ServerAddrRsp{}err = json.Unmarshal(rb, &rspMap)if err != nil {log.Fatalln("解析行情服务器地址失败:", string(rb), err)}server = rspMap.Serverif rspMap.Code != "0" || server == "" {log.Fatalln("解析行情服务器地址失败:", string(rb))}log.Println("获取行情服务器地址成功:", server)return
}//连接行情服务器
func (hq Hq) connect() (conn *websocket.Conn) {wsUrl := hq.server + "?token=" + hq.tokenconn, _, err := websocket.DefaultDialer.Dial(wsUrl, nil)if err != nil {log.Fatalln("行情服务器连接错误:", err)}return
}//增加level1行情订阅
func (hq Hq) AddLv1(codeArr []string) {cmd := "add="cmdArr := []string{}for _, code := range codeArr {cmdArr = append(cmdArr, "lv1_"+code)}cmd = cmd + strings.Join(cmdArr, ",")hq.SendRawCmd(cmd)
}//增加level2行情订阅
func (hq Hq) AddLv2(codeArr []string) {cmd := "add="cmdArr := []string{}for _, code := range codeArr {cmdArr = append(cmdArr, "lv2_"+code)}cmd = cmd + strings.Join(cmdArr, ",")hq.SendRawCmd(cmd)
}//指令入队列
func (hq Hq) SendRawCmd(cmd string) {hq.cmdChan <- cmd
}//关闭行情连接
func (hq Hq) Close() {close(hq.cmdChan)hq.exitChan <- 1hq.conn.Close()
}//线程阻塞等待
func (hq Hq) Wait() {hq.wg.Wait()
}//websocket指令发送
func (hq Hq) cmd() {for cmd := range hq.cmdChan {log.Println("发送指令:" + cmd)err := hq.conn.WriteMessage(websocket.TextMessage, []byte(cmd))if err != nil {log.Println("指令发送错误:", err)}}
}//websocket行情接收处理
func (hq Hq) receive() {for {select {case <-hq.exitChan:log.Print("接收协程退出")returndefault://阻塞接收messageType, rb, err := hq.conn.ReadMessage()if err != nil {log.Print("接收错误:", err)}//文本消息if messageType == websocket.TextMessage {log.Println("Text响应:", string(rb))}//二进制消息if messageType == websocket.BinaryMessage {unZipByte := DeCompress(rb)text := string(unZipByte)ex1 := strings.Split(text, "\n")for _, ex1r := range ex1 {ex2 := strings.Split(ex1r, "=")if len(ex2) == 2 {code := ex2[0]hqs := ex2[1]if strings.HasPrefix(code, "lv1_") {hq.lv1Deal(hqs)}if strings.HasPrefix(code, "lv2_") {hq.lv2Deal(hqs)}}}}}}
}//二进制数据解压方法
func DeCompress(b []byte) []byte {var buffer bytes.Bufferbuffer.Write([]byte(b))reader := flate.NewReader(&buffer)var result bytes.Bufferresult.ReadFrom(reader)reader.Close()return result.Bytes()
}
//http请求封装
func HttpOnce(Url string, headers, postData map[string]string, msTimeOut int) (r []byte, err error) {client := &http.Client{Timeout: time.Duration(time.Duration(msTimeOut) * time.Millisecond),}method := http.MethodGetr = []byte{}err = nilif len(headers) == 0 {headers = map[string]string{}}if len(postData) != 0 {method = http.MethodPostheaders["Content-Type"] = "application/x-www-form-urlencoded"}postParam := url.Values{}for k, v := range postData {postParam.Set(k, v)}postParamBuff := bytes.NewBufferString(postParam.Encode())req, err := http.NewRequest(method, Url, postParamBuff)if err != nil {return r, err}for k, v := range headers {req.Header.Add(k, v)}resp, er := client.Do(req)if er != nil {err = erreturn}defer resp.Body.Close()if err != nil {return r, err}br := bufio.NewReader(resp.Body)r, err = ioutil.ReadAll(br)return r, err
}

参考地址:https://github.com/jvQuant/OpenAPIDemo


http://www.ppmy.cn/ops/22439.html

相关文章

Wi-Fi HaLow:重塑物联网的未来

Wi-Fi HaLow&#xff1a;引领物联网连接的革命 数字时代的蓬勃发展正在引发一场深刻的变革&#xff0c;物联网已经融入到我们的日常生活和工作中&#xff0c;成为不可或缺的一部分。随着新一代Wi-Fi技术一Wi-Fi HaLow的崭露头角&#xff0c;有望在2024年及未来&#xff0c;重新…

怎么理解JavaScript原型、原型链

原型 JavaScript被描述为一种基于原型的语言&#xff0c;也就是每一个对象都拥有一个原型对象。 当我们访问一个对象的属性时&#xff0c;它不仅仅该改对象上查找&#xff0c;还会到这个对象的原型上查找&#xff0c;甚至是到这个对象的原型的原型上查找&#xff0c;这样一层…

stm32单片机开发三、DMA

DMA其实就是一种将ADC的数据寄存器、串口的数据寄存器等等一些数据放到sram中特定位置&#xff0c;方便CPU去读取 比如ADC转换&#xff0c;DMA直接转换的ADC的值放在内存中的特定位置&#xff0c;CPU可以直接去读取 uint16_t AD_Value[4]; //定义用于存放AD转换结果的全局…

纯js对比excel小工具

如何使用JavaScript和xlsx.js实现Excel文件对比&#xff1a;实战指南 在日常办公或数据分析工作中&#xff0c;我们经常需要比较两个Excel文件中的数据差异。手动对比不仅耗时费力&#xff0c;还容易出错。本文将带你通过一个简单的网页应用&#xff0c;利用JavaScript和开源库…

云原生Kubernetes: K8S 1.29版本 部署Sonarqube

一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构版本IP备注masterK8S master节点1.29.0192.168.204.8 node1K8S node节点1.29.0192.168.204.9node2K8S node节点1.29.0192.168.204.10已部署Kuboard &#xff08;2&#xff09;master节点查看集群 1&…

进程地址空间

首先我们先了解不同数据存储的位置 堆区:动态分配的内存&#xff0c;例如使用malloc或者new出来的对象 栈区:存储局部变量 静态区:存储全局变量或者静态变量 只读常量区(数据段):存储只读数据例如字符串常量 代码段:存储执行代码 可以通过以下代码验证 1 #include <st…

CentOS 删除文件提示 Operation not permitted 的解决方法

1、阿里云服务器提示存在挖矿行为&#xff0c;路径在 /etc/zzh&#xff0c;我们做下删除动作&#xff0c;发现不能删除 [rootMSH etc]# rm -f zzh# 提示 rm: cannot remove ‘zzh’: Operation not permitted2、解决方法&#xff1a; (1)、查看文件权限 [rootMSH etc]# lsat…

最新官方破解版会声会影2024永久序列号和激活码

会声会影2024是一款功能强大的视频编辑软件&#xff0c;它集合了视频剪辑、音频调整、特效添加等多项功能于一身&#xff0c;为用户提供了一个全面且易用的视频制作平台。无论是初学者还是专业视频编辑人员&#xff0c;都能在这款软件中找到满足自己创作需求的工具。 会声会影最…