首页 > 其他分享 >上交所FAST行情接口对接

上交所FAST行情接口对接

时间:2022-10-15 19:45:56浏览次数:78  
标签:openfast 对接 接口 STEP FAST import byte 解析

一、前言

之前已完成了Binary行情的解析,接着便继续研究FAST(STEP)行情,但花费了将近一个月时间才终于搞定了。前面说过Binary格式的行情不太直观,所以对于初学者有点难度,接触FAST后才知道什么叫“完全看不明白”。还好互联网是伟大的,大佬们偶尔留下的只言片语对我们来说就是难得的启迪了。

一开始我是想人肉解析的,但确实没看明白,找到的参考资料如下:

https://github.com/kuangtu/fixfast

上述链接的资料非常全,但恕我真的没看懂,接着推荐另一份资料:

https://blog.csdn.net/wqfhenanxc/article/details/86512143(这只是一部分,该博客还有同系列的其他文章)

两个结合起来看终于搞明白了“停止位”和“map”,但实际解析还是不对,故放弃转而开始研究openfast。

事实上关于openfast的资料也非常稀有,而且大都只是提了几句完全无法使用,但经过我不懈的努力,还是找到了一些有用的资料。

Openfast下载:

https://sourceforge.net/projects/openfast/

非常有参考价值的一个示例:

https://blog.csdn.net/qq_33601179/article/details/122407384?spm=1001.2014.3001.5502(此链接也只是一部分,该博客还有同系列其他文章)

有了之前binary的经验以及上述资料的加持,我终于把FAST行情初步给搞出来了,不过截至目前我只是用openfast解析出了内容,并没有做深入研究,所以仅供各位看官参考。

另附上官方参考文档:

《上海证券交易所低延时行情发布系统(LDDS)接口说明书》

《上海证券交易所LDDS系统Level-1 FAST行情接口说明书》

《IS120_上海证券交易所行情网关STEP数据接口规范》

 

二、FAST接口

要搞明白FAST就得先搞清楚fix、step,参考资料如下:

https://blog.csdn.net/wqfhenanxc/article/details/81042310

简单来说,FIX就是KEY=VALUE这样的一对数据,中间用一个特殊符号分割开,解析起来比较容易而且新增、修改接口也比较简单。但缺点是过于冗长了,传输金融行情数据占用很大的带宽,不是很科学。

STEP跟FIX看起来差不多,只是做了一些本地化,没详细研究也不知道做了啥修改,不多说。

由于FIX、STEP都比较冗长,所以又整出了FAST。首先FAST也是源于KEY=VALUE这样的格式,然后在此基础上做了压缩,所以所谓的FAST解析就是把它还原成KEY=VALUE这样。FAST压缩的大致方法如下:

1、取消了Key,使用模板(temple)来约定各字段的含义

2、使用二进制而不是字符串的形式来传输

3、在二进制的基础上使用了非常特别(而且看不懂)的压缩方法,进一步做了压缩。

而上交所在发FAST行情时,还给他套了个STEP的壳,而且是双重壳,见下图:

 

 

 

STEP的内容直接输出成字符串即可,可读性很强,但FAST的内容全都是乱码了,因为它即是二进制又做了压缩。虽然FAST协议本身很难看懂,但借助openfast我们可以很容易解析出数据,那么现在的问题就是如何获取FAST的内容。

 

三、登录

与binary类似,只需要按指定的格式发信息到VDE即可,这一块参考官方文档很容易就接入了。其中“\u0001”就是SOH这个分隔符了。

 

 

 

四、STEP解析

你把从接口获取到的内容直接字符串输出,可以看到STEP部分很好处理,而FAST部分全是乱码,所以要把FAST部分完整的截取出来用openfast来解析。如果你用SOH来分割还不行,因为FAST里有很多“00000001”这样的数据,所以你得先解析出FAST的长度,然后根据长度去读byte数组,读刚好那么长的byte数组出来,直接怼到openfast里解析就行了。

这里我偷懒直接通过数SOH找到FAST的长度,也就是tag95,注意因为套娃的关系,是第二个tag95的值。

 

 

 

 

 

 

五、FAST解析

前面把FAST的内容读出来了,解析的话就是用openfast即可,具体openfast的使用好似也比较多样,我这里就参考前面博文随便写了下,没有深入研究。

 

 

 

输出结果如下:

 

 

 

由于中文还得特别处理下,所以这里显示的是乱码,另外我为了简便都是以string格式读的,按说不太合适,大家自行研究吧,可以看openfast的文档看都有啥函数。

 

完整代码如下:

 

