Last active
October 24, 2016 16:18
-
-
Save pinhopro/f90bc1191c5f2f7ec296f2ce28714cb3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var os = require('os'); | |
var util = require('util'); | |
var Promise = require('promise'); | |
var WebSocketClient = require('websocket').w3cwebsocket; | |
var macaddress = require('macaddress'); | |
var dgram = require('dgram'); | |
var ip = require('ip'); | |
/** | |
* @param {string} api_endpoint | |
* @param {Object.<string,string>} opt_extra_params | |
* @constructor | |
*/ | |
var BlinkTradeWebSocketTransport = function(api_endpoint, opt_extra_params){ | |
var self = this; | |
/** | |
* @type {string} | |
* @private | |
*/ | |
this.websocket_url_ = api_endpoint; | |
/** | |
* @type {WebSocket} | |
* @private | |
*/ | |
this.ws_ = null; | |
/** | |
* | |
* @type {Object.<number,*>} | |
* @private | |
*/ | |
this.handlers_ = {}; | |
/** | |
* @type {number} | |
* @private | |
*/ | |
this.last_request_id_ = null; | |
/** | |
* @type {Object.<string,string|Array.<string>>|null} | |
* @private | |
*/ | |
this.stun_ip_ = null; | |
/** | |
* @type {number|null} | |
* @private | |
*/ | |
this.finger_print_ = null; | |
/** | |
* @type {number|null} | |
* @private | |
*/ | |
this.tracking_code_ = null; | |
// Send a STUNT request to stun servers, so we can retrieve our public ip addresses | |
if (dgram) { | |
var socket = dgram.createSocket('udp4'); | |
var STUN_HEADER_LENGTH = 20; | |
var stun_request = new Buffer(STUN_HEADER_LENGTH); | |
var STUN_METHOD_REQUEST = 0x000; | |
var STUN_BINDING_CLASS = 0x0001; | |
var STUN_MAGIC_COOKIE = 0x2112A442; | |
var STUN_TID_MAX = Math.pow(2,32); | |
var STUN_ATTR_MAPPED_ADDRESS = 0x0001; | |
var STUN_ATTR_SOURCE_ADDRESS = 0x0004; | |
var STUN_ATTR_CHANGE_ADDRESS = 0x0005; | |
var STUN_ATTR_XOR_MAPPED_ADDRESS = 0x8020; | |
var STUN_ATTR_XOR_MAPPED_ADDRESS_ALT = 0x0020; | |
var stun_tx_id = (Math.random() * STUN_TID_MAX); | |
stun_request.writeUInt16BE(((STUN_BINDING_CLASS|STUN_METHOD_REQUEST) & 0x3fff), 0); | |
stun_request.writeUInt16BE(0, 2); | |
stun_request.writeUInt32BE(STUN_MAGIC_COOKIE, 4); | |
stun_request.writeUInt32BE(0, 8); | |
stun_request.writeUInt32BE(0, 12); | |
stun_request.writeUInt32BE(stun_tx_id, 16); | |
socket.on('message', function(msg){ | |
var _xor = function(a, b) { | |
var data = []; | |
if (b.length > a.length) { | |
var tmp = a; | |
a = b; | |
b = tmp; | |
} | |
for (var i=0, len=a.length; i<len; i++) { | |
data.push(a[i] ^ b[i]); | |
} | |
return new Buffer(data); | |
}; | |
var block = msg.readUInt8(0); | |
var bit1 = block & 0x80; | |
var bit2 = block & 0x40; | |
var _isStunPacket = (bit1 === 0 && bit2 === 0) ? true : false; | |
if (!_isStunPacket) { | |
return; | |
} | |
var msg_header = msg.slice(0, STUN_HEADER_LENGTH); | |
var msg_attrs = msg.slice(STUN_HEADER_LENGTH, msg.length ); | |
var offset = 0; | |
while (offset < msg_attrs.length) { | |
var attr_type = msg_attrs.readUInt16BE(offset); | |
offset += 2; | |
var attr_buff_length = msg_attrs.readUInt16BE(offset); | |
var block_out = attr_buff_length % 4; | |
if (block_out > 0) { | |
attr_buff_length += 4 - block_out; | |
} | |
offset += 2; | |
var value = msg_attrs.slice(offset, offset + attr_buff_length); | |
offset += attr_buff_length; | |
var family; | |
var port; | |
var address; | |
switch (attr_type) { | |
case STUN_ATTR_MAPPED_ADDRESS: | |
family = (value.readUInt16BE(0) === 0x02) ? 6 : 4; | |
port = value.readUInt16BE(2); | |
address = ip.toString(value, 4, family); | |
self.addIPAddress_(address); | |
break; | |
case STUN_ATTR_XOR_MAPPED_ADDRESS: | |
case STUN_ATTR_XOR_MAPPED_ADDRESS_ALT: | |
family = (value.readUInt16BE(0) === 0x02) ? 6 : 4; | |
var magic = msg_header.slice(4, 8); | |
var tid = msg_header.slice(8, 20); | |
var xport = value.slice(2, 4); | |
var xaddr = value.slice(4, family === 4 ? 8 : 20); | |
port = _xor(xport, magic.slice(0, 2)).readUInt16BE(0); | |
addr = _xor(xaddr, family === 4 ? magic : value.concat([magic, tid])); | |
address = ip.toString(addr, 0, family); | |
self.addIPAddress_(address); | |
break; | |
default: | |
} | |
} | |
}); | |
var stun_servers = [ | |
[3478, 'stun.services.mozilla.com'], | |
[19302, 'stun.l.google.com'], | |
[3478, 'stun.stunprotocol.org'], | |
[3478, 'stun.softjoys.com'], | |
[3478, 'stun.samsungsmartcam.com'], | |
[3478, 'stun.sonetel.com'], | |
[3478, 'stun.tagan.ru'], | |
[3478, 'stun.voipgain.com'], | |
[3478, 'stunserver.org'], | |
[3478, 'stun.advfn.com'], | |
[3478, 'stun.annatel.net'], | |
[3478, 'stun.freevoipdeal.com'] | |
]; | |
for (var stun_server_index in stun_servers) { | |
var stun_server_port = stun_servers[stun_server_index][0]; | |
var stun_server_host = stun_servers[stun_server_index][1]; | |
socket.send(stun_request,0,stun_request.length,stun_server_port,stun_server_host); | |
} | |
} | |
if (macaddress) { | |
macaddress.all(function (err, all) { | |
var hashCode = function(str){ | |
var hash = 0; | |
if (str.length == 0) return hash; | |
for (i = 0; i < str.length; i++) { | |
char = str.charCodeAt(i); | |
hash = ((hash<<5)-hash)+char; | |
hash = hash & hash; // Convert to 32bit integer | |
} | |
return hash; | |
}; | |
var mac_addresses = ''; | |
Object.keys(all).forEach(function(iface) { | |
mac_addresses += all[iface]["mac"]; | |
if (all[iface]["ipv4"]) { | |
self.addIPAddress_(all[iface]["ipv4"]); | |
} | |
}); | |
finger_print = hashCode(mac_addresses); | |
if (finger_print < 0) { | |
finger_print *= -1; | |
} | |
this.finger_print_ = finger_print; | |
}.bind(this)); | |
} | |
}; | |
/** | |
* | |
* @param {!Function} connected_cb | |
* @param {!Function} disconnected_cb | |
*/ | |
BlinkTradeWebSocketTransport.prototype.connect = function(connected_cb, disconnected_cb) { | |
this.ws_ = new WebSocketClient(this.websocket_url_); | |
this.ws_.onopen = connected_cb.bind(this); | |
this.ws_.onclose = disconnected_cb.bind(this); | |
this.ws_.onmessage = function(e) { | |
if (typeof e.data === 'string') { | |
var msg = JSON.parse(e.data); | |
var msg_type = msg['MsgType']; | |
var request_id = this.getRequestID_(msg); | |
var handlers = this.handlers_[request_id]; | |
if (handlers) { | |
if (handlers.status == 0) { | |
if (msg_type == 'ERROR') { | |
handlers.error_callback(msg); | |
} else { | |
handlers.callback(msg); | |
} | |
handlers.status = 1; | |
msg = JSON.parse(e.data); // deep copy the message again. | |
} | |
if (typeof handlers.subscribe_callback == 'function' ) { | |
handlers.subscribe_callback(msg); | |
} else { | |
delete this.handlers_[request_id]; | |
} | |
} | |
} | |
}.bind(this); | |
}; | |
BlinkTradeWebSocketTransport.prototype.disconnect = function() { | |
if (this.ws_) { | |
this.ws_.close(); | |
this.ws_ = null; | |
} | |
}; | |
/** | |
* @param {Object.<string,*>} msg | |
* @returns {number|null} | |
* @private | |
*/ | |
BlinkTradeWebSocketTransport.prototype.getRequestID_ = function(msg) { | |
var msg_type = msg['MsgType']; | |
switch( msg_type ) { | |
case 'ERROR': | |
if (msg['Request']){ | |
return this.getRequestID_(msg['Request']); | |
} else { | |
return this.last_request_id_; | |
} | |
case '0': | |
case '1': | |
return msg['TestReqID']; | |
case 'e': | |
case 'f': | |
return msg['SecurityStatusReqID']; | |
case 'x': | |
case 'y': | |
return msg['SecurityReqID']; | |
case 'D': | |
case '8': | |
return msg['ClOrdID']; | |
case 'F': | |
if (msg['OrderID']){ | |
return msg['OrderID']; | |
} else if (msg['OrigClOrdID']){ | |
return msg['OrigClOrdID']; | |
} | |
break; | |
case 'U0': | |
case 'BE': | |
case 'BF': | |
return msg['UserReqID']; | |
case 'V': | |
case 'W': | |
case 'Y': | |
case 'X': | |
return msg['MDReqID']; | |
case 'U2': | |
case 'U3': | |
return msg['BalanceReqID']; | |
case 'U4': | |
case 'U5': | |
return msg['OrdersReqID']; | |
case 'U6': | |
case 'U7': | |
return msg['WithdrawReqID']; | |
case 'U10': | |
return msg['ForgotPasswordReqID']; | |
case 'U12': | |
case 'U13': | |
return msg['ResetPasswordReqID']; | |
case 'U16': | |
case 'U17': | |
return msg['EnableTwoFactorReqID']; | |
case 'U18': | |
case 'U19': | |
case 'U23': | |
return msg['DepositReqID']; | |
case 'U20': | |
case 'U21': | |
return msg['DepositMethodReqID']; | |
case 'U24': | |
case 'U25': | |
return msg['WithdrawReqID']; | |
case 'U26': | |
case 'U27': | |
return msg['WithdrawListReqID']; | |
case 'U28': | |
case 'U29': | |
return msg['BrokerListReqID']; | |
case 'U30': | |
case 'U31': | |
return msg['DepositListReqID']; | |
case 'U32': | |
case 'U33': | |
return msg['TradeHistoryReqID']; | |
case 'U34': | |
case 'U35': | |
return msg['LedgerListReqID']; | |
case 'U36': | |
case 'U37': | |
return msg['TradersRankReqID']; | |
case 'U38': | |
case 'U39': | |
return msg['UpdateReqID']; | |
case 'U50': | |
case 'U51': | |
return msg['APIKeyListReqID']; | |
case 'U52': | |
case 'U53': | |
return msg['APIKeyCreateReqID']; | |
case 'U54': | |
case 'U55': | |
return msg['APIKeyRevokeReqID']; | |
case 'U56': | |
case 'U57': | |
return msg['GetCreditLineOfCreditReqID']; | |
case 'U58': | |
case 'U59': | |
return msg['PayCreditLineOfCreditReqID']; | |
case 'U60': | |
case 'U61': | |
return msg['LineOfCreditListReqID']; | |
case 'U62': | |
case 'U63': | |
return msg['EnableCreditLineOfCreditReqID']; | |
case 'U70': // User cancel withdraw | |
case 'U71': // TODO: Missing response on the server. | |
return msg['WithdrawCancelReqID']; | |
case 'U72': | |
case 'U73': | |
return msg['CardListReqID']; | |
case 'U74': | |
case 'U75': | |
return msg['CardCreateReqID']; | |
case 'U76': | |
case 'U77': | |
return msg['CardDisableReqID']; | |
case 'U78': // commentWithdraw | |
case 'U79': // TODO: Missing response on the server | |
return msg['WithdrawReqID']; | |
case 'U42': | |
case 'U43': | |
return msg['PositionReqID']; | |
case 'B0': | |
case 'B1': | |
return msg['ProcessDepositReqID']; | |
case 'B2': | |
case 'B3': | |
return msg['CustomerListReqID']; | |
case 'B4': | |
case 'B5': | |
return msg['CustomerReqID']; | |
case 'B6': | |
case 'B7': | |
return msg['ProcessWithdrawReqID']; | |
case 'B8': | |
case 'B9': | |
return msg['VerifyCustomerReqID']; | |
} | |
}; | |
/** | |
* @param {Object.<string,*>} msg | |
* @returns {boolean} | |
*/ | |
BlinkTradeWebSocketTransport.prototype.isSupportedMessage = function(msg){ | |
return true; | |
}; | |
/** | |
* @param {string} ip_address | |
* @private | |
*/ | |
BlinkTradeWebSocketTransport.prototype.addIPAddress_ = function (ip_address) { | |
if (!this.stun_ip_){ | |
this.stun_ip_ = {'local':null, 'public':[]}; | |
} | |
if (ip_address.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/)) { | |
this.stun_ip_['local'] = ip_address; | |
} else { | |
if (this.stun_ip_['public'].indexOf(ip_address ) == -1) { | |
this.stun_ip_['public'].push(ip_address); | |
} | |
} | |
}; | |
/** | |
* @param {number} tracking_code | |
*/ | |
BlinkTradeWebSocketTransport.prototype.setTrackingCode = function(tracking_code){ | |
this.tracking_code_ = tracking_code; | |
}; | |
/** | |
* @param {Object.<string,*>} msg | |
* @param {!Function} callback | |
* @param {!Function} error_callback | |
* @param {!Function|null} opt_subscribe_callback Some messages have a subscription associated with it. | |
*/ | |
BlinkTradeWebSocketTransport.prototype.sendMessage = function(msg, callback, error_callback, opt_subscribe_callback) { | |
var msg_type = msg['MsgType']; | |
var request_id = this.getRequestID_(msg); | |
if (request_id) { | |
this.handlers_[request_id] = { | |
callback:callback, | |
error_callback:error_callback, | |
subscribe_callback:opt_subscribe_callback, | |
status:0 | |
} | |
this.last_request_id_ = request_id; | |
} | |
if (!this.isSupportedMessage(msg)){ | |
throw "MESSAGE_NOT_SUPPORTTED"; | |
}; | |
if (this.finger_print_) { | |
msg['FingerPrint'] = this.finger_print_; | |
} | |
if (this.stun_ip_) { | |
msg['STUNTIP'] = this.stun_ip_; | |
} | |
if (this.tracking_code_) { | |
msg['TrackingCode'] = this.tracking_code_; | |
} | |
var raw_message = JSON.stringify(msg); | |
if (msg_type !== '1') { | |
console.log('Sending message: [MsgtType:"' + msg_type + '"] [req_id:' + request_id + ']:' + raw_message); | |
} | |
if (this.ws_) { | |
this.ws_.send(raw_message); | |
} | |
}; | |
/** | |
* | |
* @param {BlinkTradeWebSocketTransport} transport | |
* @constructor | |
*/ | |
BlinkTrade = function(transport){ | |
this.transport_ = transport; | |
this.permission_list_ = {'*':[]}; | |
this.order_book_ = {}; | |
}; | |
BlinkTrade.prototype.testRequest = function() { | |
var self = this; | |
var d = new Date(); | |
var requestId = d.getTime(); | |
var msg = { | |
'MsgType': '1', | |
'TestReqID': requestId, | |
'SendTime': d.getTime() | |
}; | |
return new Promise(function(fulfill, reject){ | |
self.transport_.sendMessage(msg, | |
function(msg){ | |
var sent = new Date(msg['SendTime']); | |
var just_now = new Date(Date.now()); | |
var response = { | |
'Latency': just_now - sent | |
}; | |
fulfill(response); | |
}, | |
function(error_message){ | |
var error_response = { | |
'Description': error_message['Description'], | |
'Detail': error_message['Detail'] | |
}; | |
reject(error_response); | |
} | |
); | |
}); | |
}; | |
/** | |
* @param {number} broker_id | |
* @param {string} api_key | |
* @param {string} api_password | |
* @param {string=} opt_second_factor | |
*/ | |
BlinkTrade.prototype.login = function(broker_id, api_key, api_password, opt_second_factor){ | |
var self = this; | |
var reqId = parseInt(Math.random() * 1000000, 10); | |
var userAgentTimezoneOffset = new Date().getTimezoneOffset(); | |
var userAgent = os.type() + ' ' + os.release(); | |
var userAgentLanguage = 'en_US'; | |
var userAgentPlatform = os.platform() + '(' + os.arch() + ')'; | |
var msg = { | |
'MsgType': 'BE', | |
'UserReqID': reqId, | |
'BrokerID': broker_id, | |
'Username': api_key, | |
'Password': api_password, | |
'UserReqTyp': '1', | |
'UserAgent': userAgent, | |
'UserAgentLanguage': userAgentLanguage, | |
'UserAgentTimezoneOffset': userAgentTimezoneOffset, | |
'UserAgentPlatform': userAgentPlatform | |
}; | |
if (opt_second_factor) { | |
msg['SecondFactor'] = opt_second_factor; | |
} | |
return new Promise(function(fulfill, reject){ | |
self.transport_.sendMessage(msg, | |
function(msg){ | |
delete msg['MsgType']; | |
delete msg['UserReqID']; | |
if (msg['UserStatus'] == 1 ) { | |
delete msg['UserStatus']; | |
self.permission_list_ = msg['PermissionList']; | |
fulfill(msg); | |
} else { | |
var login_fail_response = { | |
'Description': msg['UserStatusText'], | |
'Detail': '' | |
}; | |
if (msg['NeedSecondFactor']) { | |
login_fail_response['Detail'] = msg['SecondFactorType'] | |
} | |
reject(login_fail_response); | |
} | |
}, | |
function(error_message){ | |
var error_response = { | |
'Description': error_message['Description'], | |
'Detail': error_message['Detail'] | |
}; | |
reject(error_response); | |
}); | |
}); | |
}; | |
/** | |
* Subscribe to receive ticker updates | |
* @param {Array.<string>} symbols | |
* @param {!Function} ticker_cb Callback that will be invoked on every security status update. | |
* @return {number} | |
*/ | |
BlinkTrade.prototype.subscribeTicker = function(symbols, ticker_cb) { | |
var self = this; | |
var reqId = parseInt(Math.random() * 1000000, 10); | |
var msg = { | |
'MsgType': 'e', | |
'SecurityStatusReqID': reqId, | |
'SubscriptionRequestType': '1', | |
'Instruments': symbols | |
}; | |
return new Promise(function(fulfill, reject){ | |
self.transport_.sendMessage(msg, | |
function(ticker_message){ | |
fulfill(ticker_message['SecurityStatusReqID']); | |
}, | |
function(error_message){ | |
var error_response = { | |
'Description': error_message['Description'], | |
'Detail': error_message['Detail'] | |
}; | |
reject(error_response); | |
}, | |
function(ticker_message){ | |
delete ticker_message['MsgType']; | |
delete ticker_message['SecurityStatusReqID']; | |
ticker_message['SellVolume'] = ticker_message['SellVolume']/1e8; | |
ticker_message['LowPx'] = ticker_message['LowPx']/1e8; | |
ticker_message['LastPx'] = ticker_message['LastPx']/1e8; | |
ticker_message['BestAsk'] = ticker_message['BestAsk']/1e8; | |
ticker_message['HighPx'] = ticker_message['HighPx']/1e8; | |
ticker_message['BuyVolume'] = ticker_message['BuyVolume']/1e8; | |
ticker_message['BestBid'] = ticker_message['BestBid']/1e8; | |
ticker_cb(ticker_message); | |
}.bind(self) | |
); | |
}); | |
}; | |
/** | |
* Subscribe to receive ticker updates | |
* @param {Array.<string>} symbols | |
* @param {!Function} orderbook_cb Callback that will be invoked on every order book update. | |
* @return {number} | |
*/ | |
BlinkTrade.prototype.subscribeOrderbook = function(symbols, orderbook_cb) { | |
var self = this; | |
var reqId = parseInt(Math.random() * 1000000, 10); | |
var msg = { | |
'MsgType' : 'V', | |
'MDReqID' : reqId, | |
'SubscriptionRequestType' : '1', // 1 = Snapshot + Updates (Subscribe) | |
'MarketDepth' : 0, // Full book | |
'MDUpdateType' : '1', // Incremental refresh | |
'MDEntryTypes' : ['0', '1'], // 0-Bid and 1-Offer | |
'Instruments': symbols | |
}; | |
return new Promise(function(fulfill, reject){ | |
self.transport_.sendMessage(msg, | |
function(message){ | |
if (message['MsgType'] == 'Y') { // Market Data Request Reject | |
var md_reject_response = { | |
'Description': message['MDReqRejReason'], | |
'Detail': message['Text'] | |
}; | |
reject(md_reject_response); | |
} else { | |
fulfill(message['MDReqID']); | |
} | |
}, | |
function(error_message){ | |
var error_response = { | |
'Description': error_message['Description'], | |
'Detail': error_message['Detail'] | |
}; | |
reject(error_response); | |
}, | |
function(msg){ | |
var symbol; | |
var side; | |
var index; | |
var price; | |
var qty; | |
var user_id; | |
var should_execute_callback = false; | |
switch (msg['MsgType']) { | |
case 'W': | |
symbol = msg['Symbol']; | |
for (var x in msg['MDFullGrp']) { | |
var wentry = msg['MDFullGrp'][x]; | |
switch (wentry['MDEntryType']){ | |
case '0': // Bid | |
case '1': // Offer | |
side = wentry['MDEntryType']; | |
index = wentry['MDEntryPositionNo'] - 1; | |
price = wentry['MDEntryPx'] / 1e8; | |
qty = wentry['MDEntrySize'] / 1e8; | |
user_id = wentry['UserID']; | |
if ( self.order_book_[symbol] == null ) { | |
self.order_book_[symbol] = {'bids': [], 'asks':[] }; | |
} | |
if (side == '0') { | |
self.order_book_[symbol]['bids'].splice(index, 0, [price, qty, user_id]); | |
} else if (side == '1') { | |
self.order_book_[symbol]['asks'].splice(index, 0, [price, qty, user_id]); | |
} | |
should_execute_callback = true; | |
break; | |
} | |
} | |
if (should_execute_callback) { | |
orderbook_cb(self.order_book_[symbol]); | |
} | |
break; | |
case 'X': | |
for (var y in msg['MDIncGrp']) { | |
var xentry = msg['MDIncGrp'][y]; | |
switch (xentry['MDEntryType']) { | |
case '0': // Bid | |
case '1': // Offer | |
has_order_book_changed = true; | |
switch (xentry['MDUpdateAction']) { | |
case '0': // New | |
symbol = xentry['Symbol']; | |
side = xentry['MDEntryType']; | |
index = xentry['MDEntryPositionNo'] - 1; | |
price = xentry['MDEntryPx'] / 1e8; | |
qty = xentry['MDEntrySize'] / 1e8; | |
user_id = xentry['UserID']; | |
if (side == '0') { | |
self.order_book_[symbol]['bids'].splice(index, 0, [price, qty, user_id]); | |
} else if (side == '1') { | |
self.order_book_[symbol]['asks'].splice(index, 0, [price, qty, user_id]); | |
} | |
should_execute_callback = true; | |
break; | |
case '1': // Change | |
symbol = xentry['Symbol']; | |
side = xentry['MDEntryType']; | |
index = xentry['MDEntryPositionNo'] - 1; | |
qty = xentry['MDEntrySize'] / 1e8; | |
if (side == '0') { | |
price = self.order_book_[symbol]['bids'][index][0]; | |
user_id = self.order_book_[symbol]['bids'][index][2]; | |
self.order_book_[symbol]['bids'][index] = [price,qty,user_id]; | |
} else if (side == '1') { | |
price = self.order_book_[symbol]['asks'][index][0]; | |
user_id = self.order_book_[symbol]['asks'][index][2]; | |
self.order_book_[symbol]['asks'][index] = [price,qty,user_id]; | |
} | |
should_execute_callback = true; | |
break; | |
case '2': // Delete | |
symbol = xentry['Symbol']; | |
index = xentry['MDEntryPositionNo'] - 1; | |
side = xentry['MDEntryType']; | |
if (side == '0') { | |
self.order_book_[symbol]['bids'].splice(index,1); | |
} else if (side == '1') { | |
self.order_book_[symbol]['asks'].splice(index,1); | |
} | |
should_execute_callback = true; | |
break; | |
case '3': // Delete Thru | |
symbol = xentry['Symbol']; | |
index = xentry['MDEntryPositionNo']; | |
side = xentry['MDEntryType']; | |
if (side == '0') { | |
self.order_book_[symbol]['bids'].splice(0, index); | |
} else if (side == '1') { | |
self.order_book_[symbol]['asks'].splice(0, index); | |
} | |
should_execute_callback = true; | |
break; | |
} | |
} | |
} | |
if (should_execute_callback) { | |
orderbook_cb(self.order_book_[symbol]); | |
} | |
break; | |
} | |
}.bind(self) | |
); | |
}); | |
}; | |
/** | |
* @param {number} market_data_id | |
*/ | |
BlinkTrade.prototype.unSubscribeTicker = function(market_data_id){ | |
var self = this; | |
var msg = { | |
'MsgType': 'e', | |
'SecurityStatusReqID': market_data_id, | |
'SubscriptionRequestType': '2' | |
}; | |
return new Promise(function(fulfill, reject){ | |
self.transport_.sendMessage(msg); | |
setTimeout( function() { | |
fulfill(); | |
}, 0); // keep it asyncronous | |
}); | |
}; | |
/** | |
* @param {number} market_data_id | |
*/ | |
BlinkTrade.prototype.unSubscribeOrderbook = function(market_data_id){ | |
var self = this; | |
var msg = { | |
'MsgType': 'V', | |
'MDReqID': market_data_id, | |
'MarketDepth' : 0, | |
'SubscriptionRequestType': '2' | |
}; | |
return new Promise(function(fulfill, reject){ | |
self.transport_.sendMessage(msg); | |
setTimeout( function() { | |
fulfill(); | |
}, 0); // keep it asyncronous | |
}); | |
}; | |
/** | |
* @param {string} symbol | |
* @returns {*} | |
*/ | |
BlinkTrade.prototype.getOrderBook = function(symbol) { | |
return this.order_book_[symbol]; | |
}; | |
var api_endpoint = 'wss://api.testnet.blinktrade.com/trade/'; // testnet | |
//api_endpoint = 'ws://127.0.0.1:8445/'; // localhost development server | |
//api_endpoint = 'wss://api.blinktrade.com/trade/'; // production | |
var ws_transport = new BlinkTradeWebSocketTransport(api_endpoint); | |
var bt = new BlinkTrade(ws_transport); | |
var testRequestFn = function() { | |
bt.testRequest().then(function(response){ | |
console.log('Response:' + util.inspect(response)); | |
}, function(error_message){ | |
console.log('Error:' + util.inspect(error_message)); | |
}); | |
}; | |
var testRequestInterval = null; | |
var tickerSubscriptionID = null; | |
var orderbookSubscriptionID = null; | |
var on_transport_connected = function() { | |
console.log('on_transport_connected'); | |
var api_key = 'wYuY7FQLdhenPVNYlLNjepvkJ5GFDAUYN8SqbgKoLDE'; | |
var api_password = 'El0rKCS9Xg2M8ka'; | |
var broker_id = 4; // 4 - FOXBIT | |
bt.login(broker_id,api_key,api_password).then(function(msg){ | |
console.log('Received message:' + util.inspect(msg)); | |
}, function(error_message){ | |
console.log('error on login:' + util.inspect(error_message)); | |
}); | |
bt.subscribeTicker(['BTCBRL', 'UOL:USDBRT', 'UOL:USDBRL'], function(ticker){ | |
console.log('Ticker:' + util.inspect(ticker)); | |
}).then(function(subscrition_id){ | |
tickerSubscriptionID = subscrition_id; | |
}); | |
bt.subscribeOrderbook(['BTCBRL'], function(order_book){ | |
console.log('Orderbook message bids:' + order_book['bids'].length + ', asks:' + order_book['asks'].length ); | |
}).then(function(subscrition_id){ | |
orderbookSubscriptionID = subscrition_id; | |
console.log('Orderbook subscrition_id:' + subscrition_id); | |
}); | |
// send a test request every 30 seconds | |
testRequestInterval = setInterval( testRequestFn,30000); | |
// Unsubscribe from ticker updates after 20 seconds | |
//setTimeout( function() { | |
// bt.unSubscribeTicker(tickerSubscriptionID); | |
// bt.unSubscribeOrderbook(orderbookSubscriptionID); | |
//}, 20000); | |
}; | |
var on_transport_disconnected = function() { | |
console.log('on_transport_disconnected'); | |
clearInterval(testRequestInterval); | |
testRequestInterval = null; | |
// try to reconnect in 3 seconds | |
setTimeout( function() { | |
ws_transport.connect(on_transport_connected, on_transport_disconnected); | |
}, 3000); | |
}; | |
ws_transport.connect(on_transport_connected, on_transport_disconnected); | |
//console.log(getMACAddresses()); | |
/* | |
ws_transport = new BlinkTradeWebSocketTransport('wss://api.testnet.blinktrade.com/trade/'); | |
ws_transport.connect(); | |
bt = new BlinkTrade(ws_transport); | |
bt.sendLimitedBuyOrder('BTCBRL', 0.01, 1830.32).then(function(response_msg){ | |
console.log(util.inspect(response_msg)); | |
}); | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment