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

行情接入包

golang packge:

package hangqing

import (
	"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 Token
	server   string          //websocket服务器地址
	conn     *websocket.Conn //websocket连接
	cmdChan  chan string
	exitChan chan int
	lv1Deal  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 = token
	if serAddr == "" {
		hq.server = hq.initServer()
	}
	hq.lv1Deal = lv1Handle
	hq.lv2Deal = lv2Handle
	hq.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.Server
	if rspMap.Code != "0" || server == "" {
		log.Fatalln("解析行情服务器地址失败:", string(rb))
	}
	log.Println("获取行情服务器地址成功:", server)
	return
}

//连接行情服务器
func (hq Hq) connect() (conn *websocket.Conn) {
	wsUrl := hq.server + "?token=" + hq.token
	conn, _, 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 <- 1
	hq.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("接收协程退出")
			return
		default:
			//阻塞接收
			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.Buffer
	buffer.Write([]byte(b))
	reader := flate.NewReader(&buffer)
	var result bytes.Buffer
	result.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.MethodGet
	r = []byte{}
	err = nil
	if len(headers) == 0 {
		headers = map[string]string{}
	}
	if len(postData) != 0 {
		method = http.MethodPost
		headers["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 = er
		return
	}
	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.mfbz.cn/a/582050.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Go语言快速上手(五)】文件操作协程操作

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Go语言专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Go语言知识   &#x1f51d;&#x1f51d; GO快速上手 1. 前言2. GO语言的文件操…

武汉星起航:挂牌上海股权中心,开启资本新篇章助力跨境电商飞跃

2023年10月30日&#xff0c;武汉星起航电子商务有限公司在上海股权托管交易中心成功挂牌展示&#xff0c;标志着这家在跨境电商领域拥有卓越声誉的企业正式迈入了资本市场的大门。对于武汉星起航来说&#xff0c;这不仅是其发展历程中的一个重要里程碑&#xff0c;更是对其业务…

Python学习笔记------异常

当检测到错误时&#xff0c;Python解释器就无法继续执行了&#xff0c;反而出现一些错误提示&#xff0c;就是所谓异常&#xff08;bug&#xff09; 1、异常的捕获方法 任何程序运行过程中都可能出现异常&#xff0c;我们可以在力所能及的范围内&#xff0c;对可能出现的bug提…

C语言趣味代码(四)

这一篇主要编写几个打字练习的小程序&#xff0c;然后通过这些小程序的实现来回顾复习我们之前学过的知识&#xff0c;然后通过这写打字练习的小程序来提升我们的打字技术和编程技术。 1. 打字练习 1.1 基本打字练习 1.1.1 基本实现 首先我们来制作一个用于计算并显示输入一…

ip网络广播前置放大器SV-7031 接纯后级功放

ip网络广播前置放大器SV-7031 接纯后级功放 感谢您使用我们的网络前置放大器SV-7031。 SV-7031具有1路AC200V OUT电源输出&#xff0c;1路AC200V IN电源输入&#xff1b;RJ45 网络接口&#xff0c;具有网络音频广播、本地广播功能。 18123651365 ip网络广播前置放大器SV-703…

vue-cli+vue3+vite+ts 搭建uniapp项目全过程(一)

unapp官方提供了cli 脚手架创建 uni-app 项目的文档 Vue3/Vite版要求 node 版本 18、20使用Vue3/Vite版创建不会提示选择模板&#xff0c;目前只支持创建默认模板 本文以vue3vitets为例 1、初始化项目 npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project 执行完生成…

就业班 第三阶段(tomcat) 2401--4.28 day1 tomcat1安装配置及单机多实例

企业 Tomcat 运维 文章目录 企业 Tomcat 运维一、Tomcat 简介1、Tomcat好帮手---JDK2、安装Tomcat & JDK1、系统环境说明2 、安装JDK3、安装Tomcat 二、Tomcat目录介绍1、tomcat主目录介绍2、webapps目录介绍3、Tomcat配置介绍&#xff08;conf&#xff09;4、Tomcat的管理…

Linux-管道通信

1. 管道概念 管道&#xff0c;是进程间通信的一种方式&#xff0c;在Linux命令中“ | ”就是一种管道&#xff0c;它可以&#xff0c;连接前一条命令&#xff0c;和后一条命令&#xff0c;把前面命令处理完的内容交给后面&#xff0c;例如 cat filename | grep hello …

本地部署 Meta Llama3-8b

Meta Llama 3(8B) Instruct model performance Meta Llama 3(8B) Pre-trained model performance 使用 Ollama 运行 Llama3 访问 Tags llama3&#xff0c;选择你想运行的模型&#xff0c;例如&#xff0c;8b-instruct-q8_0 拷贝并运行命令&#xff0c;ollama run llama3:8b-…

秋招后端开发面试题 - Java语言基础(上)

目录 Java基础上前言面试题Java 语言的特点JVM JDK JRE什么是跨平台性&#xff1f;原理是什么&#xff1f;什么是字节码?采用字节码的好处是什么?Java 和 C 的区别&#xff1f;注释&#xff1f;关键字关键字 instanceof类型转换关键字 this 和 super关键字 final finally fin…

Android数据恢复:如何在手机上恢复丢失的文件和照片

我们都有 我们错误地从手机中删除重要内容的时刻。确实如此 不一定是我们的错。其他人可以对您的手机数据执行此操作 有意或无意。这在某个时间点发生在我们所有人身上。 但是&#xff0c;今天市场上有各种各样的软件可以 帮助恢复已删除的文件。这些类型的软件被归类为数据恢复…

Linux命令大全 以及搭建hadoop

Liunx系统目录 ├── bin -> usr/bin # 用于存放二进制命令 ├── boot # 内核及引导系统程序所在的目录 ├── dev # 所有设备文件的目录&#xff08;如磁盘、光驱等&#xff09; ├── etc # 配置文件默认路径、服务启动命令存放目录 ├── home # 用户家目录&#…

UEFI安全启动模式下安装Ubuntu的NVIDIA显卡驱动

UEFI安全启动模式下安装ubuntu的nvidia显卡驱动 实践设备&#xff1a;华硕FX-PRO&#xff08;NVIDIA GeForce GTX 960M&#xff09; 一、NVIDIA官网下载驱动 1.1在浏览器地址栏输入https://www.nvidia.cn/drivers/lookup/进入网站&#xff0c;接着手动驱动搜索&#xff0c;并…

【C语言】:动态内存管理

1、为什么要有动态内存分配2、动态内存管理函数2.1 malloc2.2 free2.3 calloc2.4 realloc 3、常见的动态内存的错误3.1 对NULL指针的解引用操作3.2 对动态开辟空间的越界访问3.3 对非动态开辟内存使用free释放3.4 使用free释放一块动态开辟内存的一部分3.5 对同一块动态内存多次…

stm32单片机开发三、DMA

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

告别繁琐!小浪助手助你轻松下载学浪视频

小浪助手&#xff0c;一站式学浪视频下载工具&#xff0c;能让你轻松下载学浪视频 工具我已经打包好了&#xff0c;有需要的自己取一下 学浪下载器链接&#xff1a;https://pan.baidu.com/s/1djUmmnsfLEt_oD2V7loO-g?pwd1234 提取码&#xff1a;1234 --来自百度网盘超级会…

Pycharm配深度学习环境所遇到的部分问题

问题1&#xff1a;Anaconda prompt界面安装CUDA出现的问题: 不管是&#xff1a;conda install pytorch torchvision torchaudio cudatoolkit11.3 -c pytorch 还是:pip ****什么的 问题描述&#xff1a;EnvironmentNotWritableError: The current user does not have write p…

python应用-socket网络编程(1)

目录 1 先简单回顾下客户端和服务端通信的知识 2 服务端常用函数 3 客户端常用函数 4 服务端和客户端都用的函数 5 示例介绍客户端和服务端通信过程 6 建立服务端套接制 7 创建服务端函数socket.create_server() 8 创建客户端套接字 9 客户端连接函数socket.create_co…

用socat验证multicase(组播)和broadcast(广播) with k8s容器环境

安装socat 网络允许的话&#xff0c;可以使用yum install -y socat进行安装。 如果是在容器里面运行&#xff0c;建议使用静态链接的socat: 可以从此处下载&#xff1a; Release socat-v1.7.4.4 ernw/static-toolbox GitHub 确定网络接口地址和组播地址 #kubectl exec -i…

请编写函数fun,该函数的功能是:实现B=A+A‘,即把矩阵A加上A的转置,存放在矩阵B中。计算结果在main函数中输出。

本文收录于专栏:算法之翼 https://blog.csdn.net/weixin_52908342/category_10943144.html 订阅后本专栏全部文章可见。 本文含有题目的题干、解题思路、解题思路、解题代码、代码解析。本文分别包含C语言、C++、Java、Python四种语言的解法完整代码和详细的解析。 题干 请编…