import java.io.InputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.*;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.openfast.template.MessageTemplate;
import org.openfast.template.loader.XMLMessageTemplateLoader;
import org.openfast.Context;
import org.openfast.codec.FastDecoder;
import org.openfast.Message;

public class connSHFAST2{
    public static String getCheckSum(String str){
        byte[] strBytes = str.getBytes();
        int sum = 0;
        for(byte b : strBytes){
            int bInt = b&0xff;
            sum += bInt;
            sum = sum&0xff;
        }
        String sumStr = sum + "";
        if(sumStr.length()==1){
            sumStr = "00"+sumStr;
        }else if(sumStr.length()==2){
            sumStr = "0"+sumStr;
        }
        return sumStr;
    }
    /**
     * 把byte转化成2进制字符串
     * @param b
     * @return
     */
    public static String getBinaryStrFromByte(byte b){
        String result ="";
        byte a = b; ;
        for (int i = 0; i < 8; i++){
            byte c=a;
            a=(byte)(a>>1);//每移一位如同将10进制数除以2并去掉余数。
            a=(byte)(a<<1);
            if(a==c){
                result="0"+result;
            }else{
                result="1"+result;
            }
            a=(byte)(a>>1);
        }
        return result;
    }
    static class ReadThread extends Thread{
        InputStream readStream;
        public ReadThread(InputStream readStream){
            this.readStream = readStream;
        }
        @Override
        public void run(){
            try{
                System.out.println("thread run...");
                while(true){
                    byte[] buffer = new byte[102400];
                    int len = readStream.read(buffer,0,102400);
                    //读到的数据太少
                    if(len<28){
                        System.out.println("len<28");
                        Thread.sleep(1000);
                        continue;
                    }
                    //读到的数据太多
                    if(len>=102400){
                        System.out.println("len>=102400");
                        continue;
                    }
                    //截取有效部分
                    byte[] step = Arrays.copyOf(buffer,len);
                    //逐一读取byte,数SOH,数到第27个
                    int count = 0;
                    int start = 0;
                    len = 0;
                    for(int i=0; i<step.length; i++){
                        byte b = step[i];
                        int bInt = b & 0xFF;
                        if(bInt==1){
                            count = count + 1;
                            if(count == 1){
                                len = i - start;
                                byte[] BeginString = new byte[len];
                                System.arraycopy(step,start,BeginString,0,len);
                                System.out.println("BeginString="+new String(BeginString));
                                start = i+1;
                            }
                            if(count == 2){
                                len = i - start;
                                byte[] BodyLength = new byte[len];
                                System.arraycopy(step,start,BodyLength,0,len);
                                System.out.println("BodyLength="+new String(BodyLength));
                                start = i+1;
                            }
                            if(count == 3){
                                len = i - start;
                                byte[] MsgType = new byte[len];
                                System.arraycopy(step,start,MsgType,0,len);
                                System.out.println("MsgType="+new String(MsgType));
                                start = i+1;
                                if(!"35=UA5302".equals(new String(MsgType))){
                                    System.out.println("MsgType!=UA5302");
                                    break;
                                }
                            }
                            if(count == 26){
                                start = i+1;
                            }
                            if(count==27){
                                len = i - start;
                                byte[] Tag95 = new byte[len];
                                System.arraycopy(step,start,Tag95,0,len);
                                System.out.println("Tag95="+new String(Tag95));
                                byte[] FastLenBG = new byte[len-3];
                                System.arraycopy(Tag95,3,FastLenBG,0,len-3);
                                int FastLen = Integer.parseInt(new String(FastLenBG));
                                System.out.println("FastLen="+FastLen);
                                start = i+1;
                                //读取FAST内容
                                byte[] FAST = new byte[FastLen];
                                System.arraycopy(step,start+3,FAST,0,FastLen);
                                //System.out.println("FAST="+new String(FAST));
                                //解析FATS内容
                                InputStream inputStream = new FileInputStream("template.xml");
                                MessageTemplate template = new XMLMessageTemplateLoader().load(inputStream)[0];
                                
                                Context context = new Context();
                                context.registerTemplate(4001, template);
                                
                                InputStream sbs = new ByteArrayInputStream(FAST);
                                
                                FastDecoder fastDecoder = new FastDecoder(context, sbs);
                                
                                Message msg111 = fastDecoder.readMessage();
                                System.out.println("MDStreamID="+msg111.getString("MDStreamID"));
                                System.out.println("SecurityID="+msg111.getString("SecurityID"));
                                System.out.println("Symbol="+msg111.getString("Symbol"));
                                System.out.println("NumTrades="+msg111.getString("NumTrades"));
                                System.out.println("TradeVolume="+msg111.getString("TradeVolume"));
                                System.out.println("TotalValueTraded="+msg111.getString("TotalValueTraded"));
                                System.out.println("PrevClosePx="+msg111.getString("PrevClosePx"));
                                System.out.println("PrevSetPx="+msg111.getString("PrevSetPx"));
                                System.out.println("TotalLongPosition="+msg111.getString("TotalLongPosition"));
                            }
                        }
                    }

                }
            }catch(Exception e){
                System.out.println(e.getMessage());
            }
        }
    }
    public static void main(String[] args){
        try{
            //head
            String BeginString = "8=STEP.1.0.0\u0001";
            String BodyLength = "9=56\u0001";//除了 8、9、10 域,所 有其他域长度总和
            String MsgType = "35=A\u0001";
            String SenderCompID = "49=VSS\u0001";
            String TargetCompID = "56=VDE\u0001";
            String MsgSeqNum = "34=0\u0001";
            String SendingTime = "52=20220916-11:00:00\u0001";
            //body
            String EncryptMethod = "98=0\u0001";
            String HeartBtInt = "108=0\u0001";
            //check body,用于做校验和的
            String CheckBody = BeginString+BodyLength+MsgType+SenderCompID
                                +TargetCompID+MsgSeqNum+SendingTime
                                +EncryptMethod+HeartBtInt;
            //checksum 除了10域本身,对所有其他域的每个字节累加后取256的余数。余数不足3位的,前补0
            String CheckSum = "10="+getCheckSum(CheckBody)+"\u0001";
            String MsgBody = CheckBody + CheckSum;
            //connect
            Socket socket = new Socket("你的IP",端口);
            OutputStream outStream = socket.getOutputStream();
            outStream.write(MsgBody.getBytes());
            outStream.flush();
            //listion thread
            ReadThread readThread = new ReadThread(socket.getInputStream());
            readThread.start();
            while(true){
                Thread.sleep(3000);
                System.out.println("every 3000...");
            }
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
}

 

标签:openfast,对接,接口,STEP,FAST,import,byte,解析
From: https://www.cnblogs.com/cation/p/16794878.html

相关文章

  • 温控采集器对接-java版-modbus4j
    @​​TOC​​​​​​看此文说明你已经了解了modbus协议,这里不再赘述​​业务需求采集冷柜温控采集器的温度,web端显示各个冷柜的温度(​​定时采集​​)需求分析1,采集温度2.......
  • Function接口
    function(T,R)Rapply(Tt)根据类型T的参数获取类型R的结果使用场景例如,将String类型转化为Integer类型publicclassDemo1Apply{publicstaticIntegerc......
  • 网络通信——HTTP接口访问——移动数据格式JSON
        网络通信的交互数据格式有两大类,分别是JSON和XML。对于App来说,基本采用JSON格式与服务器通信。JSON相比XML的优势主要有两个:(1)手机流量很贵,表达同样的信息,J......
  • [Java] jackson 和 fastjson 处理 JSON对比
    JSON字符串->对象处理原型数值实体类@Setter@Getter@ToStringpublicclassInfo{privateintage;}测试代码@TestpublicvoidtestString()throwsJso......
  • VM系列振弦采集模块电源接口详细说明
    VM系列振弦采集模块电源接口详细说明VMXXX模块有多个电源接口,分别为:宽电压电源输入(VIN)、内核电源(VDD)、参考电压源(VREF)、振弦传感器激励电源(VSEN),各电源共用GND。 ......
  • 多通道振弦传感器无线采发仪VS-BOX通讯接口与电源接口定义
    多通道振弦传感器无线采发仪VS-BOX通讯接口与电源接口定义 VS-Box是以振弦、温度传感信号为主的多通道无线采发仪,并可扩展其它模拟(电流、电压、电阻)信号和数字信号(RS485......
  • 接口加签处理
    接口签名通过appid,appsecret,nonce(随机数字)timestamp和其他参数经过一定的规则组成的字符串,然后经过加密之后的sign值。sign签名的值一般是通过query参数或者请求头参数传......
  • python2 接口下载文件,文件名设置中文无效解决方案
    fromurllibimportquote_file_name=quote("测试".encode("utf-8"))data=models.AdaptationPChannel.export_active_project(start_date)response=HttpResponse......
  • 兆骑科创:推动投融资合作对接
        在这个快节奏的时代中,下一秒永远是未知的。选择和发明的每一个重要时刻都只有一次,如果在某一刻萌生一个念头,一定要抓住它。没有资金可以创业吗?答案是:当然可以。......
  • 操作系统导论习题解答(41. Fast File System (FFS))
    LocalityandTheFastFileSystem"oldUNIXfilesystem"lookedlikethis:superblock(S):containsinformationabouttheentirefilesysteminoderegion:conta......