Skip to content

现货 WebSocket 市场数据API

Wenqing Yu edited this page May 26, 2016 · 1 revision

Socket.io API是公开使用的, 即时市场行情和即时市场交易无需进行身份验证,但私人订单即时更新需要使用私人秘钥进行验证。 为确保正常使用Socket.io API,请提前在您的计算机中安装socket.io。Socket.io的相关知识可参考以下网站:

在代码中包含socket.io资源, 文中均为Javascript版本示例:

<script src="<YOUR PATH>/socket.io.js"></script> 

使用如下方式与BTCC的websocket服务器建立连接:

var socket = io ('https://websocket.btcc.com/'); 

使用 “subscribe” 方法订阅我们的websocket服务器推送的不同交易市场的即时交易信息;

## 订阅三个不同的市场 ##
socket.emit('subscribe', 'marketdata_cnybtc');
socket.emit('subscribe', 'marketdata_cnyltc');
socket.emit('subscribe', 'marketdata_btcltc');
socket.emit('subscribe', 'grouporder_cnybtc');
socket.emit('subscribe', 'grouporder_cnyltc');
socket.emit('subscribe', 'grouporder_btcltc');
Name Value Description
market_data string 订阅的市场数据可以是 'marketdata_cnybtc', 'marketdata_cnyltc' 或者 'marketdata_btcltc'中的一个或多个,以”,”作为分隔符
grouporder string 订阅市场深度数据,可以是 'grouporder_cnybtc', 'grouporder_cnyltc' 或者 'grouporder_btcltc'中的一个或多个,以”,”作为分隔符

即时市场行情

使用 “ticker” 方法监听即时市场行情并处理接收到的实时数据,示例:

socket.on('ticker', function (data) { console.log(data); });

接收到的数据样本

{
   buy: 2940.03
   date: 1410399073
   high: 2970
   last: 2940.04
   low: 2901
   market: "btccny"
   open: 2930.15
   prev_close: 2931.03
   sell: 2940.06
   vol: 15187.3352
   vwap: 2936.02
}

即时市场交易

使用 “trade” 方法监听即时市场交易数据并处理接收到的实时数据,示例:

socket.on('trade', function (data) { console.log(data); });
## 接收到的数据样本 ## 
{
	amount: 0.056
	date: 1402970632
	market: "btccny"
	price: 3735.83
	trade_id: 6069941
	type: "sell"
	}

即时市场深度

即时市场深度方法会实时返回市场上的5对未成交的买卖订单。 使用 “grouporder” 方法监听即时市场深度数据并处理接收到的实时数据,示例:

socket.on('grouporder', function (data) { console.log(data); });
## 接收到的数据样本 ## 
	{
	"grouporder":
	{
	"market":"btccny",
	"ask":[
	{"price":2405.04,"type":"ask","totalamount":0.1}, 
	{"price":2404.24,"type":"ask","totalamount":2.9544}, 
	{"price":2404.21,"type":"ask","totalamount":0.011}, 
	{"price":2404.02,"type":"ask","totalamount":0.011},
	{"price":2403.71,"type":"ask","totalamount":0.01}
	],
	"bid":[
	{"price":2402.74,"type":"bid","totalamount":0.099}, 
	{"price":2401.11,"type":"bid","totalamount":6},
	{"price":2401.1,"type":"bid","totalamount":1.0014},
	{"price":2400.66,"type":"bid","totalamount":0.1},
	{"price":2400.65,"type":"bid","totalamount":0.1066}
	]
	}
	}

私人订单即时更新

使用'private'方法订阅私人订单即时更新来接收处理私人订单数据。每当您的私人订单状态发生改变时,服务器就会主动推送此订单的最新状态给客户端。 此方法需要使用访问秘钥和秘密秘钥进行个人身份认证,和交易API的加密方法一致。请参照Java示例代码的以下部分进行加密和订阅处理:

//Use 'private' method to subscribe the order feed
	List arg = new ArrayList();
	arg.add(sm.get_payload());
	arg.add(sm.get_sign());
	socket.emit("private",arg);
## 接收到的数据样本 ## 
	{
	"amount": 0
	"id": 3804213
	"price": 33.51
	"market": "ltccny"
	"status": "closed"
	"date":1410400468 
	"type":"ask"
	"amount_original":1
	}

即时余额更新

使用'private'方法订阅即时余额更新来接收处理账户余额数据。每当您的余额发生改变时,服务器就会主动推送账户的相应最新余额给客户端。 此方法需要使用访问秘钥和秘密秘钥进行个人身份认证,和交易API的加密方法一致。请参照Java示例代码的以下部分进行加密和订阅处理:

//Use 'private' method to subscribe the order and account_info feed
	List arg = new ArrayList();
	arg.add(sm.get_payload());
	arg.add(sm.get_sign());
	socket.emit("private",arg);
