Python socketio 示例连接到 cryptocompare
Posted
技术标签:
【中文标题】Python socketio 示例连接到 cryptocompare【英文标题】:Python socketio example to connect to cryptocompare 【发布时间】:2018-03-16 03:32:02 【问题描述】:我正在尝试使用来自 Python 客户端的 socketIO 连接到 Cryptocompare 的 websocket 流。事实证明这是具有挑战性的。这是一些示例 Python 代码:
from socketIO_client import SocketIO
print "connecting to server"
socketIO = SocketIO('https://streamer.cryptocompare.com/',443, transports=['websocket'])
print "Connected"
但是,无论我做什么,我都无法连接。其实这就是那个connect的结果
connecting to server
Traceback (most recent call last):
File "test.py", line 4, in <module>
socketIO = SocketIO('https://streamer.cryptocompare.com/',443, transports=['websocket'])
File "/usr/local/lib/python2.7/site-packages/socketIO_client/__init__.py", line 353, in __init__
resource, hurry_interval_in_seconds, **kw)
File "/usr/local/lib/python2.7/site-packages/socketIO_client/__init__.py", line 54, in __init__
self._transport
File "/usr/local/lib/python2.7/site-packages/socketIO_client/__init__.py", line 62, in _transport
self._engineIO_session = self._get_engineIO_session()
File "/usr/local/lib/python2.7/site-packages/socketIO_client/__init__.py", line 76, in _get_engineIO_session
transport.recv_packet())
StopIteration
将上述代码包装在 try-catch 中并打印异常不会产生额外信息。任何帮助将不胜感激。
【问题讨论】:
问题可能是服务器端的,因为我也无法建立连接(即使直接使用websocket.connect('wss://streamer.cryptocompare.com/socket.io/websocket')
访问他们的服务器)。
另外值得注意的是,当使用javascript client 时,它连接没有错误
是的,但是我认为我们的问题是缺乏好的例子。看来 Python 对 websockets 和 socketio 的实现有点混乱。
如果 websocket 服务器设置正确,可用的示例工作。这些客户端处理与服务器握手的方式可能略有不同。尝试准系统 websocket
连接时,您会收到更详细的错误:websocket._exceptions.WebSocketBadStatusException: Handshake status 400
看起来所有迹象都指向服务器问题:github.com/cryptoqween/cryptoqween.github.io/issues/1
【参考方案1】:
socketIO_client 库似乎不支持 cryptocompare 使用的 XHR 轮询协议。我通过覆盖socketIO_client.transports.XHR_PollingTransport
类中的方法recv_packet
让它工作。
import logging
import socketIO_client
from socketIO_client.transports import get_response
from socketIO_client.parsers import get_byte, _read_packet_text, parse_packet_text
from requests.exceptions import ConnectionError
# extra function to support XHR1 style protocol
def _new_read_packet_length(content, content_index):
packet_length_string = ''
while get_byte(content, content_index) != ord(':'):
byte = get_byte(content, content_index)
packet_length_string += chr(byte)
content_index += 1
content_index += 1
return content_index, int(packet_length_string)
def new_decode_engineIO_content(content):
content_index = 0
content_length = len(content)
while content_index < content_length:
try:
content_index, packet_length = _new_read_packet_length(
content, content_index)
except IndexError:
break
content_index, packet_text = _read_packet_text(
content, content_index, packet_length)
engineIO_packet_type, engineIO_packet_data = parse_packet_text(
packet_text)
yield engineIO_packet_type, engineIO_packet_data
def new_recv_packet(self):
params = dict(self._params)
params['t'] = self._get_timestamp()
response = get_response(
self.http_session.get,
self._http_url,
params=params,
**self._kw_get)
for engineIO_packet in new_decode_engineIO_content(response.content):
engineIO_packet_type, engineIO_packet_data = engineIO_packet
yield engineIO_packet_type, engineIO_packet_data
setattr(socketIO_client.transports.XHR_PollingTransport, 'recv_packet', new_recv_packet)
logging.basicConfig(level=logging.DEBUG)
try:
socket = socketIO_client.SocketIO('https://streamer.cryptocompare.com')
socket.emit('SubAdd', 'subs': ['0~Kraken~BTC~USD'] );
socket.wait()
except ConnectionError:
print('The server is down. Try again later.')
解决方案很大程度上基于这个 github 评论:https://github.com/invisibleroads/socketIO-client/issues/129#issuecomment-330058318
【讨论】:
这是正确答案,我很惊讶没有人支持这个【参考方案2】:您需要在设置套接字后立即调用 emit 来设置您想要接收的订阅。
socketIO.emit('SubAdd', subs: ['0~Poloniex~BTC~USD'] );
【讨论】:
但它返回 401~BADFORMAT ... 对此有什么帮助吗? 对于 java 版本,以下应该可以工作: JSONObject object = new JSONObject(); JSONArray arr = new JSONArray(); arr.put("11~BTC'"); object.put("subs", arr); socket.emit("SubAdd", object);【参考方案3】:我从几个角度观察了这个问题,得出的结论是python的socketio客户端不适用于这个API。如果您只想从 CryptoCompare 流式 API 将数据流式传输到 python,那么我有一个工作解决方法,它使用 websockets 将请求提交到一个简单的 nodejs 应用程序,然后使用其 socketio-client 将所需的数据流式传输回来。我对 python 还很陌生,只查看了 nodejs 的解决方案,所以请放轻松。
加密货币目前很热门,所以我相信这对某些人会有用
Python 部分:
import json
import pandas as pd
try:
import thread
except ImportError:
import _thread as thread
import threading
import time
import websocket
class WebSocketClient(threading.Thread):
def __init__(self):
self.url = 'ws://localhost:9030/path'
# self.daemon = True
self.clist = list()
threading.Thread.__init__(self)
def run(self):
# Running the run_forever() in a seperate thread.
#websocket.enableTrace(True)
self.ws = websocket.WebSocketApp(self.url,
on_message = self.on_message,
on_error = self.on_error,
on_close = self.on_close)
self.ws.on_open = self.on_open
self.ws.run_forever()
def send(self, data):
data = self._encode_message(data)
# Wait till websocket is connected.
while not self.ws.sock.connected:
time.sleep(0.25)
print(f'Sending data... data')
self.ws.send(data)
def stop(self):
print(f'Stopping the websocket...')
self.ws.close()
def on_message(self, ws, message):
message = self._decode_message(message)
print(f'Received data...message')
if message['msg']=='crypto':
self.clist.append(message['data'])
def on_error(self, ws, error):
print(f'Received error...')
print(error)
def on_close(self, ws):
print('Closed the connection...')
def on_open(self, ws):
print('Opened the connection...')
data = "msg":"open" ,"from":"Rob", "data":"Hello from the client"
self.send(data)
def _encode_message(self,message):
message = json.dumps(message)
return message
def _decode_message(self, message):
message = json.loads(message)
return message
def getclist(self):
return self.clist
wsCli = WebSocketClient()
wsCli.daemon = True
wsCli.start()
wsCli.send("msg":"getcrypto" ,"from":"Client", "data":['0~Coinbase~BTC~USD'],"subs":['0~Coinbase~BTC~USD'])
wsCli.stop()
Nodejs 部分:
var socket = require('socket.io-client')('https://streamer.cryptocompare.com/')
var socketon = false
var WebSocketServer = require('ws').Server , wss = new WebSocketServer(port: 9030);
wss.on('connection', function(ws)
ws.on('message', function(message)
msg = decode_message(message);
console.log('received: %s', message);
console.log('test: %s', msg['msg']);
switch(msg['msg'])
case 'open':
message_type = 'open';
// do something with chat data. i.e.:
console.log("open from " + msg['from'] +
": " + msg['data']);
outmessage = 'welcome from server ' + msg['from'];
ws.send(encode_message(outmessage, message_type = 'open'));
break
case 'getcrypto':
message_type = "crypto"
// do something with chat data. i.e.:
console.log("'getcrypto': object" + msg['data']);
socket.emit('SubAdd', subs: msg.subs );
if (!socketon)
socket.on("m", function (message)
var messageType = message.substring(0, message.indexOf("~"));
var res = ;
switch (messageType)
case CCC.STATIC.TYPE.TRADE:
res = CCC.TRADE.unpack(message);
break;
case CCC.STATIC.TYPE.CURRENT:
res = CCC.CURRENT.unpack(message);
break;
case CCC.STATIC.TYPE.CURRENTAGG:
res = CCC.CURRENT.unpack(message);
// updateQuote(res);
break;
case CCC.STATIC.TYPE.ORDERBOOK:
res = CCC.ORDER.unpack(message);
break;
case CCC.STATIC.TYPE.FULLORDERBOOK:
res = CCC.ORDER.unpack(message);
break;
console.log(message);
console.log(res);
ws.send(encode_message(res, message_type = "crypto"));
)
socketon = true;
break
case 'canccrypto':
// do something with chat data. i.e.:
message_type = "crypto"
console.log(msg['msg'] +":" + msg['data']);
socket.emit('SubRemove', subs: msg.subs );
break
case 'other':
// do something with chat data. i.e.:
console.log("open from " + msg['from'] +
": " + msg['data']);
outmessage = 'other from server ' + msg['from']
ws.send(encode_message(outmessage, message_type = "other"));
break
// ... and so on
);
);
function decode_message(message)
msg = JSON.parse(message);
return msg;
function encode_message(message, messsage_type)
if (message_type == "crypto")
var msg_crypto = 'msg': 'crypto', 'data': message ;
msg = JSON.stringify(msg_crypto);
else
var msg_other = 'msg': 'other', 'data': message ;
msg = JSON.stringify(msg_other);
return msg;
var CCC = CCC || ;
CCC.STATIC = CCC.STATIC || ;
CCC.STATIC.TYPE =
'TRADE': '0'
, 'FEEDNEWS': '1'
, 'CURRENT': '2'
, 'LOADCOMPLATE': '3'
, 'COINPAIRS': '4'
, 'CURRENTAGG': '5'
, 'TOPLIST': '6'
, 'TOPLISTCHANGE': '7'
, 'ORDERBOOK': '8'
, 'FULLORDERBOOK': '9'
, 'ACTIVATION': '10'
, 'TRADECATCHUP': '100'
, 'NEWSCATCHUP': '101'
, 'TRADECATCHUPCOMPLETE': '300'
, 'NEWSCATCHUPCOMPLETE': '301'
;
CCC.STATIC.CURRENCY = CCC.STATIC.CURRENCY || ;
CCC.STATIC.CURRENCY.SYMBOL =
'BTC': '?'
, 'LTC': '?'
, 'DAO': 'Ð'
, 'USD': '$'
, 'CNY': '¥'
, 'EUR': '€'
, 'GBP': '£'
, 'JPY': '¥'
, 'PLN': 'z?'
, 'RUB': '?'
, 'ETH': '?'
, 'GOLD': 'Gold g'
, 'INR': '?'
, 'BRL': 'R$'
;
CCC.STATIC.CURRENCY.getSymbol = function (symbol)
return CCC.STATIC.CURRENCY.SYMBOL[symbol] || symbol;
;
CCC.STATIC.UTIL =
exchangeNameMapping:
'CCCAGG': 'CryptoCompare Index',
'BTCChina': 'BTCC'
,
isMobile: function (userAgent)
if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(userAgent)
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)))
return true;
return false;
,
convertToMB: function (bytes)
return (parseInt(bytes, 10) / 1024 / 1024).toFixed(2) + ' MB';
,
getNameForExchange: function (exchangeName)
if (this.exchangeNameMapping.hasOwnProperty(exchangeName))
return this.exchangeNameMapping[exchangeName];
return exchangeName;
,
noExponents: function (value)
var data = String(value).split(/[eE]/);
if (data.length == 1) return data[0];
var z = '', sign = value < 0 ? '-' : '',
str = data[0].replace('.', ''),
mag = Number(data[1]) + 1;
if (mag < 0)
z = sign + '0.';
while (mag++) z += '0';
return z + str.replace(/^\-/, '');
mag -= str.length;
while (mag--) z += '0';
return str + z;
,
reduceFloatVal: function (value)
value = parseFloat(value);
if (value > 1)
value = Math.round(value * 100) / 100;
return value;
if (value >= 0.00001000)
return parseFloat(value.toPrecision(4));
if (value >= 0.00000100)
return parseFloat(value.toPrecision(3));
if (value >= 0.00000010)
return parseFloat(value.toPrecision(2));
return parseFloat(value.toPrecision(1));
,
reduceReal: function (value)
value = parseFloat(value);
return parseFloat(value.toFixed(8));
,
convertCurrentKeyToAll: function (key)
var valuesArray = key.split("~");
valuesArray[0] = CCC.STATIC.TYPE.CURRENTAGG;
valuesArray[1] = 'CCCAGG';
return valuesArray.join('~');
,
convertCurrentKeyToTrade: function (key)
var valuesArray = key.split("~");
valuesArray[0] = CCC.STATIC.TYPE.TRADE;
return valuesArray.join('~');
,
convertValueToDisplay: function (symbol, value, filterNumberFunctionAngularJS, type, fullNumbers)
var prefix = '';
var valueSign = 1;
value = parseFloat(value);
var valueAbs = Math.abs(value);
var decimalsOnBigNumbers = 2;
var decimalsOnNormalNumbers = 2;
var decimalsOnSmallNumbers = 4;
if (fullNumbers === true)
decimalsOnBigNumbers = 2;
decimalsOnNormalNumbers = 0;
decimalsOnSmallNumbers = 4;
if (type == "8decimals")
decimalsOnBigNumbers = 4;
decimalsOnNormalNumbers = 8;
decimalsOnSmallNumbers = 8;
if (value < 0.0001 && value >= 0.00001) decimalsOnSmallNumbers = 4;
if (value < 0.001 && value >= 0.0001) decimalsOnSmallNumbers = 5;
if (value < 0.01 && value >= 0.001) decimalsOnSmallNumbers = 6;
if (value < 0.1 && value >= 0.01) decimalsOnSmallNumbers = 7;
if (symbol != '') prefix = symbol + ' ';
if (value < 0) valueSign = -1;
if (value == 0) return prefix + '0';
if (value < 0.00001000 && value >= 0.00000100 && decimalsOnSmallNumbers > 3)
decimalsOnSmallNumbers = 3;
if (value < 0.00000100 && value >= 0.00000010 && decimalsOnSmallNumbers > 2)
decimalsOnSmallNumbers = 2;
if (value < 0.00000010 && decimalsOnSmallNumbers > 1)
decimalsOnSmallNumbers = 1;
if (type == "short" || type == "8decimals")
if (valueAbs > 10000000000)
valueAbs = valueAbs / 1000000000;
return prefix + filterNumberFunctionAngularJS(valueSign * valueAbs, decimalsOnBigNumbers) + ' B';
if (valueAbs > 10000000)
valueAbs = valueAbs / 1000000;
return prefix + filterNumberFunctionAngularJS(valueSign * valueAbs, decimalsOnBigNumbers) + ' M';
if (valueAbs > 10000)
valueAbs = valueAbs / 1000;
return prefix + filterNumberFunctionAngularJS(valueSign * valueAbs, decimalsOnBigNumbers) + ' K';
if (type == "8decimals" && valueAbs >= 100)
return prefix + filterNumberFunctionAngularJS(valueSign * valueAbs, decimalsOnBigNumbers);
if (valueAbs >= 1)
return prefix + filterNumberFunctionAngularJS(valueSign * valueAbs, decimalsOnNormalNumbers);
return prefix + (valueSign * valueAbs).toPrecision(decimalsOnSmallNumbers);
else
if (valueAbs >= 1)
return prefix + filterNumberFunctionAngularJS(valueSign * valueAbs, decimalsOnNormalNumbers);
return prefix + this.noExponents((valueSign * valueAbs).toPrecision(decimalsOnSmallNumbers));
;
CCC.TRADE = CCC.TRADE || ;
/*
trade fields binary values always in the last ~
*/
CCC.TRADE.FLAGS =
'SELL': 0x1 // hex for binary 1
, 'BUY': 0x2 // hex for binary 10
, 'UNKNOWN': 0x4 // hex for binary 100
CCC.TRADE.FIELDS =
'T': 0x0 // hex for binary 0, it is a special case of fields that are always there TYPE
, 'M': 0x0 // hex for binary 0, it is a special case of fields that are always there MARKET
, 'FSYM': 0x0 // hex for binary 0, it is a special case of fields that are always there FROM SYMBOL
, 'TSYM': 0x0 // hex for binary 0, it is a special case of fields that are always there TO SYMBOL
, 'F': 0x0 // hex for binary 0, it is a special case of fields that are always there FLAGS
, 'ID': 0x1 // hex for binary 1 ID
, 'TS': 0x2 // hex for binary 10 TIMESTAMP
, 'Q': 0x4 // hex for binary 100 QUANTITY
, 'P': 0x8 // hex for binary 1000 PRICE
, 'TOTAL': 0x10 // hex for binary 10000 TOTAL
;
CCC.TRADE.DISPLAY = CCC.TRADE.DISPLAY || ;
CCC.TRADE.DISPLAY.FIELDS =
'T': "Show": false
, 'M': "Show": true, 'Filter': 'Market'
, 'FSYM': "Show": true, 'Filter': 'CurrencySymbol'
, 'TSYM': "Show": true, 'Filter': 'CurrencySymbol'
, 'F': "Show": true, 'Filter': 'TradeFlag'
, 'ID': "Show": true, 'Filter': 'Text'
, 'TS': 'Show': true, 'Filter': 'Date', 'Format': 'yyyy MMMM dd HH:mm:ss'
, 'Q': 'Show': true, 'Filter': 'Number', 'Symbol': 'FSYM'
, 'P': 'Show': true, 'Filter': 'Number', 'Symbol': 'TSYM'
, 'TOTAL': 'Show': true, 'Filter': 'Number', 'Symbol': 'TSYM'
;
CCC.TRADE.pack = function (tradeObject)
var mask = 0;
var packedTrade = '';
for (var field in tradeObject)
packedTrade += '~' + tradeObject[field];
mask |= this.FIELDS[field];
return packedTrade.substr(1) + '~' + mask.toString(16);
;
CCC.TRADE.unpack = function (tradeString)
var valuesArray = tradeString.split("~");
var valuesArrayLenght = valuesArray.length;
var mask = valuesArray[valuesArrayLenght - 1];
var maskInt = parseInt(mask, 16);
var unpackedTrade = ;
var currentField = 0;
for (var property in this.FIELDS)
if (this.FIELDS[property] === 0)
unpackedTrade[property] = valuesArray[currentField];
currentField++;
else if (maskInt & this.FIELDS[property])
unpackedTrade[property] = valuesArray[currentField];
currentField++;
return unpackedTrade;
CCC.TRADE.getKey = function (tradeObject)
return tradeObject['T'] + '~' + tradeObject['M'] + '~' + tradeObject['FSYM'] + '~' + tradeObject['TSYM'];
;
CCC.CURRENT = CCC.CURRENT || ;
/*
current fields mask values always in the last ~
*/
CCC.CURRENT.FLAGS =
'PRICEUP': 0x1 // hex for binary 1
, 'PRICEDOWN': 0x2 // hex for binary 10
, 'PRICEUNCHANGED': 0x4 // hex for binary 100
, 'BIDUP': 0x8 // hex for binary 1000
, 'BIDDOWN': 0x10 // hex for binary 10000
, 'BIDUNCHANGED': 0x20 // hex for binary 100000
, 'OFFERUP': 0x40 // hex for binary 1000000
, 'OFFERDOWN': 0x80 // hex for binary 10000000
, 'OFFERUNCHANGED': 0x100 // hex for binary 100000000
, 'AVGUP': 0x200 // hex for binary 1000000000
, 'AVGDOWN': 0x400 // hex for binary 10000000000
, 'AVGUNCHANGED': 0x800 // hex for binary 100000000000
;
CCC.CURRENT.FIELDS =
'TYPE': 0x0 // hex for binary 0, it is a special case of fields that are always there
, 'MARKET': 0x0 // hex for binary 0, it is a special case of fields that are always there
, 'FROMSYMBOL': 0x0 // hex for binary 0, it is a special case of fields that are always there
, 'TOSYMBOL': 0x0 // hex for binary 0, it is a special case of fields that are always there
, 'FLAGS': 0x0 // hex for binary 0, it is a special case of fields that are always there
, 'PRICE': 0x1 // hex for binary 1
, 'BID': 0x2 // hex for binary 10
, 'OFFER': 0x4 // hex for binary 100
, 'LASTUPDATE': 0x8 // hex for binary 1000
, 'AVG': 0x10 // hex for binary 10000
, 'LASTVOLUME': 0x20 // hex for binary 100000
, 'LASTVOLUMETO': 0x40 // hex for binary 1000000
, 'LASTTRADEID': 0x80 // hex for binary 10000000
, 'VOLUMEHOUR': 0x100 // hex for binary 100000000
, 'VOLUMEHOURTO': 0x200 // hex for binary 1000000000
, 'VOLUME24HOUR': 0x400 // hex for binary 10000000000
, 'VOLUME24HOURTO': 0x800 // hex for binary 100000000000
, 'OPENHOUR': 0x1000 // hex for binary 1000000000000
, 'HIGHHOUR': 0x2000 // hex for binary 10000000000000
, 'LOWHOUR': 0x4000 // hex for binary 100000000000000
, 'OPEN24HOUR': 0x8000 // hex for binary 1000000000000000
, 'HIGH24HOUR': 0x10000 // hex for binary 10000000000000000
, 'LOW24HOUR': 0x20000 // hex for binary 100000000000000000
, 'LASTMARKET': 0x40000 // hex for binary 1000000000000000000, this is a special case and will only appear on CCCAGG messages
;
CCC.CURRENT.DISPLAY = CCC.CURRENT.DISPLAY || ;
CCC.CURRENT.DISPLAY.FIELDS =
'TYPE': 'Show': false
, 'MARKET': 'Show': true, 'Filter': 'Market'
, 'FROMSYMBOL': 'Show': false
, 'TOSYMBOL': 'Show': false
, 'FLAGS': 'Show': false
, 'PRICE': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'BID': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'OFFER': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'LASTUPDATE': 'Show': true, 'Filter': 'Date', 'Format': 'yyyy MMMM dd HH:mm:ss'
, 'AVG': 'Show': true, ' Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'LASTVOLUME': 'Show': true, 'Filter': 'Number', 'Symbol': 'FROMSYMBOL'
, 'LASTVOLUMETO': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'LASTTRADEID': 'Show': true, 'Filter': 'String'
, 'VOLUMEHOUR': 'Show': true, 'Filter': 'Number', 'Symbol': 'FROMSYMBOL'
, 'VOLUMEHOURTO': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'VOLUME24HOUR': 'Show': true, 'Filter': 'Number', 'Symbol': 'FROMSYMBOL'
, 'VOLUME24HOURTO': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'OPENHOUR': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'HIGHHOUR': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'LOWHOUR': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'OPEN24HOUR': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'HIGH24HOUR': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'LOW24HOUR': 'Show': true, 'Filter': 'Number', 'Symbol': 'TOSYMBOL'
, 'LASTMARKET': 'Show': true, 'Filter': 'String'
;
CCC.CURRENT.pack = function (currentObject)
var mask = 0;
var packedCurrent = '';
for (var property in this.FIELDS)
if (currentObject.hasOwnProperty(property))
packedCurrent += '~' + currentObject[property];
mask |= this.FIELDS[property];
//removing first character beacsue it is a ~
return packedCurrent.substr(1) + '~' + mask.toString(16);
;
CCC.CURRENT.unpack = function (value)
var valuesArray = value.split("~");
var valuesArrayLenght = valuesArray.length;
var mask = valuesArray[valuesArrayLenght - 1];
var maskInt = parseInt(mask, 16);
var unpackedCurrent = ;
var currentField = 0;
for (var property in this.FIELDS)
if (this.FIELDS[property] === 0)
unpackedCurrent[property] = valuesArray[currentField];
currentField++;
else if (maskInt & this.FIELDS[property])
//i know this is a hack, for cccagg, future code please don't hate me:(, i did this to avoid
//subscribing to trades as well in order to show the last market
if (property === 'LASTMARKET')
unpackedCurrent[property] = valuesArray[currentField];
else
unpackedCurrent[property] = parseFloat(valuesArray[currentField]);
currentField++;
return unpackedCurrent;
;
CCC.CURRENT.getKey = function (currentObject)
return currentObject['TYPE'] + '~' + currentObject['MARKET'] + '~' + currentObject['FROMSYMBOL'] + '~' + currentObject['TOSYMBOL'];
;
CCC.CURRENT.getKeyFromStreamerData = function (streamerData)
var valuesArray = streamerData.split("~");
return valuesArray[0] + '~' + valuesArray[1] + '~' + valuesArray[2] + '~' + valuesArray[3];
;
CCC.noExponents = function (value)
var data = String(value).split(/[eE]/);
if (data.length == 1) return data[0];
var z = '', sign = value < 0 ? '-' : '',
str = data[0].replace('.', ''),
mag = Number(data[1]) + 1;
if (mag < 0)
z = sign + '0.';
while (mag++) z += '0';
return z + str.replace(/^\-/, '');
mag -= str.length;
while (mag--) z += '0';
return str + z;
;
CCC.filterNumberFunctionPolyfill = function (value, decimals)
var decimalsDenominator = Math.pow(10, decimals);
var numberWithCorrectDecimals = Math.round(value * decimalsDenominator) / decimalsDenominator;
var parts = numberWithCorrectDecimals.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d3)+(?!\d))/g, ",");
return parts.join(".");
CCC.convertValueToDisplay = function (symbol, value, type, fullNumbers)
var prefix = '';
var valueSign = 1;
value = parseFloat(value);
var valueAbs = Math.abs(value);
var decimalsOnBigNumbers = 2;
var decimalsOnNormalNumbers = 2;
var decimalsOnSmallNumbers = 4;
if (fullNumbers === true)
decimalsOnBigNumbers = 2;
decimalsOnNormalNumbers = 0;
decimalsOnSmallNumbers = 4;
if (symbol != '')
prefix = symbol + ' ';
if (value < 0)
valueSign = -1;
if (value == 0)
return prefix + '0';
if (value < 0.00001000 && value >= 0.00000100 && decimalsOnSmallNumbers > 3)
decimalsOnSmallNumbers = 3;
if (value < 0.00000100 && value >= 0.00000010 && decimalsOnSmallNumbers > 2)
decimalsOnSmallNumbers = 2;
if (value < 0.00000010 && value >= 0.00000001 && decimalsOnSmallNumbers > 1)
decimalsOnSmallNumbers = 1;
if (type == "short")
if (valueAbs > 10000000000)
valueAbs = valueAbs / 1000000000;
return prefix + CCC.filterNumberFunctionPolyfill(valueSign * valueAbs, decimalsOnBigNumbers) + ' B';
if (valueAbs > 10000000)
valueAbs = valueAbs / 1000000;
return prefix + CCC.filterNumberFunctionPolyfill(valueSign * valueAbs, decimalsOnBigNumbers) + ' M';
if (valueAbs > 10000)
valueAbs = valueAbs / 1000;
return prefix + CCC.filterNumberFunctionPolyfill(valueSign * valueAbs, decimalsOnBigNumbers) + ' K';
if (valueAbs >= 1)
return prefix + CCC.filterNumberFunctionPolyfill(valueSign * valueAbs, decimalsOnNormalNumbers);
return prefix + (valueSign * valueAbs).toPrecision(decimalsOnSmallNumbers);
else
if (valueAbs >= 1)
return prefix + CCC.filterNumberFunctionPolyfill(valueSign * valueAbs, decimalsOnNormalNumbers);
return prefix + CCC.noExponents((valueSign * valueAbs).toPrecision(decimalsOnSmallNumbers));
;
【讨论】:
以上是关于Python socketio 示例连接到 cryptocompare的主要内容,如果未能解决你的问题,请参考以下文章
Expo react-native 将无法连接到 socketio(Android 和 iOS)
连接到 GCP App Engine 上的 SocketIO 服务器时如何使用域而不是公共 IP?