上交所FAST行情接口对接

这篇具有很好参考价值的文章主要介绍了上交所FAST行情接口对接。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  • 前言

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

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

GitHub - kuangtu/fixfast: 对于fast协议通过OpenFast进行分析

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

SSE Level 2 Vendor Interface Specification(FAST)-15章-FAST Decoder(FAST解析-第四部分)_wqfhenanxc的博客-CSDN博客(这只是一部分,该博客还有同系列的其他文章)

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

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

Openfast下载:

OpenFAST download | SourceForge.net

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

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,参考资料如下:

国内交易所协议FIX STEP FAST Binary_wqfhenanxc的博客-CSDN博客_binary协议

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

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

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

  1. 取消了Key,使用模板(temple)来约定各字段的含义
  2. 使用二进制而不是字符串的形式来传输
  3. 在二进制的基础上使用了非常特别(而且看不懂)的压缩方法,进一步做了压缩。

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

上交所行情对接开发,上交所,行情,FAST,step

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

  • 登录

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

 上交所行情对接开发,上交所,行情,FAST,step

  • STEP解析

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

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

 上交所行情对接开发,上交所,行情,FAST,step

上交所行情对接开发,上交所,行情,FAST,step

  • FAST解析

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

上交所行情对接开发,上交所,行情,FAST,step

输出结果如下:

上交所行情对接开发,上交所,行情,FAST,step

 由于中文还得特别处理下,所以这里显示的是乱码,另外我为了简便都是以string格式读的,按说不太合适,大家自行研究吧,可以看openfast的文档看都有啥函数。文章来源地址https://www.toymoban.com/news/detail-801167.html

完整代码如下:

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());
		}
	}
}

到了这里,关于上交所FAST行情接口对接的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • IoT-Fast支持C#啦!教你对接HslCommunication

    导读:IoT-Fast是一款全流程低代码物联网平台,提供了丰富的设备采集控制协议(Modbus RTU 串口、Modbus TCP 网口、通用 OpcUa 通讯协议、西门子 S7 通讯协议、三菱 Fx-Serial 协议、三菱 MC 通讯协议、欧姆龙 HostLink 通讯协议、欧姆龙 FinS 通讯协议、霍尼韦尔 Logix 通讯协议、松下 M

    2024年02月10日
    浏览(36)
  • 用Python编程实现百度自然语言处理接口的对接,助力你开发智能化处理程序

    用Python编程实现百度自然语言处理接口的对接,助力你开发智能化处理程序 随着人工智能的不断进步,自然语言处理(Natural Language Processing,NLP)成为了解决文本处理问题的重要工具。百度自然语言处理接口提供了一系列强大的功能,如提取、文本分类、情感分析等,

    2024年02月13日
    浏览(105)
  • 设计模式之美-实战二:如何对接口鉴权这样一个功能开发做面向对象分析?

            面向对象的三个环节:面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程(OOP)。只知道OOA、OOD、OOP只能说有一个宏观了解,我们更重要的还是要知道“如何做”,也就是,如何进行面向对象分析、设计与编程。         本文结合一个真实的开发案例,从基

    2024年02月09日
    浏览(48)
  • Java 亚马逊Amazon spapi对接开发,java Sdk,授权和接口访问步骤详细说明

    确认是否收到通过sp-api开发人员资料申请。   创建一个策略,我们建议您将 IAM 策略命名为 SellingPartnerAPI 。     开发商名称:任意字符 开发者id :accessKeyId 客户端相关信息,包含clientId和clientSecret。 1.8.1访问需要的参数和数据如图 参数 说明 样例 roleArn 角色Arn,在角色中

    2024年02月03日
    浏览(46)
  • 通达信l1l2行情接口-十档行情有哪些优势?

    据提供系统或用户编制的条件选股公式进行选股选定一个条件选股公式或多个组合条件后,计算机自动帮您选出当时或历史上某一段时间内满足条件的所有股票十档行情 英文,列在行情下载显示窗口,同时可保留成板块。 那通达信l1l2行情接口-十档行情有哪些优势? 1、主要

    2024年01月16日
    浏览(38)
  • 通达信l2行情接口怎么用?

    通达信L2行情接口, 包括了普通行情接口所有功能,并新增了十档行情,逐笔成交,买卖队列和深圳逐笔委托(上海证券交易所不对外提供逐笔委托数据)这四个新功能。 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace TdxH

    2023年04月10日
    浏览(50)
  • 63.网游逆向分析与插件开发-游戏增加自动化助手接口-自动化助手UI与游戏菜单的对接

    内容来源于: 易道云信息技术研究院VIP课 上一个内容:游戏公告类的C++还原-CSDN博客 码云地址(master分支):https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本号:19a2828def451a280ee211c62dcd1074ed422054 代码下载地址,在 SRO_EX 目录下,文件名为:SRO_Ex-自动化助手UI与游戏菜单的对接.

    2024年02月02日
    浏览(43)
  • 新浪股票行情数据接口有什么作用?

    通过 新浪股票行情数据接口 可以让投资者在实际交易当中能够更加精准的洞悉盘口变化。该接口可以说是目前最好用的免费股票行情数据接口了,虽然一直并未公开,但暂时使用良好。大家用浏览器访问新浪的股票行情数据接口就能查看最新行情数据了。那么今天小编简单

    2024年02月01日
    浏览(52)
  • 炒股有必要买L2行情数据接口吗?

            全推L2行情数据股票软件有 level2数据 后,市场上只有一两个股票池功能。方便公式的引用和计算,及时进入股票池。一般市场只有分笔数据,一个分笔数据含有10-20个分笔数据,用分笔数据计算的资金流入数据不如分笔数据准确。因此,逐笔数据计算资金流入更为准

    2024年02月03日
    浏览(42)
  • 通过股票数据接口如何看懂Level-2行情?

    交易用户在进行投资的时候,通过股票数据接口来实现自己的盈利目标,今天来聊聊如何看懂Level-2行情? 在交易开盘之后某股快速杀跌,但杀跌后盘面缺不跌反涨,甚至一度差点翻红,如果是五档行情,我们并不知道发生了什么。 如果通过十档行情功能,我们就能发现买

    2024年02月12日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包