## 接收到的数据样本 ## 
	{
	"balance": 
	{
	"amount":0.0349086,
	"symbol":"฿",
	"currency":"BTC"
	}
	}
	{
	"balance":
	{
	"amount":10.191074,
	"symbol":"¥",
	"currency":"CNY"
	}
	}

示例代码

点击以下链接,获取更多Socket.io客户端示例源代码: Python: https://github.com/BTCChina/btcchina-websocket-api-python Java: https://github.com/BTCChina/btcchina-websocket-api-java Ruby: https://github.com/BTCChina/btcchina-websocket-api-ruby JavaScript: https://github.com/BTCChina/btcchina-websocket-api-js C++: https://github.com/BTCChina/btcchina-api-cpp C#: https://github.com/BTCChina/btcchina-api-csharp

JAVASCRIPT

<script src="./js/socket.io.js"></script>
<script>
var socket = io('https://websocket.btcc.com/'); 
socket.emit('subscribe', 'marketdata_cnybtc');
socket.emit('subscribe', 'marketdata_cnyltc');
socket.emit('subscribe', 'marketdata_btcltc');
socket.emit('subscribe', 'grouporder_cnybtc');
socket.emit('subscribe', 'grouporder_cnyltc');
socket.emit('subscribe', 'grouporder_btcltc'); 
socket.on('connect', function(){
socket.on('trade', function (data) {
console.log(data);
});
socket.on('ticker', function (data) {
console.log(data);
});
socket.on('grouporder', function (data) {
console.log(data);
});
});
</script>

JAVA

// an example
	import com.github.nkzawa.emitter.Emitter;
	import com.github.nkzawa.socketio.client.IO;
	import com.github.nkzawa.socketio.client.Socket;
	import java.net.URISyntaxException;
	import java.util.ArrayList;
	import java.util.List;
	import java.util.logging.Level;
	import java.util.logging.Logger;
	import javax.crypto.Mac;
	import javax.crypto.spec.SecretKeySpec;
	import javax.xml.bind.DatatypeConverter;
	import org.json.JSONObject; 
	public class SocketMain { 
	private String ACCESS_KEY="YOUR_ACCESS_KEY";
	private String SECRET_KEY="YOUR_SECRET_KEY";
	private static String HMAC_SHA1_ALGORITHM = "HmacSHA1";
	private String postdata="";
	private String tonce = ""+(System.currentTimeMillis() * 1000);
	public static void main(String[] args) throws Exception {
	try {
	IO.Options opt = new IO.Options();
	opt.reconnection = true;
	Logger.getLogger(SocketMain.class.getName()).setLevel(Level.FINE);
	final Socket socket = IO.socket("https://websocket.btcc.com", opt); 
	socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
	SocketMain sm= new SocketMain();
	@Override
	public void call(Object... args) {
	System.out.println("connected");
	socket.emit("subscribe", "marketdata_cnybtc"); // subscribe
	socket.emit("subscribe", "marketdata_cnyltc"); // subscribe another market
	socket.emit("subscribe", "marketdata_btcltc"); // subscribe another market
	socket.emit("subscribe", "grouporder_cnybtc"); // subscribe grouporder 
	socket.emit("subscribe", "grouporder_cnyltc"); // subscribe another market
	socket.emit("subscribe", "grouporder_btcltc"); // subscribe another market
	//Use 'private' method to subscribe the order and account_info feed
	try {
	List arg = new ArrayList();
	arg.add(sm.get_payload());
	arg.add(sm.get_sign());
	socket.emit("private",arg);
	} catch (Exception e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
	}
	}
	}).on("trade", new Emitter.Listener() {
	@Override
	public void call(Object... args) {
	JSONObject json = (JSONObject) args[0]; //receive the trade message
	System.out.println(json); 
	}
	}).on("ticker", new Emitter.Listener() {
	@Override
	public void call(Object... args) {
	JSONObject json = (JSONObject) args[0];//receive the ticker message
	System.out.println(json);
	}
	}).on("grouporder", new Emitter.Listener() {
	@Override
	public void call(Object... args) {
	JSONObject json = (JSONObject) args[0];//receive the grouporder message
	System.out.println(json);
	}
	}).on("order", new Emitter.Listener() {
	@Override
	public void call(Object... args) {
	JSONObject json = (JSONObject) args[0];//receive your order feed
	System.out.println(json);
	}
	}).on("account_info", new Emitter.Listener() {
	@Override
	public void call(Object... args) {
	JSONObject json = (JSONObject) args[0];//receive your account_info feed
	System.out.println(json);
	}
	}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
	@Override
	public void call(Object... args) {
	System.out.println("disconnected");
	}
	});
	socket.connect();
	} catch (URISyntaxException ex) {
	Logger.getLogger(SocketMain.class.getName()).log(Level.SEVERE, null, ex);
	}
	} 
	public String get_payload() throws Exception{
	postdata = "{\"tonce\":\""+tonce.toString()+"\",\"accesskey\":\""+ACCESS_KEY+"\",\"requestmethod\": \"post\",\"id\":\""+tonce.toString()+"\",         \"method\": \"subscribe\", \"params\": [\"order_cnyltc\",\"account_info\"]}";//subscribe order feed for cnyltc market and balance feed
	System.out.println("postdata is: " + postdata);
	return postdata;
	}
	public String get_sign() throws Exception{
	String params = "tonce="+tonce.toString()+"&accesskey="+ACCESS_KEY+"&requestmethod=post&id="+tonce.toString()+"&method=subscribe&params=order_cnyltc,account_info"; //subscribe the order of cnyltc market and the account_info
	String hash = getSignature(params, SECRET_KEY);
	String userpass = ACCESS_KEY + ":" + hash;
	String basicAuth = DatatypeConverter.printBase64Binary(userpass.getBytes());
	return basicAuth;
	}
	public String getSignature(String data,String key) throws Exception {
	// get an hmac_sha1 key from the raw key bytes
	SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
	// get an hmac_sha1 Mac instance and initialize with the signing key
	Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
	mac.init(signingKey);
	// compute the hmac on input data bytes
	byte[] rawHmac = mac.doFinal(data.getBytes());
	return bytArrayToHex(rawHmac);
	}
	private String bytArrayToHex(byte[] a) {
	StringBuilder sb = new StringBuilder();
	for(byte b: a)
	sb.append(String.format("%02x", b&0xff));
	return sb.toString();
	}
	}

