深圳证券交易所Binary行情数据,MDC_VSS_DEMO数据接收示例代码


import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;

/**
 * MDC VSS连接客户端
 * Vendor Supplied System 接入用户服务器(简称“VSS”)
 */
public class SjsVss {


    /**
     * 登录消息
     *
     * @return
     */
    private static byte[] getLogonMsg() {
        byte[] msgTypeArr = toHH(1);
        byte[] msgLengthArr = toHH(20 + 20 + 4 + 16 + 32);

        byte[] senderIDArr = getLogonBytes("VSS", 20);
        byte[] targetIDArr = getLogonBytes("VDE", 20);
        byte[] xintiao = toHH(30);//心跳

        byte[] mimaArr = getLogonBytes("", 16); //api模式才填, vss模式空着
        byte[] xieyiArr = getLogonBytes("1.02", 32);

        byte[] msgHeadBody = byteMerger(msgTypeArr, msgLengthArr);
        msgHeadBody = byteMerger(msgHeadBody, senderIDArr);
        msgHeadBody = byteMerger(msgHeadBody, targetIDArr);
        msgHeadBody = byteMerger(msgHeadBody, xintiao);
        msgHeadBody = byteMerger(msgHeadBody, mimaArr);
        msgHeadBody = byteMerger(msgHeadBody, xieyiArr);

        byte[] check = toHH(GenerateCheckSum(msgHeadBody));
        byte[] r = byteMerger(msgHeadBody, check);
        return r;
    }

    private static byte[] hexStringToByteArr(String s) {
        if (s == null || s.equals("")) {
            return null;
        }
        s = s.replace(" ", "");
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return baKeyword;
    }

    /**
     * 发送数据转换时按高字节序列转换
     * int 转 byte[]   高字节在前(高字节序)
     *
     * @param n
     * @return
     */
    public static byte[] toHH(int n) {
        byte[] b = new byte[4];
        b[3] = (byte) (n & 0xff);
        b[2] = (byte) (n >> 8 & 0xff);
        b[1] = (byte) (n >> 16 & 0xff);
        b[0] = (byte) (n >> 24 & 0xff);
        return b;
    }

    /**
     * byte数组合并
     *
     * @param bt1
     * @param bt2
     * @return
     */
    public static byte[] byteMerger(byte[] bt1, byte[] bt2) {
        byte[] bt3 = new byte[bt1.length + bt2.length];
        System.arraycopy(bt1, 0, bt3, 0, bt1.length);
        System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
        return bt3;
    }

    private static byte[] getLogonBytes(String s, int len) {
        byte[] vssCs = s.getBytes();
        byte[] senderIDArr = new byte[len];
        for (int i = 0; i < senderIDArr.length; i++) {
            senderIDArr[i] = 32;//空的字符串默认必须填 32(空格)
        }
        System.arraycopy(vssCs, 0, senderIDArr, 0, vssCs.length);
        return senderIDArr;
    }


