沪深行情 C++ Pro SDK 环境与接口手册
1 简介
安湖行情服务是 FPGA 极速行情 接入的开发包,支持 linux 系统,以动态库(.so)和静态库 (.a) 两种形式提供给开发者。行情用户可以通过 sdk 的接口文档和 sdk 头文件,轻松实现行情的接入, 并对行情做自定义的回调处理操作。本手册主要分为:
- 系统环境配置
- 行情 sdk 系统
- 行情 sdk 回调
等三部分组成。为 FPGA 行情的开发人员、测试人员和运维人员而提供相应的资料文档.
2 系统环境配置
系统环境配置是指行情sdk系统运行时,所依赖的系统库,软件库等。主要有
- gcc-8.5.0+
- other tools
3 gcc-8.5.0 依赖
由于行情 SDK 系统采用了 c++11/c++14/c++17 新特性开发, 而 redhat 7 内置的 gcc 版本为 4.8.5 。 gcc-8.5.0 是一个较为全面支持 c++17. 建议通过源码安装 gcc,且版本 最低 为 gcc-8.5.0, 可以通过网络下载源码:
wget https://ftp.gnu.org/gnu/gcc/gcc-8.5.0/gcc-8.5.0.tar.gz
对上述 gcc 压缩包解压:
tar xvf gcc-8.5.0.tar.gz
3.1 依赖库表
| name | package name | download url | description |
|---|---|---|---|
| m4 | m4-1.4.16-10.el7.x86_64.rpm | m4下载 | 编译 gmp 依赖 |
| gmp | gmp-6.2.1.tar | 源码安装,压缩包已提供(最低版本4.2+) | gcc源码编译前需要安装 |
| mpfr | mpfr-4.1.0.tar.bz2 | 源码安装,压缩包已提供(最低版本2.4+) | gcc源码编译前需要安装 |
| mpc | mpc-1.2.0.tar.gz | 源码安装,压缩包已提供(最低版本0.8+) | gcc源码编译前需要安装 |
| isl | isl-0.16.1.tar.bz2 | 源码安装,压缩包已提供 | gcc源码编译前需要安装 |
3.2 在线安装
如果系统可以联网, 那么可以直接在 gcc 目录下的执行:
cd gcc-8.5.0
./contrib/download_prerequisites
make -j$(nproc)
sudo make install
其中, m4 通过离线的安装包安装. gmp, mpfr , mpc 和 isl 通过源码编译安装。 如果系统可以联网,可直接在 gcc 目录下的执行:
./contrib/download_prerequisites
即可实现四个依赖的联网安装。另外,以上四个包, 详见压缩在文件 infrastructure.tar.bz2. m4 对应的安装包为 m4-1.4.16-10.el7.x86_64.rpm
3.3 离线安装
如果系统联网不便, 我们也提供了压缩文件: infrastructure.tar.bz2, 该压缩包文件有:
gmp-6.2.1.tar.bz2
mpc-1.2.1.tar.gz
mpfr-4.1.0.tar.bz2
isl-0.24.tar.bz2
另外还有一个编译脚本 upgrade-gcc.sh 可以一键编译, 步骤如下:
- 切换到解压后的 gcc 目录下
- 拷贝 infrastructure.tar.bz2 和 upgrade-gcc.sh 至 gcc 源码目录
- 解压 infrastructure.tar.bz2
- 执行 upgrade-gcc.sh 即可
4 环境配置
大概编译20-30分钟左右。等编译安装完成后,请执行以下命令行:
echo /usr/local/gcc8/lib | sudo tee -a /etc/ld.so.conf
echo /usr/local/gcc8/lib64 |sudo tee -a /etc/ld.so.conf
sudo ldconfig
- 如果 gcc 没有安装, 请在线安装
sudo yum group install "Development Tools"- 如果编译 gcc 中途出错, 可能需要 m4. 在Redhat7 中, 离线安装包请点击 m4下载地址, 下载后的rpm包为: m4-1.4.16-10.el7.x86_64.rpm , 安装命令:
rpm -ivh m4-1.4.16-10.el7.x86_64.rpm. 如果系统支持在线安装, 请执行:yum install m4即可- 如果 cmake 没有安装, 请在线安装
sudo yum install cmake- 缺省的 cmake 版本比较低, 需要升级. 版本为 3.11+, 然后请在线安装
sudo yum install openssl openssl-devel以便对 cmake 进行源码编译升级安装- cmake 最新源码: cmake 源码, 编译安装命令为:
./bootstrap && make -j$(nproc) && sudo make install. 编译后请执行hash -r以便所安装的最新版本 cmake 生效- 升级安装后的
gcc版本, 可以在项目的 cmake 参数中指定 gcc 的路径:cmake -DCMAKE_CXX_COMPILER=/usr/local/gcc8/bin/g++ ..(即指向所安装的 gcc 路径). 或者在 CMakeLists.txt 中的 project 前面强行设置:set(CMAKE_CXX_COMPILER /usr/local/gcc8/bin/g++)
5 行情 SDK 系统
以上部分( 2-4 ) 为 sdk 的环境依赖的准备工作, 现在进入 行情SDK系统 部分, 分为:
- 目录结构说明
- 运行环境说明
5.1 目录结构
[annhoo_md_sdk_demo] tree -L 3
.
├── bin
│ ├── annhoo_md_sdk_demo
│ ├── get_version
│ └── subscribe
├── CMakeLists.txt
├── conf
│ └── config_annhoo_md_sdk.yaml
├── examples
│ ├── get_version
│ │ ├── CMakeLists.txt
│ │ └── get_version.cpp
│ └── subscribe
│ ├── CMakeLists.txt
│ └── subscribe.cpp
├── include
│ ├── annhoo_md_sdk
│ │ ├── ah_md_api.h
│ │ ├── ah_md_common.h
│ │ └── ah_md_spi.h
│ └── cmdline.h
├── lib
│ └── libannhoo_md_sdk.so
├── README.md
├── spdlog_lib
│ ├── libannhoo_md_sdk.a
│ └── libannhoo_md_sdk.so
├── inner_lib
│ ├── libannhoo_md_sdk.a
│ └── libannhoo_md_sdk.so
├── src
│ ├── ah_md_spi_inl.cpp
│ ├── ah_md_spi_inl.h
│ └── main.cpp
├── start.sh
├── stop.sh
└── tick_bulk_sf
└── inner_lib
└── libannhoo_md_sdk.so
目录结构详情:
bin: demo的二进制 生成目录bin/annhoo_md_sdk_demo: 二进制可执行文件, 行情可落地文件bin/get_version: 二进制可执行文件, 可得到sdk的版本信息: 编译时间,commit hash,分支等信息bin/subscribe: 二进制可执行文件, 演示订阅功能, 所订阅的行情输出到控制台CMakeLists.txt: demo 的 CMake 文件conf: sdk 的 配置文件目录conf/config_annhoo_md_sdk.yaml: sdk配置文件, 为 ymal 格式include: sdk 所依赖的 头文件目录include/ah_md_spi.h: 用户需要实现的 行情的四个回调接口文件include/ah_md_api.h: sdk 的 行情实现接口文件include/ah_quotes_common.h: sdk 的 行情数据结构文件, 主要定义了四种行情的数据结构和其他数据结构lib: sdk 的 库文件目录lib/libannhoo_md_sdk.a: 静态库 文件lib/libannhoo_md_sdk.so: 动态库 文件src: demo 源码目录ah_md_spi_inl.h: 用户自定义实现的 行情的四个回调函数 的头文件ah_md_spi_inl.cpp: 用户自定义实现的 行情的四个回调函数 的源文件main.cpp: sdk 调用样例examples/get_version.cpp: sdk 调用样例源码, 获取版本信息examples/subscribe.cpp: sdk 调用样例源码, 订阅功能演示start.sh: 一键启动脚本stop.sh: 一键停止脚本
重要
需要注意的是,目前sdk自带的日志有两套, 一套是基于spdlog的,另外一套是非spdlog。因为 spdlog 的初始化不能够同时存在于sdk和应用。如果应用也是采用了spdlog作为日志库,那么请使用非spdlog日志的版本
5.2 运行环境说明
- 行情sdk和 FPGA在相同网络环境中的机器上运行,可使用 linux onload(需要solarflare 网卡支持),这样能进一步降低网络延时
- RedHat RHEL 7.4 x64 及以上版本
- 如果 gcc 版本不支持 c++17, 需要对 gcc 升级. 升级步骤前面章节已有相应的详细升级步骤, 并有相应的压缩包提供
- CPU 主频的越高越好,且 cpu核六个以上 (含)
6 行情sdk回调
行情sdk的回调主要包含开发流程, 配置说明和各个接口说明
6.1 开发流程
- 调用
NewMdApi创建IAHMdApisdk的行情api接口 - 按照自己的业务从
IAHMdSpi派生出一个子类,并实现自己关心的回调接口(如委托行情回调OnTickCB等),方法可参考src/ah _md_spi_inl.cpp和src/ah_md_spi_inl.h中的AHMdSpiInl实现代码. - 调用
IAHMdApi::RegisteAH pi接口, 把第二步所生成的自定义回调对象注册到IAHMdApi中 - 调用
IAHMdApi::SubscribeXXX接口订阅所关心的行情数据 - 调用
IAHMdApi::Start启动行情服务 - 调用
IAHMdApi::Join等待行情服务结束 - 调用
IAHMdApi::UnRegisterSpi注销行情回调, 释放行情回调和行情接口
6.2 配置说明
配置文件目前支持两个格式的配置
- ini
- yaml
缺省的配置文件格式是 ini. 下面以 yaml 格式作为解说. ini 类同.
6.2.1 配置文件
[quotes_sdk_demo]$ cat conf/config_annhoo_md_sdk.yaml
market:
- sh
- sz
sh:
# if tcp was set, all datas come from tcp(just for tcp test)
# tcp:
# host: 192.168.9.202
# port: 9091
quotes_server:
- master
- slave
master:
# host: 224.0.0.1
host: 232.4.102.96
timeout: 99999
try_count: 99999
imr_interface: 192.168.9.202
slave:
#host: 224.0.0.1
host: 232.4.102.96
timeout: 99999
try_count: 99999
imr_interface: 192.168.9.202
server:
url: 192.168.1.205:8080
ip: 192.168.1.201
port: 8080
mac: b4:2e:99:8f:7d:50
name: yyds
pwd: anhoo
sz:
# if tcp was set, all datas come from tcp(just for tcp test)
# tcp:
# host: 192.168.9.202
# port: 9091
quotes_server:
- master
- slave
master:
host: 232.4.102.98
timeout: 99999
try_count: 99999
imr_interface: 192.168.9.30
slave:
host: 232.4.102.98
timeout: 99999
try_count: 99999
imr_interface: 192.168.9.202
server:
url: 192.168.1.205
ip: 192.168.1.201
port: 8080
mac: b4:2e:99:8f:7d:50
name: yyds
pwd: anhoo
# quotes lists
quotes_type:
- index
- snapshot
- tick
index:
port: [22345, 12345]
recv_np: [1, 2] # recv udp thread np
dispatch_np: 10 # attach cpu index
snapshot:
port: [22346, 12346]
recv_np: [3, 4] # recv udp thread np
dispatch_np: 11 # attach cpu index
tick:
port: [22347, 12347]
recv_np: [5, 6] # recv udp thread np
dispatch_np: 12 # attach cpu index
logger:
name: annhoo_md_sdk.log
# 0: trace
# 1: debug
# 2: info
# 3: warn
# 4: error
# 5: fatal
# 6: off
level: 2
rotate_size: 100
rotate_total: 5
stdout: false
system:
# solar flare name for sh, sz.
interface: [p1p1, p1p1]
# if network is normal, interface name should be AH_NONE
# interface: [AH_NONE, AH_NONE]
# should have root/sudo to increase process permission
nice: -20
queue_size: 60000
recv_mem_size: 1234567
market: 市场类别, 其中: sh-上海, sz-深圳quotes_server: 主备, 此项包含后面的为主备的总述(保留)server: 登录 FPGA 服务器配置, 默认关闭(保留)host: udp 主备的 组播地址(保留)imr_interface: 为多网卡时, 指定接收udp的网口地址. 如果是单网卡, 请保留其值:0.0.0.0quotes_type: 行情类别, 当前四种. 如果不需要行情, 可以用#注释而不启用(保留)port: 每种行情的监听端口, 端口依次为sh, szrecv_np: 每种行情接收线程所要绑定的cpu核的索引号(-1代表不绑核, >=0 代表说绑定的cpu序列号). 依次为 sh, szdispatch_np: 分发线程所要绑定的cpu核的索引号(-1代表不绑核, >=0 代表说绑定的cpu序列号)name: 日志名称level: 所要输出的日志级别rotate_size: 日志文件大小, 单位为 Mrotate_total:日志文件个数stdout: 日志是否打印屏幕, 需要注意的是,如果sdk采用的是非spdlog日志的 inner_lib 版本,那么此项开关是互斥的,即 打屏幕后不再同时打印日志文件.nice: 是进程优先级, 需要sudo权限, 普通用户请忽略该选项, linux的取值范围为 [-20, 19)queue_size: 缓存队列长度大小, 数越大占的内存越大,队列越大,缓存相对越大。recv_mem_size: 为 udp 的接收缓存的大小设置(比如配成 67108864 为 64M), 该项依赖于系统所设的缓存值. 此项是非 solar flare 网卡所留,solar flare的用户态版本忽略此项配置。tick: 含逐笔委托和逐笔成交, 两者要么全订阅要么不订阅.interface: solar flare 网卡的名字,依次为沪市,深市。请填充完整,如果沪深两市用同一个网卡,且sdk同时支持沪深两市,请配置同样的solar flare网卡名。如果是非solar flare, 那么此项需要设置为:[AH_NONE, AH_NONE]
6.2.2 sdk 日志配置
目前的 sdk 日志有:
- 调试日志: 1 - debug
- 一般日志: 2 - info
- 警告日志: 3 - warn
- 错误日志: 4 - error
- 致命日志: 5 - fatal(该日志, 程序不正常, 必须停止排查)
- 关闭所有日志: 6 - off
6.2.3 recv_mem_size
该值对应 udp 接收缓存的设置. 可以通过如下命令展示系统默认的接收缓存的值:
[root@hpserver206 quotes_sdk_demo]# cat /proc/sys/net/core/rmem_default
268435456
行情服务系统配置文件的 recv_mem_size 所设的值, 如果大于等于 /proc/sys/net/core/rmem_default 的 2倍, 则行情服务会以 rmem_default*2 为准. 反之, 则以所设的 recv_mem_size 为准.
建议对 /proc/sys/net/core/rmem_default 进行适当调大, 以减少udp掉包率. 可通过如下命令调整(需要sudo权限)
echo 268435456 > /proc/sys/net/core/rmem_default # set to 256M
echo 536870912 > /proc/sys/net/core/rmem_max # set to 512M
ldconfig
需要注意的是, 此为临时修改, 系统重启后改修改失效.
设置永久值
sudo 权限 编辑 /etc/sysctl.conf 文件
sudo vi /etc/sysctl.conf
在文件的末尾添加以下行:
net.core.rmem_default = 268435456
net.core.rmem_max = 536870912
保存并关闭文件
运行以下命令使配置生效:
sudo sysctl -p
这将重新加载配置文件并应用更改
- 如果要启用 yaml, 需要设置环境变量
export AH_LOAD_FILE_FORMAT_YAML=1或者export AH_LOAD_FILE_FORMAT=true- yaml 和 ini 互斥, 二者之能够二选一
- ini 格式启用可以
export AH_LOAD_FILE_FORMAT=0或者export AH_LOAD_FILE_FORMAT=false或者unset AH_LOAD_FILE_FORMAT
6.2.4 ini 样式
[market]
markets_type=sz
; 行情推送方式 0-salarflare的组播 1-普通网卡组播 2-tcp
recv_type=0
queue_size=600
recv_mem_size=209715200
nice=-20
[sh]
#普通网卡使用如下配置
#interface: [AH_NONE, AH_NONE]
#solarfare 网卡使用下面配置,p1p1表示 网卡名称
interface=p1p1
auth_url=192.168.9.32
auth_ip=192.168.9.28
auth_port=80
auth_mac=00:0f:53:ad:5d:80
auth_name=EX1714986746948035
auth_pwd=888888
[sh_udp]
master_host=232.4.102.96
master_timeout=99999
master_try_count=99999
master_imr_interface=192.168.9.28
slave_host=232.4.102.96
slave_timeout=99999
slave_try_count=99999
slave_imr_interface=192.168.9.28
[sh_index]
port=32345
recv_np=1
[sh_snapshot]
port=32346
recv_np=3
[sh_tick]
port=22347
recv_np=5
; recv_type=2
[sh_tcp]
host=192.168.9.13
port=20068
[sz]
#普通网卡使用如下配置
#interface: [AH_NONE, AH_NONE]
#solarfare 网卡使用下面配置,p1p1表示 网卡名称
interface=p1p1
auth_url=192.168.9.32
auth_ip=192.168.9.28
auth_port=80
auth_mac=56:82:ab:22:ba:fd
auth_name=EX1715047404885022
auth_pwd=888888
[sz_udp]
master_host=232.4.102.98
master_timeout=99999
master_timeout=99999
master_imr_interface=192.168.9.28
slave_host=232.4.102.98
slave_timeout=99999
slave_timeout=99999
slave_imr_interface=192.168.9.28
[sz_index]
port=22345
recv_np=1
[sz_snapshot]
port=22346
recv_np=3
[sz_tick]
port=12347
recv_np=5
; recv_type=2
[sz_tcp]
host=192.168.9.15
port=20068
[dispatch]
index_np=11
snapshot_np=12
tick_np=13
[logger]
name=annhoo_md_sdk.log
# 0: trace
# 1: debug
# 2: info
# 3: warn
# 4: error
# 5: fatal
# 6: off
level=2
rotate_size=100
rotate_total=5
stdout=false
6.3 接口说明
接口函数主要是行情 sdk c++的 API 接口, 主要有
NewMdApi- 创建行情接口GetMdApiVersion- 获取 API 版本号RegisterSpi/UnRegisterSpi- 注册/注销 行情回调SubscribeXXX/UnSubscribeXXX- 订阅/取消订阅Start- 启动行情Join- 等待行情结束
需要主要的是, 以下接口以实际源码为准。
6.3.1 NewMdApi - 创建行情接口
Synopsis
annhoo::IAHMdApi* NewMdApi(const char* config_path);
Parameters
| name | data type | description |
|---|---|---|
| config_path | char* const | 配置文件(yaml格式) |
Return
IAHMdApi pointer
6.3.2 GetMdApiVersion - 获取版本号接口
Synopsis
const char* GetMdApiVersion();
Parameters
void
Return
version: 1.1.2
6.3.3 GetMdApiVersionMore - 获取更多的版本信息
Synopsis
const char* GetMdApiVersionMore();
Parameters
void
Return
version: 1.1.2
branch: tick_bulk_sf
commit id: ddefcbc1449b2a3f10c88974bb585425ac18cf8c_2023-05-07 10:25:39 +0800
build time: 2023-05-07 10:27:27
build type: RelWithDebInfo
6.3.4 RegisterSpi - 注册回调接口
Synopsis
virtual void RegisterSpi(IAHMdSpi* imp) = 0;
Parameters
| name | data type | description |
|---|---|---|
| imp | IAHMdSpi* | 向API注册自定义的回调实现子类的对象 |
Return
void
6.3.5 UnRegisterSpi 取消回调接口
Synopsis
virtual void UnRegisterSpi(IAHMdSpi* imp) = 0;
Parameters
| name | data type | description |
|---|---|---|
| imp | IAHMdSpi* | 向API取消注册的自定义回调实现子类的对象 |
Return
void
6.3.6 SubscribeXXX - 订阅指定的行情列表
Synopsis
virtual int SubscribeIndex(const std::vector<std::string>& securityIDs) = 0;
virtual int SubscribeTick(const std::vector<std::string>& securityIDs) = 0;
virtual int SubscribeSnapshot(const std::vector<std::string>& securityIDs) = 0;
Parameters
| name | data type | description |
|---|---|---|
| securityIDs | const std::vector<std::string>& | 订阅指定的具体行情列表 |
Return
void
6.3.7 Subscribe(XXX)All - 订阅所有行情
Synopsis
virtual void SubscribeAll(void) = 0;
virtual void SubscribeIndexAll(void) = 0;
virtual void SubscribeTickAll(void) = 0;
virtual void SubscribeSnapshotAll(void) = 0;
Parameters
void
Return
void
6.3.8 UnSubscribeXXX - 取消指定的订阅行情列表
Synopsis
virtual int UnSubscribeIndex(const std::vector<std::string>& securityIDs) = 0;
virtual int UnSubscribeTick(const std::vector<std::string>& securityIDs) = 0;
virtual int UnSubscribeSnapshot(const std::vector<std::string>& securityIDs) = 0;
Parameters
| name | data type | description |
|---|---|---|
| securityIDs | const std::vector<std::string>& | 订阅具体的行情列表 |
Return
int
6.3.9 UnSubscribe(XXX)All - 取消所有订阅的行情
Synopsis
virtual void UnSubscribeAll(void) = 0;
virtual void UnSubscribeIndexAll(void) = 0;
virtual void UnSubscribeTickAll(void) = 0;
virtual void UnSubscribeSnapshotAll(void) = 0;
Parameters
void
Return
void
6.3.10 ExportSubscribeXXXX - 导出订阅列表
Synopsis
virtual void ExportSubscribeAll(std::vector<std::string>& outs) = 0;
virtual void ExportSubscribeIndex(std::vector<std::string>& outs) = 0;
virtual void ExportSubscribeTick(std::vector<std::string>& outs) = 0;
virtual void ExportSubscribeSnapShot(std::vector<std::string>& outs) = 0;
Parameters
| name | data type | description |
|---|---|---|
| outs | std::vector<std::string>& | 导出订阅的具体行情列表 |
Return
void
6.3.11 OnIndexCB - 指数行情快照回调
Synopsis
virtual void OnIndexCB(AHIndex* index)
Parameters
| name | data type | description |
|---|---|---|
| index | AHIndex* | 用户自定义实现的指数行情快照回调 |
Return
void
指数回调的时候, 参数类型为原生指针
AHIndex*
6.3.12 OnTickCB - 逐笔委托和逐笔成交回调
Synopsis
virtual void OnTickCB(AHTick* data, uint16_t type)
Parameters
| name | data type | description |
|---|---|---|
| trade | AHTick* | 用户自定义实现的逐笔委托和逐笔成交回调 |
| type | AType | 委托:192, 成交:191 |
Return
void
AHTick 是一个逐笔委托指针和逐笔成交指针的联合体, 后面有 type 标识数据类型
6.3.13 OnSnapshotCB - 集中竞价交易业务行情快照回调
Synopsis
virtual void OnSnapshotCB(AHSnapShot* snapshot)
Parameters
| name | data type | description |
|---|---|---|
| snap_shot | AHSnapshot* | 用户自定义实现的集中竞价交易业务行情快照回调回调 |
Return
void
快照回调的时候, 参数类型为原生指针
AHSnapshot*
6.4 数据结构说明
安湖行情系列产品,对于交易所标准行情数据,采用的是沪深交易所标准,只有对于个别字段考虑到系统的设计要求会有一些特殊处理。
对于传输层细节部分,可参考安湖SDK文档高阶 https://mdsdk.annhoo.cn/structannhoo_1_1_a_h_index.html
6.4.1 数据头定义(AHDataHeader)
struct AHDataHeader {
uint16_t MsgType; /*!< Quotes message type: 指数: 9011, 委托: 192, 成交: 191, 快照: 111 */
char ExchangeID[2]; /*!< Exchange identify: SZ or SH */
};
MsgType 详情:
- 指数: 9011
- 委托: 192
- 成交: 191
- 快照: 111
6.4.2 指数行情定义(AHIndex)
消息类型:9011 消息长度:106 数据结构:
struct AHIndex {
AHDataHeader header; /*!< Common header: MsgType: 9011, MsgLength: 100 */
char MDStreamID[4]; /*!< 深市行情类别,沪市缺失 */
union {
int64_t OrigTime; /*!< 数据生成时间 */
int64_t TradeTime; /*!< 沪市成交时间 */
};
uint16_t ChannelNo; /*!< 深市频道代码, 沪市缺失 */
char TradingPhaseCode[2]; /*!< 深市产品所处的交易阶段代码, 沪市缺失 */
char SecurityID[8]; /*!< 证券代码, format: 'xxxxxx '(end with two spaces) */
int64_t LastIndex; /*!< 最新价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t PreCloseIndex; /*!< 前收盘指数, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t OpenIndex; /*!< 今开盘, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t HighIndex; /*!< 最高价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t LowIndex; /*!< 最低价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t CloseIndex; /*!< 今收盘, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t TotalVolumeTrade; /*!< 成交总量 */
int64_t TotalValueTrade; /*!< 成交总金额, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t NumTrades; /*!< 深市成交笔数, 沪市缺失 */
};
模拟数据案例展示:
| key | val |
|---|---|
| msgtype | 9011 |
| ExchangeID | SZ |
| MDStreamID | 900 |
| OrigTime | 20220517094612000 |
| ChannelNo | 10 |
| TradingPhaseCode | T |
| SecurityID[8] | 399284 |
| LastIndex | 2608677400 |
| PreCloseIndex | 2609506600 |
| OpenIndex | 2611665800 |
| HighIndex | 2623839000 |
| LowIndex | 2604848600 |
| CloseIndex | 0 |
| TotalVolumeTrade | 10604617000 |
| TotalValueTrade | 20248596531300 |
| NumTrades | 169946 |
6.4.3 Tick行情定义(AHTick)
消息类型:tick 消息长度:76 数据结构:
struct AHTick {
AHDataHeader header; /*!< Command header, MsgType: 191/192/193 */
union {
char MDStreamID[4]; /*!< 深市的行情类别 */
uint16_t OrderIndex; /*!< 沪市的委托序号,从1开始,按channel连续 */
uint16_t TradeIndex; /*!< 沪市的成交序号,从1开始,按channel连续 */
char TickBSFlag[4]; /*!< 沪市逐笔:逐笔标识。委托:B=买单,S=卖单;产品状态订单:START=启动,
OCALL=开市集合竞价, TRADE=连续自动撮合, SUSP=停牌, CCALL=收盘集合竞价, CLOSE=闭市,
ENDTR=交易结束 */
};
union {
uint16_t ChannelNo; /*!< 深市频道代码 */
uint16_t Channel; /*!< 沪市委托通道。沪市逐笔通道 */
uint16_t TradeChannel; /*!< 沪市成交通道 */
};
union {
char Side; /*!< 深市委托时为买卖方向: 1=买, 2=卖, G=借入 F=出借, 深市成交缺失 */
char OrderBSFlag; /*!< 沪市委托时为:B=买单, S=卖单 */
char TradeBSFlag; /*!< 沪市成交为:B=外盘主动买,S=内盘主动卖,N=未知。沪市逐笔此字段已前置,故空 */
};
union {
char OrdType; /*!< 深市委托时订单类型时:1=市价,2=限价,U=本方最优 */
char OrderType; /*!< 沪市委托时订单类型时:A=新增委托订单,D=删除委托订单; 沪市成交缺失 */
char ExecType; /*!< 深市成交时订单类型时:4=撤销,F=成交 */
char Type; /*!< 沪市逐笔:A=新增委托订单,D=删除委托订单,S=产品状态订单,T=成交 */
};
union {
int64_t ApplSeqNum; /*!< 深市时,消息记录号从 1 开始计数*/
int64_t BizIndex; /*!< 沪市时,业务序列号与竞价逐笔成交消息合并后的连续编号,从 1 开始,按Channel 连续 */
};
char SecurityID[8]; /*!< 证券代码 */
union {
int64_t Price; /*!< 深市委托价格, 实际值除以10000。沪市逐笔价格, 实际值除以1000 */
int64_t OrderPrice; /*!< 沪市委托价格, 实际值除以1000 */
int64_t LastPx; /*!< 深市成交价格, 实际值除以10000 */
int64_t TradePrice; /*!< 沪市成交价格, 实际值除以1000 */
};
union {
int64_t OrderQty; /*!< 深市委托数量, 除以100 */
int64_t Balance; /*!< 沪市委托数量, 除以1000 */
int64_t LastQty; /*!< 深市成交数量, 实际值除以100 */
int64_t TradeQty; /*!< 沪市成交数量, 实际值除以1000 */
int64_t Qty; /*! 沪市逐笔数量, 实际值除以100 */
};
union {
int64_t TransactTime; /*!< 深市委托/成交时间 */
int64_t OrderTime; /*!< 沪市委托时间 */
int64_t TradeTime; /*!< 沪市成交时间 */
int64_t TickTime; /*!< 沪市逐笔订单时间或者成交时间 */
};
union {
int64_t OrderNO; /*!< 沪市委托原始订单号 */
int64_t BidApplSeqNum; /*!< 深市成交, 买方委托索引从 1 开始计数,0 表示无对应委托 */
int64_t TradeBuyNo; /*!< 沪市成交, 买方订单号 */
int64_t BuyOrderNo; /*!< 沪市逐笔买方订单 */
};
union {
int64_t OfferApplSeqNum; /*!< 深市成交, 卖方委托索引从 1 开始计数,0 表示无对应委托 */
int64_t TradeSellNo; /*!< 沪市成交, 卖方订单号 */
int64_t SellOrderNo; /*!< 沪市逐笔买方订单 */
};
int64_t TradeMoney; /*!< 深市缺失,沪市成交金额, 实际值除以 100000。沪市逐笔:如果市新增委托(Type:
A):已成交的委托数量(精度为三位), 如果是成交(Type: T):成交金额(精度为五位) */
};
6.4.4 Tick深市回调数据案例:
深市委托行情数据案例: 消息类型:192
| key | val |
|---|---|
| msgtype | 192 |
| ExchangeID | SZ |
| MDStreamID | 011 |
| ChannelNo | 2013 |
| Side | 1 |
| OrdType | 2 |
| ApplSeqNum | 23293311 |
| SecurityID[8] | 002256 |
| Price | 26200 |
| OrderQty | 90000 |
| TransactTime | 20220517132752710 |
委托价:2.62元,买入900股
深市成交行情数据案例: 消息类型:191
| key | val |
|---|---|
| msgtype | 191 |
| ExchangeID | SZ |
| MDStreamID | 011 |
| ChannelNo | 2013 |
| ExecType | F |
| ApplSeqNum | 23294075 |
| SecurityID[8] | 003040 |
| LastPx | 199100 |
| LastQty | 80000 |
| TransactTime | 20220517132753170 |
| BidApplSeqNum | 23294074 |
| OfferApplSeqNum | 13737530 |
最近委托价为:19.19元,成交量:800股
6.4.5 Tick沪市行情回调数据案例
沪市委托行情数据案例: 消息类型:192
| key | val |
|---|---|
| msgtype | 192 |
| ExchangeID | SH |
| OrderIndex | 12585 |
| Channel | 1 |
| OrderBSFlag | S |
| OrderType | D |
| BizIndex | 16863389 |
| SecurityID [8] | 688220 |
| OrderPrice | 66000 |
| Balance | 1000000 |
| OrderTime | 20231030135731180 |
| OrderNO | 10530657 |
最近委托价为:66元,委托数量:1000股
沪市成交行情数据案例:
消息类型:191
| key | val |
|---|---|
| msgtype | 191 |
| ExchangeID | SH |
| TradeIndex | 8115 |
| TradeChannel | 1 |
| TradeBSFlag | B |
| OrderType | T |
| BizIndex | 16863537 |
| SecurityID | 601898 |
| TradePrice | 8570 |
| TradeQty | 200000 |
| TradeTime | 20231030135731320 |
| TradeBuyNo | 10532037 |
| TradeSellNo | 10528285 |
| TradeMony | 171400000 |
最近委托价为:8.57元,成交数量:200股,成交金额:1714元
6.4.6 快照行情定义(AHSnapshot)
消息类型:111 消息长度:514 数据结构:
struct AHSnapshot {
AHDataHeader header; /*!< Command header, MsgType: 111, MsgType: 514 */
char MDStreamID[4]; /*!< 深市行情类别,沪市缺失 */
union {
int64_t OrigTime; /*!< 数据生成时间 */
int64_t TradeTime; /*!< 沪市成交时间 */
};
uint16_t ChannelNo; /*!< 深市频道代码, 沪市缺失 */
char InstrumentStatus[2]; /*!< 沪市当前品种交易状态, 深市缺失 */
char TradingPhaseCode[4]; /*!< 当前产品状态 */
char SecurityID[8]; /*!< 证券代码, format: 'xxxxxx '(end with two spaces) */
int64_t BidPrice[10]; /*!< 十档申买价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t AskPrice[10]; /*!< 十档申卖价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t BidVolume[10]; /*!< 十档申买量 */
int64_t AskVolume[10]; /*!< 十档申卖量 */
int64_t PrevClosePx; /*!< 昨收价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t OpenPx; /*!< 今开盘, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t HighPx; /*!< 最高价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t LowPx; /*!< 最低价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t LastPx; /*!< 最新价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t ClosePx; /*!< 收盘价, 深市缺失, 沪市除以1000后为分 */
int64_t NumTrades; /*!< 成交笔数 */
int64_t TotalVolumeTrade; /*!< 成交总量 */
int64_t TotalValueTrade; /*!< 成交总金额 */
int64_t TotalBidQty; /*!< 委托买入总量 */
int64_t WeightedAvgBidPx; /*!< 加权平均委托买入价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t TotalOfferQty; /*!< 委托卖出总量 */
int64_t WeightedAvgOfferPx; /*!< 加权平均委托卖出价, 深市除以10000后为分, 沪市除以1000后为分 */
int64_t IOPV; /*!< 基金实时参考净值 */
int64_t LPV; /*!< 基金 T-1 日净值, 沪市缺失 */
int64_t UpperLimitPrice; /*!< 涨停价, 深市除以10000后为分, 沪市缺失 */
int64_t LowerLimitPrice; /*!< 跌停价, 深市除以10000后为分, 沪市缺失 */
int64_t OpenInterest; /*!< 合约持仓量, 沪市缺失 */
int64_t LastSubPrevClosePrice; /*!< 升跌一, 沪市缺失 */
int64_t LastSubPrevLastPrice; /*!< 升跌二, 沪市缺失 */
};
模拟环境下,案例数据展示:
| key | val |
|---|---|
| MsgType | 111 |
| ExchangeID | SZ |
| MDStreamID | 010 |
| Time | 20220517131115000 |
| ChannelNo | 1012 |
| TradingPhaseCode | T0 |
| SecurityID | 300994 |
| BidPrice[0] | 29960000 |
| BidPrice[1] | 29950000 |
| BidPrice[2] | 29940000 |
| BidPrice[3] | 29920000 |
| BidPrice[4] | 29910000 |
| BidPrice[5] | 29900000 |
| BidPrice[6] | 29870000 |
| BidPrice[7] | 29850000 |
| BidPrice[8] | 29800000 |
| BidPrice[9] | 29740000 |
| AskPrice[0] | 29990000 |
| AskPrice[1] | 30000000 |
| AskPrice[2] | 30010000 |
| AskPrice[3] | 30040000 |
| AskPrice[4] | 30050000 |
| AskPrice[5] | 30060000 |
| AskPrice[6] | 30080000 |
| AskPrice[7] | 30100000 |
| AskPrice[8] | 30120000 |
| AskPrice[9] | 30170000 |
| BidVolume[0] | 220000 |
| BidVolume[1] | 10000 |
| BidVolume[2] | 30000 |
| BidVolume[3] | 310000 |
| BidVolume[4] | 30000 |
| BidVolume[5] | 10000 |
| BidVolume[6] | 6170000 |
| BidVolume[7] | 520000 |
| BidVolume[8] | 50000 |
| BidVolume[9] | 40000 |
| AskVolume[0] | 100000 |
| AskVolume[1] | 330000 |
| AskVolume[2] | 320000 |
| AskVolume[3] | 330000 |
| AskVolume[4] | 10000 |
| AskVolume[5] | 10000 |
| AskVolume[6] | 10000 |
| AskVolume[7] | 150000 |
| AskVolume[8] | 10000 |
| AskVolume[9] | 50000 |
| PrevClosePx | 297100 |
| OpenPx | 29300000 |
| HighPx | 29980000 |
| LowPx | 28850000 |
| LastPx | 29980000 |
| ClosePx | 0 |
| NumTrades | 4971 |
| TotalVolumeTrade | 169965300 |
| TotalValueTrade | 497509300900 |
| TotalBidQty | 77280000 |
| WeightedAvgBidPx | 29110000 |
| TotalOfferQty | 29550000 |
| WeightedAvgOfferPx | 32070000 |
| IOPV | 0 |
| LPV | 0 |
| UpperLimitPrice | 35650000 |
| LowerLimitPrice | 23770000 |
| OpenInterest | 0 |
| LastSubPrevClosePrice | 270000 |
| LastSubPrevLastPrice | 30000 |
6.5 字典说明
6.5.1 TradingPhaseCode
产品所处的交易阶段代码
深交所:
- 第 0 位:S=启动(开市前),O=开盘集合竞价,T=连续竞价,B=休市,C=收盘集合竞价,E=已闭市,H=临时停牌,A=盘后交易,V=波动性中断
- 第 1 位:0=正常状态,1=全天停牌
上交所: 该字段为 8 位字符串,左起每位表示特定的含义,无定义则填空格
- 第 1 位:‘S’表示启动(开市前)时段,‘C’表示开盘集合竞价时段,‘T’表示连续交易时段,‘E’表示闭市时段,‘P’表示产品停牌,‘M’表示可恢复交易的熔断时段(盘中集合竞价),‘N’表示不可恢复交易的熔断时段(暂停交易至闭市),‘U’表示收盘集合竞价时段。
- 第 2 位:‘0’表示此产品不可正常交易,‘1’表示此产品可正常交易,无意义填空格。
- 第 3 位:‘0’表示未上市,‘1’表示已上市。
- 第 4 位:‘0’表示此产品在当前时段不接受订单申报,‘1’ 表示此产品在当前时段可接受订单申报。无意义填空格
7 其他
yaml格式校验
鉴于yaml语法格式的不熟悉或者误操作,程序提供了对yaml格式检查的工具和开关。我们可以通过环境变量的设置,对yaml文件进行检查。把以下语句添加到启动脚本中。
# yq 的文件路径
export YQ_LINUX_AMD=/home/annhoo/annhoo_md_sdk/tools
8 常见问题
启动异常 请查看启动日志,确定是否是由于版本原因还是硬件驱动问题,详情对照我们的环境说明。或者参考我们的线上文档:https://doc.annhoo.cn/fund/annhoo_md_sdk.html
如何确定自己的SDK运行模式 当客户使用我们的sdk运行后,启动日志中是有对应的运行日志记录的。如果是采用SF的ef_vi模式接收,在日志中会存在记录:EFVI_mode for tick market之类的数据。
修订记录
| 版本 | 日期 | 备注 |
|---|---|---|
| 0.0.1 | 2021-10-20 | 初稿 |
| 0.0.2 | 2021-12-29 | 重构架构和内存管理方式, 添加主备方案 |
| 0.1.0 | 2022-08-20 | 添加多网卡时的网口绑定, cpu绑定等 |
| 0.1.1 | 2022-10-10 | 补充案例和说明 |
| 0.4.0 | 2023-02-01 | tick数据及其接口 |
| 1.1.2 | 2023-05-13 | 支持solar flare |
| 1.6.0 | 2023-10-30 | 对原结构体做调整,增加OrderNO,BizIndex等字段 |
| 2.0.1 | 2024-01-30 | 新增登录校验 |
| 2.0.2 | 2024-02-29 | 新增tcp模式 |
| 2.1.0 | 2023-03-29 | 新增配置文件校验和普通网卡 |
| 2.2.0 | 2023-04-18 | 支持沪市逐笔合并后的tick消息分发处理 |
| 2.2.1 | 2023-04-27 | 修复登录bug |
| 2.2.2 | 2023-05-07 | 补充solare flare onload版本信息 |
| 3.0.0 | 2023-05-27 | 优化系统网络接收性能,超低时延获取行情数据 |
| 3.1.0 | 2023-06-18 | 增加配置项ini格式,简化配置同时优化sdk性能 |