Ruby

# Require installing socket.io-client-simple
	require 'socket.io-client-simple'
	require 'base64'
	require 'json'
	$access_key = "<YOUR ACCESS KEY>"
	$secret_key = "<YOUR SECRET KEY>"
	def initial_post_data
	post_data = {}
	post_data['tonce'] = (Time.now.to_f * 1000000).to_i.to_s
	post_data
	end
	def params_string(post_data)
	post_data['params'] = post_data['params'].join(',')
	params_parse(post_data).collect{|k, v| "#{k}=#{v}"} * '&'
	end
	def params_parse(post_data)
	post_data['accesskey'] = $access_key #access key
	post_data['requestmethod'] = 'post'
	post_data['id'] = post_data['tonce'] unless post_data.keys.include?('id')
	fields=['tonce','accesskey','requestmethod','id','method','params']
	ordered_data = {}
	fields.each do |field|
	ordered_data[field] = post_data[field]
	end
	ordered_data
	end
	def sign(params_string)
	signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha1'), $secret_key, params_string) #secret key
	Base64.strict_encode64($access_key+ ':' + signature)
	end
	socket = SocketIO::Client::Simple.connect 'https://websocket.btcc.com'
	socket.on:connect do
	puts "connected!"
	socket.emit :subscribe, "marketdata_cnybtc"
	socket.emit :subscribe, "marketdata_cnyltc"
	socket.emit :subscribe, "marketdata_btcltc"
	socket.emit :subscribe, "grouporder_cnybtc"
	socket.emit :subscribe, "grouporder_cnyltc"
	socket.emit :subscribe, "grouporder_btcltc"
	post_data = initial_post_data
	post_data['method'] = 'subscribe'
	post_data['params'] = ["order_cnybtc", "order_cnyltc", "order_btcltc", "account_info"]
	payload = params_parse(post_data)
	pstr = params_string(payload.clone)
	signature_string = sign(pstr)
	socket.emit :private, [payload.to_json, signature_string]
	end
	socket.on :disconnect do
	puts "disconnected!"
	end
	socket.on :message do |data|
	puts "message: "+data
	end
	socket.on :trade do |data|
	puts 'trade:'
	p data
	end
	socket.on :ticker do |data|
	puts 'ticker:'
	p data
	end
	socket.on :grouporder do |data|
	puts 'grouporder:'
	p data
	end
	socket.on :order do |data|
	puts 'order:'
	p data
	end
	socket.on :account_info do |data|
	puts 'account_info:'
	p data
	end
	loop do
	sleep 3
	end

Socket.io API v1.2.3

2014-10-27 将文档标题由Websocket API改为Socket.io API .

Socket.io API v1.2.2

2014-10-15 Socket.io API v1.2.2 增加了即时市场深度方法.

Socket.io API v1.2.1

2014-09-30 Socket.io API v1.2.1 增加了即时余额更新方法;增加了Java的即时余额更新('account_info')方法示例代码 和 Ruby的私人订单即时更新('order')和即时余额更新('account_info')方法示例代码.

Socket.io API v1.2

2014-09-11 Socket.io API v1.2 增加了C#和C++的示例代码; 增加了即时市场行情和私人订单即时更新方法;增加了java的私人订单即时更新('order')方法示例代码.

Socket.io API v1.1

2014-07-30 Socket.io API v1.1加入了更多的Github上的示例代码链接,包括Java,Python,Ruby和JavaScript.

Socket.io API v1.0

Socket.io API v1.0 包含trade方法和JavaScript的客户端代码示例.