    /**
     * byte数组转hex
     *
     * @param bytes
     * @return
     */
    public static String byteToHex(byte[] bytes) {
        String strHex = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < bytes.length; n++) {
            strHex = Integer.toHexString(bytes[n] & 0xFF);
            sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0
        }
        return sb.toString().trim();
    }

    /**
     * 心跳消息
     *
     * @return
     */
    private static byte[] getHeartbeatMsg() {
        byte[] msgTypeArr = toHH(3);
        byte[] msgLengthArr = toHH(0);
        byte[] headAndLenArr = byteMerger(msgTypeArr, msgLengthArr);

        byte[] check = toHH(GenerateCheckSum(headAndLenArr));
        byte[] r = byteMerger(headAndLenArr, check);
        return r;
    }


    /**
     * 生成消息尾校验
     *
     * @param bytes
     * @return
     */
    public static int GenerateCheckSum(byte[] bytes) {
        int sum = 0;
        for (int b : bytes) {
            sum += (int) b;
        }
        return sum % 256;
    }


    /**
     * 读数据线程处理
     */
    static class ReadThread extends Thread {
        InputStream readStream;

        public ReadThread(InputStream readStream) {
            this.readStream = readStream;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    //消息类型
                    byte[] msgTypeBs = new byte[4];
                    readStream.read(msgTypeBs, 0, msgTypeBs.length);
                    int msgTypeInt = ByteBuffer.wrap(msgTypeBs).getInt();

                    //消息长度
                    byte[] msgLenBs = new byte[4];
                    readStream.read(msgLenBs, 0, msgLenBs.length);
                    int msgLengthInt = ByteBuffer.wrap(msgLenBs).getInt();

                    //消息体
                    byte[] msgBodyBs = new byte[msgLengthInt];
                    readStream.read(msgBodyBs, 0, msgBodyBs.length);

                    //消息尾,校验
                    byte[] msgCheckBs = new byte[4];
                    readStream.read(msgCheckBs, 0, msgCheckBs.length);

                    /**
                     * 根据不同类别解析消息体
                     * 表 4-13-0 快照行情数据类别列表
                     * 行情类别
                     * MDStreamID
                     * 说明 消息类型 有无扩展
                     * 字段
                     * 010 现货(股票,基金等)集中竞价交易快照行情 300111 Y
                     * 040 期权集中竞价交易快照行情
                     * 020 债券通用质押式回购匹配交易快照行情 300211 Y
                     * 030 债券分销快照行情
                     * 410 债券现券交易快照行情
                     * 060 以收盘价交易的盘后定价大宗交易快照行情 300611 Y
                     * 061 以成交量加权平均价交易的盘后定价大宗交
                     * 易快照行情
                     * 工程技术标准 深圳证券交易所 Binary 行情数据接口规范
                     *  第 16 页 共 37 页
                     * 370 盘后定价交易快照行情 303711 Y
                     * 630 港股实时行情 306311 Y
                     * 900 指数快照行情 309011 Y
                     * 910 成交量统计指标快照行情 309111 Y
                     * 920 国证指数快照行情 309011 Y
                     */

                    System.out.println("msgTypeInt:" + msgTypeInt);
                    System.out.println("msgLengthInt:" + msgLengthInt);
                    System.out.println("msgBody:" + new String(msgBodyBs));
                    if (msgTypeInt == 1) {
                        //返回登录消息,啥也不干
                    } else if (msgTypeInt == 300111) {
                        /**
                         * 4.5.4 快照行情
                         * 表 4-13 MDGW 发布快照行情消息定义
                         * 域名 字段描述
                         * Standard Header
                         * 消息头
                         * MsgType=3xxx11
                         * OrigTime 数据生成时间  int64
                         * ChannelNo 频道代码 int16
                         * MDStreamID 行情类别 char[3]
                         * SecurityID 证券代码 char[8]
                         * SecurityIDSource 证券代码源 char[4]
                         * TradingPhaseCode 产品所处的交易阶段代码 char[8]
                         * PrevClosePx 昨收价
                         * NumTrades 成交笔数
                         * TotalVolumeTrade 成交总量
                         * TotalValueTrade 成交总金额
                         * Extend Fields 各业务扩展字段
                         */

                        {
                            //数据生成时间 int64
                            byte[] OrigTimeArr = new byte[8];
                            System.arraycopy(msgBodyBs, 0, OrigTimeArr, 0, OrigTimeArr.length);
                            long OrigTime = ByteBuffer.wrap(OrigTimeArr).getLong();//20211118085506000
                            System.out.println(OrigTime);
                        }
                        {
                            //ChannelNo 频道代码 int16
                            /**
                             * 集中竞价交易
                             * 快照行情
                             * 股票 101x 行情快照消息(300111)
                             * 基金 102x
                             * 可转债 103x
                             * 权证 104x
                             * 期权 105x
                             * 集中竞价交易
                             * 逐笔行情
                             * 股票 201x 逐笔委托消息(300192)
                             * 逐笔成交消息(300191) 基金 202x
                             */
                            byte[] ChannelNoArr = new byte[2];
                            System.arraycopy(msgBodyBs, 8, ChannelNoArr, 0, ChannelNoArr.length);
                            short ChannelNo = ByteBuffer.wrap(ChannelNoArr).getShort();
                            System.out.println(ChannelNo);
                        }
                        {
                            //MDStreamID 行情类别 char[3]
                            byte[] MDStreamIDArr = new byte[3];
                            System.arraycopy(msgBodyBs, 8 + 2, MDStreamIDArr, 0, MDStreamIDArr.length);
                            String MDStreamID = new String(MDStreamIDArr, "UTF-8");//010 现货(股票,基金等)集中竞价交易快照行情
                            System.out.println(MDStreamID);
                        }
                        {
                            //SecurityID 证券代码 char[8]
                            byte[] SecurityIDArr = new byte[8];
                            System.arraycopy(msgBodyBs, 8 + 2 + 3, SecurityIDArr, 0, SecurityIDArr.length);
                            String SecurityID = new String(SecurityIDArr, "UTF-8");
                            System.out.println(SecurityID);
                        }
                        {
                            /**
                             * SecurityIDSource 证券代码源 char[4]
                             * 证券代码源
                             * 102=深圳证券交易所
                             * 103=香港交易所
                             */
                            byte[] SecurityIDSourceArr = new byte[4];
                            System.arraycopy(msgBodyBs, 8 + 2 + 3 + 8, SecurityIDSourceArr, 0, SecurityIDSourceArr.length);
                            String SecurityIDSource = new String(SecurityIDSourceArr, "UTF-8");//
                            System.out.println(SecurityIDSource);
                        }
                    } else {

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }

    }


    public static void main(String[] args) {

        try {

//            {
//                var socket = new Socket("192.168.20.11", 9230);
//                var outStream = socket.getOutputStream();
//                outStream.write(getLogonMsg());
//                outStream.flush();
//            }
            //发登录消息
            Socket socket = new Socket("192.168.20.11", 9130);
            OutputStream outStream = socket.getOutputStream();
            outStream.write(getLogonMsg());
            outStream.flush();

            //线程读消息
            ReadThread readThread = new ReadThread(socket.getInputStream());
            readThread.start();

            //定时发心跳
            while (true) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                outStream.write(getHeartbeatMsg());
                outStream.flush();
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值