Commit a9eb0bca by rongjun

init

parents
node_modules/
package-lock.json
.idea/
const WebSocket = require('ws');
const SocksProxyAgent = require('socks-proxy-agent');
const proxy = process.env.agent;
const agent = proxy ? new SocksProxyAgent(proxy) : null;
// const zlib = require('zlib');
const wsUrl = 'wss://push.bibox.com/';
const request = require('request');
const host = 'https://api.bibox.com';
const CrytoJS = require('crypto-js');
const constants = require('./constants');
class biboxApi {
constructor() {
this.apiKey = '61e6fa70476199d7245e2993b01d33ef14cb24dd';
this.apiSecret = '269bdc93d18f9215814a6a25dc38a4a8915cd63a';
}
subscribeSymbols(symbols, callback) {
const channels = symbols.map((item) => {
return JSON.stringify({event: "addChannel", "channel": `bibox_sub_spot_${item}_depth`, "binary": 1});
});
const wss = new WebSocket(wsUrl, {agent});
wss.on('open', () => {
console.log("websocket on open");
for (let channel of channels) {
wss.send(channel);
}
});
wss.on('message', (data) => {
const response = JSON.parse(data);
if (Array.isArray(response) && response.length && response[0].channel.endsWith("depth")) {
callback(null, response[0]);
} else {
console.log(data);
callback(response, null);
}
});
wss.on('error', (error) => {
console.log(" websocket error:");
console.log(error);
})
wss.on('close', () => {
console.log("websocket closed");
this.subscribeSymbols(symbols, callback);
})
}
_publicRequest(path, params, callback) {
let url = host + path;
if (params) {
url += "?";
const keys = Object.keys(params);
for (let i = 0; i < keys.length; i++) {
url += `${keys[i]}=${params[keys[i]]}`;
if (i !== keys.length - 1) {
url += "&";
}
}
}
const options = {
url,
method: 'GET',
timeout: 8000,
forever: true,
};
request(options, (error, response, body) => {
if (error) {
callback(error);
} else {
try {
const result = JSON.parse(body);
if (result.result) {
callback(null, result);
} else {
callback(result, null);
}
} catch (e) {
callback(e, null);
}
}
});
}
_request(method, path, cmd, params, callback) {
const url = host + path;
const cmdStr = JSON.stringify([{"cmd": cmd, "body": params}]);
const sign = CrytoJS.HmacMD5(cmdStr, this.apiSecret).toString();
const form = {"cmds": cmdStr, "apikey": this.apiKey, "sign": sign};
const requestParams = {};
requestParams["url"] = url;
requestParams["method"] = method;
requestParams["form"] = form;
requestParams["timeout"] = 10000;
requestParams["forever"] = true;
request(requestParams, (error, response, body) => {
if (error) {
callback(error);
} else {
try {
const result = JSON.parse(body);
if (result.error) {
callback(result.error, null);
} else {
callback(null, result.result[0]);
}
} catch (e) {
console.error("parse body时出错");
console.error("status code:" + response.statusCode + ",body:" + response.body);
// if (response.statusCode === 429) {
// callback({statusCode: response.statusCode})
// } else {
callback(e, null);
// }
}
}
});
}
fetchSymbols(callback) {
this._publicRequest('/v1/mdata', {"cmd": 'pairList'}, callback);
}
order(price, amount, symbol, side, callback) {
//账户类型,0-普通账户,1-信用账户
//交易类型,1-市价单,2-限价单
//交易方向,1-买,2-卖
const params = {
pair: symbol,
account_type: 0,
order_type: 2,
order_side: side === constants.OrderSideBuy ? 1 : 2,
pay_bix: 1,
price,
amount,
// money:parseFloat(price) * parseFloat(amount)
};
this._request("POST", "/v1/orderpending", "orderpending/trade", params, callback)
}
balance(callback) {
this._request("POST", "/v1/transfer", "transfer/assets", {select: 1}, callback);
}
getTrades(symbol, callback) {
const params = {
"cmd": "deals",
"pair": symbol,
"size": 10
}
this._publicRequest("/v1/mdata", params, callback);
}
searchOrder(orderId, callback) {
const params = {
id: orderId
}
this._request("POST", "/v1/orderpending", "orderpending/order", params, callback);
}
cancelOrder(orderId, callback) {
const params = {
orders_id: orderId
}
this._request("POST", "/v1/orderpending", "orderpending/cancelTrade", params, callback);
}
fetchHistorOrders(page,size,symbol,side,callback){
const params = {
pair:symbol,
account_type:0,
page,
size,
order_side:side === constants.OrderSideBuy ? 1 : 2,
hide_cancel:0
};
this._request("POST","/v1/orderpending","orderpending/pendingHistoryList",params,callback);
}
}
module.exports = biboxApi;
\ No newline at end of file
const WebSocket = require('ws');
const SocksProxyAgent = require('socks-proxy-agent');
const proxy = process.env.agent;
const agent = proxy ? new SocksProxyAgent(proxy) : null;
// const zlib = require('zlib');
const wsUrl = 'wss://api.lbkex.com/ws/V2/';
const request = require('request');
const host = 'https://api.lbkex.com';
const CryptoJS = require('crypto-js');
const crypto = require('crypto');
const constants = require('./constants');
class lbankApi {
constructor() {
this.apiKey = '926468ad-9a27-4226-ae05-b23a22520f1d';
this.apiSecret = '-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK0KVME06yIf/HeFyCnsVXX39UsUogBJr1HYgD6K3AgCBFLDq2ItF/xPrn1smkG8IiIl2qjxNIkykc74BWNGDhboftrPniPz+eshl+zWkTb1QEizbIs6h4Rcjfd1z0KF0/lgh5EnrMRT/V6x9JVkg9bSzOZPLNnWtX9nkJnE32UNAgMBAAECgYA9tnqFsWbOc9PpmJfLg9Ly0Kz1yvT/30eci/co1wMkA/wgvFIKIIT2YkCb0LivCvatcQyrxeJzr8paow/g2OI66Qw4eSfyKXjp5H+IfZ1xgP1hF+HnwHrP+CAGKa/PgqRhD9CTrU7a9keKeJ7Kuj1Q6iA3MucO+yvL573BzHanwQJBANtvjxj/PqCFjLXqM0qt9Tq83bS93obU1HaPXDXeQjr91CE37+vMLxyx5Xwr3IGgEI82cLCyUMmA2IX6ga3E1/0CQQDJ37Brma3Ezeo9WsHkDv1xquFIRjXyhzBG57NynAFT8IMcWoiO+GyXLl/leaZrZOU71Ot1gygP29LiOasbfaZRAkB7vte1wwswPt/xHpe6P4uRijyE1qYM5yzBh2r6vdIfrlDYQtE76jOPPQsrERkSyI9OE+dM3eINIGn6dCB5PA6JAkA1G4TU+cvuH2HFHFAvyAXC1nqHwfjFQe1gaeoad5Id3AMR/Xs5aX9f0lJmEzfFvvhTYjNDaeqrKWB0JUmvZMHRAkEAqbmHUVn8qOqeX7cSxJPgmquEvq0wAD5Wl8cYSM0hloB2EWQ0Z9BGliRq0u0j/qdM1GK/xyAPzBIuhD5/McldZQ==\n-----END PRIVATE KEY-----';
}
subscribeSymbols(symbols, callback) {
const channels = symbols.map((item) => {
return JSON.stringify({action: "subscribe", subscribe: "depth", depth: 10, pair: item});
});
const wss = new WebSocket(wsUrl, {agent});
wss.on('open', () => {
console.log("websocket on open");
for (let channel of channels) {
wss.send(channel);
}
});
wss.on('message', (data) => {
const response = JSON.parse(data);
if (response['type'] === "depth") {
callback(null, response);
} else if(response['ping']){
console.log('lbank ping')
wss.send(JSON.stringify({"action": "pong", "pong": response['ping']}));
} else {
console.log(data);
callback(response, null);
}
});
wss.on('error', (error) => {
console.log(" websocket error:");
console.log(error);
})
wss.on('close', () => {
console.log("websocket closed");
this.subscribeSymbols(symbols, callback);
})
}
transform(obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
}
objKeySort(obj) {//排序的函数
var newkey = Object.keys(obj).sort();
//先用Object内置类的keys方法获取要排序对象的属性名,再利用Array原型上的sort方法对获取的属性名进行排序,newkey是一个数组
var newObj = {};//创建一个新的对象,用于存放排好序的键值对
for (var i = 0; i < newkey.length; i++) {//遍历newkey数组
newObj[newkey[i]] = obj[newkey[i]];//向新创建的对象中按照排好的顺序依次增加键值对
}
return newObj;//返回排好序的新对象
}
_publicRequest(path, params, callback) {
let url = host + path;
if (params) {
url += "?";
const keys = Object.keys(params);
for (let i = 0; i < keys.length; i++) {
url += `${keys[i]}=${params[keys[i]]}`;
if (i !== keys.length - 1) {
url += "&";
}
}
}
const options = {
url,
method: 'GET',
timeout: 8000,
forever: true,
};
request(options, (error, response, body) => {
if (error) {
callback(error);
} else {
try {
const result = JSON.parse(body);
callback(null, result);
} catch (e) {
callback(e, null);
}
}
});
}
_request(method, path, params, callback) {
const url = host + path;
params["api_key"] = this.apiKey;
const md5Str = CryptoJS.MD5(this.transform(this.objKeySort(params))).toString().toUpperCase();
const signer = crypto.createSign('SHA256');
signer.update(md5Str);
const sign = signer.sign(this.apiSecret, 'base64')
params["sign"] = sign;
const requestParams = {}
requestParams["url"] = url;
requestParams["method"] = method;
requestParams["form"] = params;
requestParams["timeout"] = 10000;
requestParams["forever"] = true;
request(requestParams, (error, response, body) => {
if (error) {
callback(error);
} else {
try {
const result = JSON.parse(body);
if (result.result === 'true') {
callback(null, result);
} else {
callback(result, null);
}
} catch (e) {
console.error("parse body时出错");
console.error("status code:" + response.statusCode + ",body:" + response.body);
// if (response.statusCode === 429) {
// callback({statusCode: response.statusCode})
// } else {
callback(e, null);
// }
}
}
});
}
fetchSymbols(callback) {
this._publicRequest('/v1/ticker.do', {"symbol": 'all'}, callback);
}
order(price, amount, symbol, side, callback) {
//账户类型,0-普通账户,1-信用账户
//交易类型,1-市价单,2-限价单
//交易方向,1-买,2-卖
const params = {
type: side,
symbol,
price,
amount
// money:parseFloat(price) * parseFloat(amount)
};
this._request("POST", "/v1/create_order.do", params, callback)
}
balance(callback) {
this._request("POST", "/v1/user_info.do", {}, callback);
}
getTrades(symbol, callback) {
const params = {
"symbol": symbol,
"size": 10
}
this._publicRequest("/v1/trades.do", params, callback);
}
searchOrder(orderId, symbol, callback) {
const params = {
order_id: orderId,
symbol
}
this._request("POST", "/v1/orders_info.do", params, callback);
}
cancelOrder(orderId, symbol, callback) {
const params = {
orders_id: orderId,
symbol
}
this._request("POST", "/v1/cancel_order.do", params, callback);
}
fetchHistorOrders(page, size, symbol, side, callback) {
const params = {
symbol: symbol,
current_page: page,
page_length: size,
};
this._request("POST", "/v1/orders_info_history.do", params, callback);
}
}
module.exports = lbankApi;
\ No newline at end of file
let symbolMap = {};
const redis = require("redis");
const redisClient = redis.createClient();
const lastDataMap = {};
const lastLastDataMap = {};
const constants =require('./constants');
class BaseCollector {
constructor(platformName, baseCurrencies,machine,str2Symbols) {
this.onSymbolUpdate = null;
this.allowTrade = true;
this.baseCurrencies = baseCurrencies;
this.platformName = platformName;
this.currencySymbolMap = {};
this.machine = machine;
this.balanceMap = {};
this.str2Symbols = str2Symbols;
}
/**
*
* @param asks [[price,amount],[price,amount]] 升序排序
* @param bids [[price,amount],[price,amount]] 降序排序
* @param timeStamp 从服务器获取的数据的时间戳
* @private
*/
_publishDataForStrategy3(asks, bids, symbol, timeStamp) {
if(!asks.length || !bids.length){
return;
}
const realSymbol = this._convertSymbolName(symbol);
const lastEventTime = this.getSymbolEventTime(realSymbol);
if(lastEventTime >= timeStamp){
return;
}
const data = {
bestBidQty: bids[0][1],
bestAskQty: asks[0][1],
eventTime: timeStamp,
bestBid: bids[0][0],
bestAsk: asks[0][0],
symbol: realSymbol,
asks: asks,
bids: bids,
}
if(parseFloat(data.bestBid) > parseFloat(data.bestAsk)){
console.error("同一交易对,卖价低于买价,可能数据有误");
return;
}
const key = `${realSymbol}@${this.platformName.toLowerCase()}0`;
redisClient.set(key, JSON.stringify(data), 'EX', 120);
const lastData = lastDataMap[realSymbol];
let dataChanged = true;
if (lastData) {
dataChanged = lastData.bestBidQty !== data.bestBidQty
|| lastData.bestAskQty !== data.bestAskQty || lastData.bestBid !== data.bestBid || lastData.bestAsk !== data.bestAsk
||lastData.asks.toString() !== data.asks.toString() || lastData.bids.toString() !== data.bids.toString();
}
if (dataChanged) {
lastDataMap[realSymbol] = data;
lastLastDataMap[realSymbol] = lastData;
const publistKey = `${this.platformName.toUpperCase()}0`;
redisClient.publish(publistKey, JSON.stringify({symbol: realSymbol, time: data.eventTime}));
if (this.onSymbolUpdate && this.allowTrade && this._allowPublish(asks,bids,symbol) ) {
this.onSymbolUpdate(realSymbol, "", Date.now() - data.eventTime);
}
}
}
_getSymbolDetail(fromCurrency,toCurrency){
let symbol = fromCurrency+toCurrency;
let detail = symbolMap[symbol];
if(detail){
return detail;
}
symbol = toCurrency+fromCurrency;
return symbolMap[symbol];
}
getBaseCurrency(symbol) {
for (const baseCurrency of this.baseCurrencies) {
if (symbol.endsWith(baseCurrency.toUpperCase())) {
return baseCurrency.toUpperCase();
}
}
}
getMidCurrency(symbol) {
for (const baseCurrency of this.baseCurrencies) {
if (symbol.endsWith(baseCurrency.toUpperCase())) {
return symbol.replace(new RegExp(baseCurrency.toUpperCase() + '$'), '');
}
}
}
getSymbols(currency) {
if (!currency || !this.currencySymbolMap[currency]) {
return [];
}
return this.currencySymbolMap[currency].sort(() => {
return Math.random() > 0.5;
})
}
getDepth(fromCurrency, toCurrency, depth = 1) {
let symbol = fromCurrency + toCurrency;
let data = lastDataMap[symbol];
if (data) {
const bids = data.bids;
return bids.slice(0, depth);
}
else {
symbol = toCurrency + fromCurrency;
data = lastDataMap[symbol];
if (!data) {
return 0;
}
const asks = data.asks;
return asks.slice(0, depth);
}
}
getLastDepth(fromCurrency, toCurrency, depth=1) {
let symbol = fromCurrency + toCurrency;
let data = lastLastDataMap[symbol];
if (data) {
const bids = data.bids;
return bids.slice(0, depth);
}
else {
symbol = toCurrency + fromCurrency;
data = lastLastDataMap[symbol];
if (!data) {
return 0;
}
const asks = data.asks;
return asks.slice(0, depth);
}
}
getSymbolEventTime(symbol) {
const keySymbol = this._convertSymbolName(symbol);
let lastData = lastDataMap[keySymbol];
if(lastData){
return lastData['eventTime'] || 0;
}
return 0;
}
isBaseCurrency(currency) {
return this.baseCurrencies.includes(currency);
}
getAmount(fromCurrency, toCurrency, depth = 1) {
let symbol = fromCurrency + toCurrency;
let data = lastDataMap[symbol];
if (data) {
const bids = data.bids;
return bids.length>=depth ?[bids[depth - 1][1], fromCurrency]:-1;
}
else {
symbol = toCurrency + fromCurrency;
data = lastDataMap[symbol];
if (!data) {
return 0;
}
const asks = data.asks;
return asks.length>=depth ?[asks[depth - 1][1], toCurrency]:-1;
}
}
getPrice(fromCurrency, toCurrency, depth = 1, isRaw = false) {
let symbol = fromCurrency + toCurrency;
let data = lastDataMap[symbol];
if (data) {
const bids = data.bids;
return bids.length>=depth?bids[depth - 1][0]:-1;
}
else {
symbol = toCurrency + fromCurrency;
data = lastDataMap[symbol];
if (!data) {
return -1;
}
const asks = data.asks;
if (isRaw)
return asks.length>=depth?asks[depth - 1][0]:-1;
if (asks.length >= depth && asks[depth - 1][0])
return 1.0 / asks[depth - 1][0];
else
return -1;
}
}
_handleFetchSymbolResult(error,data){
if(error){
console.error("获取交易对出错");
console.error(error);
this._fetchSymbols(this._handleFetchSymbolResult.bind(this));
return;
}
symbolMap={};
const symbolNames = [];
for(let key in data){
if(!data.hasOwnProperty(key)){
continue;
}
symbolNames.push(key);
const symbol = this._convertSymbolName(key);
symbolMap[symbol]=data[key];
const midCurrency = this.getMidCurrency(symbol);
const symbolArray = this.currencySymbolMap[midCurrency];
if (symbolArray) {
symbolArray.push(symbol);
} else {
this.currencySymbolMap[midCurrency] = [symbol];
}
}
this._subscribeSymbols(symbolNames,this._publishDataForStrategy3.bind(this),5);
}
runStrategy3(){
console.log("启动成功");
this._fetchSymbols(this._handleFetchSymbolResult.bind(this));
setInterval(()=>{
redisClient.get(this.machine + "_STOP", (err, value) => {
if (value) {
this.allowTrade = false;
console.log("滑点过多,停止交易");
} else {
this.allowTrade = true;
}
});
},1000 *10);
setInterval(()=>{
this._runMonitor((data)=>{
if(data){
this.balanceMap = {...data};
redisClient.set(this.machine,JSON.stringify(this.balanceMap),"EX",30);
}
});
},this._runMonitorInterval());
}
runStrategy2(){
// this.runWebserviceDepth();
// this.runMonitorForever();
this._subscribeSymbols(this.str2Symbols,(asks,bids,symbol,timeStamp)=>{
const key = symbol + `DEPTH@${this.platformName.toLowerCase()}`;
console.warn(key);
redisClient.set(key, JSON.stringify({
'symbol': symbol,
'asks': asks,
'bids': bids,
}), "EX", 15);
redisClient.publish(`${this.platformName.toUpperCase()}@2`, JSON.stringify({symbol: symbol, time: Date.now()}));
},5);
setInterval(() => {
this._runMonitor((data)=>{
if(!data){
redisClient.hset("balance", this.platformName.toLowerCase(), JSON.stringify({}));
}else{
redisClient.hset("balance", this.platformName.toLowerCase(), JSON.stringify(data));
}
});
}, 2000);
}
getCurrencyMaxReturnAmount(currency){
throw "应该覆盖此方法,返回该币种的最大回归量,主要用于规避风险;只有基础币需要设定此值";
}
processAmount(fromCurrency, toCurrency, amount){
throw "应覆盖此方法,按照平台规则对通量的精度进行处理";
}
processPrice(fromCurrency,toCurrency,amount){
throw "应覆盖此方法,按照平台规则对价格的精度进行处理";
}
getFeeRate(fromCurrency,toCurrency){
throw "应覆盖此方法,返回交易手续费";
}
/**
*
* @param callback function:(error,data),data应该是:{symbol:{}}
*/
_fetchSymbols(callback){
throw "应覆盖fetchSymbols(callback),从平台接口获取所有交易对"
}
/**
*
* @param callback function(data),data格式:{currency:{available,onOrder}},currency要求大写
*/
_runMonitor(callback){
throw "覆盖方法_runMonitor(callback),获取底仓,并返回结果"
}
_runMonitorInterval(){
return 10 *1000;
}
/**
* @param symbols 数组,需要订阅交易对
* @param callback function:(asks, bids, symbol, timeStamp)
*/
_subscribeSymbols(symbols, callback, subscribeDepth){
throw "应覆盖方法subscribeSymbols(symbols,callback),订阅交易对,并将数据回调";
}
/**
*
* @param symbol 此值的格式由子类在覆盖fetchSymbols方法时,调用callback所返回的数据的中的symbol决定
*/
_convertSymbolName(symbol){
throw "覆盖方法convertSymbolName(symbol),将symbol转换成如BTCUSDT的格式";
}
getSymbol(fromCurrency, toCurrency) {
throw "覆盖方法getSymbol(fromCurrency, toCurrency),按照平台API格式拼接出symbol";
}
getTradeSide(fromCurrency,toCurrency){
let symbol = fromCurrency+toCurrency;
const detail = symbolMap[symbol];
if(detail){
return constants.OrderSideSell;
}
return constants.OrderSideBuy;
}
_getLastData(symbol){
return lastDataMap[this._convertSymbolName(symbol)];
}
getDepthPrintStr(fromCurrency,toCurrency,depth=1){
const depthArray = this.getDepth(fromCurrency,toCurrency,depth);
let depthStr = "";
for(let i =0;i<depthArray.length;i++){
depthStr += depthArray[i].toString();
if(i!== depthArray.length-1){
depthStr +="<br/>";
}
}
return depthStr;
}
getLastDepthPrintStr(fromCurrency,toCurrency,depth=1){
const depthArray = this.getLastDepth(fromCurrency,toCurrency,depth);
let depthStr = "";
for(let i =0;i<depthArray.length;i++){
depthStr += depthArray[i].toString();
if(i!== depthArray.length-1){
depthStr +="<br/>";
}
}
return depthStr;
}
/**
* 添加额外的限制所有交易的条件
*/
_allowPublish(asks,bids,symbol){
const midCurrency = this.getMidCurrency(symbol);
const balance = this.balanceMap[midCurrency];
if(!this.isBaseCurrency(midCurrency) && balance && balance.onOrder >0){
return false;
}
// if(!asks.length >=5 || !bids.length >=5){
// console.error("深度不足,放弃此轮");
// return false;
// }
return true;
}
getCurrencyBalance(currency, includeOnOrder = false) {
const detail = this.balanceMap[currency.toUpperCase()];
if (detail) {
return includeOnOrder ? parseFloat(detail.available) + parseFloat(detail.onOrder) : parseFloat(detail.available);
}
return 0;
}
}
module.exports = BaseCollector;
const BaseCollector = require('./baseCollector');
const baseCurrencies = ["BIX","ETH","BTC","USDT"];
const machine = process.env['MACHINE'];
const biboxApi = require('./api');
const zlib = require('zlib');
const Strategy3MaxAmountMap = {
USDT: 1000,
BTC: 0.15,
ETH: 1.5,
BIX:600
}
class BiboxCollector extends BaseCollector{
constructor(wantedSymbols){
super("BIBOX",baseCurrencies,machine,wantedSymbols);
this.api = new biboxApi('','');
}
_convertSymbolName(symbol){
return symbol.replace("_","");
}
_fetchSymbols(callback){
this.api.fetchSymbols((error,data)=>{
if(error){
console.error("fetch symbol error");
console.error(error);
this._fetchSymbols(callback);
}else{
const symbolDetails = data.result;
const symbolMap = {};
for(let detail of symbolDetails){
symbolMap[detail.pair] = detail;
}
callback(null,symbolMap);
}
})
}
_runMonitorInterval(){
return 5 *1000;
}
_subscribeSymbols(symbols,callback,subscribeDepth){
this.api.subscribeSymbols(symbols,(error,data)=>{
if(error){
console.error("subscribe error");
console.error(error);
}else{
const symbol = data.channel.replace("bibox_sub_spot_","").replace("_depth","").replace("_","");
const decodeStr = Buffer.from(data.data,'base64');
const unzipData = zlib.unzipSync(decodeStr);
const result = JSON.parse(unzipData.toString());
// const symbol = result.pair.replace("_","");
const timeStamp = result.update_time;
const asks = result.asks.slice(0,subscribeDepth).map((item)=>[item.price,item.volume]);
const bids = result.bids.slice(0,subscribeDepth).map((item)=>[item.price,item.volume]);
callback(asks, bids, symbol, timeStamp);
}
})
}
_runMonitor(callback){
this.api.balance((error,result)=>{
if(error){
console.error("get balance error");
console.error(error);
callback(null);
}else{
const balanceList = result.result.assets_list;
const balanceMap = {};
for(let detail of balanceList){
if(detail.balance >0 || detail.freeze >0 || balanceMap[detail.coin_symbol]){
balanceMap[detail.coin_symbol] = {available:detail.balance,onOrder:detail.freeze};
}
}
callback(balanceMap);
}
})
}
getSymbol(fromCurrency,toCurrency){
let symbolDetail = this._getSymbolDetail(fromCurrency,toCurrency);
return symbolDetail.pair;
}
getFeeRate(fromCurrency,toCurrency){
return 0.0005;
}
processAmount(fromCurrency,toCurrency,amount){
//有可能会由于数值过小,传进来的amount被表示为科学计数法法
const amountStr = parseFloat(amount).toFixed(10);
const nums = amountStr.split('.');
if(nums.length ===2 && nums[1].length>4){
return nums[0]+"."+nums[1].slice(0,4);
}
return amount;
}
processPrice(fromCurrency,toCurrency,price){
// const amountStr = price+'';
// const nums = amountStr.split('.');
// if(nums.length ===2 && nums[1].length>4){
// return nums[0]+"."+nums[1].slice(0,4);
// }
return price;
}
getCurrencyMaxReturnAmount(currency){
const balance = this.getCurrencyBalance(currency);
return Math.min(Strategy3MaxAmountMap[currency],balance);
}
getDepthPrintStr(fromCurrency,toCurrency,depth=1){
return super.getDepthPrintStr(fromCurrency,toCurrency,3);
}
}
module.exports = BiboxCollector;
const Strategy3 = require('./strategy3');
const machine = process.env['MACHINE'];
const Order = require('./order');
const constants = require('./constants');
const STRATEGY3_RETURN_MIN_AMOUNT_MAP = {
USDT: 20,
BTC: 0.002,
ETH: 0.03,
BIX: 15,
};
class BiboxStrategy3 extends Strategy3 {
constructor(collector) {
super(collector, machine);
this.orderService = new Order();
}
_doTrade(baseCurrency1, midCurrency, baseCurrency2, buyPrice, sellPrice, returnPrice, amount, returnAmount, doSaveOrder) {
const buySymbol = this.collector.getSymbol(baseCurrency1, midCurrency);
const buyStartTime = Date.now();
const collector = this.collector;
const orderService = this.orderService;
const sellSymbol = this.collector.getSymbol(midCurrency, baseCurrency2);
const returnSymbol = this.collector.getSymbol(baseCurrency2, baseCurrency1);
let createdSellOrder = false;
let createdBuyOrder = false;
let retryTime = 8;
function sellOrder() {
console.log("sell@" + sellSymbol + " amount:" + amount + " price:" + sellPrice);
const sellStartTime = Date.now();
orderService.order(
sellSymbol, sellPrice, amount, constants.OrderSideSell
, (error, order) => {
if (error) {
if(error.code === "2027"){
if(retryTime>0 && !createdSellOrder){
console.log("提示余额不足,再次尝试");
retryTime -- ;
// setTimeout(()=>{
sellOrder();
// },50);
}else if(!createdSellOrder && createdBuyOrder){
console.log("已没有重试次数,但是买单已创建成功,继续重试");
setTimeout(()=>{
sellOrder();
},500);
}
}
console.error("sell error:" + JSON.stringify(error) + ";sell price:" + sellPrice + " @amount:" + amount);
return;
}
createdSellOrder = true;
doSaveOrder(order, midCurrency, baseCurrency2, constants.OrderTypeSell);
console.log("sell start@" + sellStartTime + " end@" + Date.now() + " symbol:" + sellSymbol);
})
}
function returnOrder() {
console.log("return@" + returnSymbol + " amount:" + returnAmount + " price:" + returnPrice);
const returnStartTime = Date.now();
orderService.order(returnSymbol, returnPrice, returnAmount, collector.getTradeSide(baseCurrency2, baseCurrency1)
, (error, order) => {
if (error) {
console.error("return error:");
console.error(error);
return;
}
console.log("return start@" + returnStartTime + " end@" + Date.now() + " symbol:" + returnSymbol);
doSaveOrder(order, baseCurrency2, baseCurrency1, constants.OrderTypeReturn);
}, true);
}
console.log("buy@" + buySymbol + " amount:" + amount + " price:" + buyPrice);
orderService.FOKLikeOrder(buySymbol, buyPrice, amount, constants.OrderSideBuy
, (error, order) => {
if (error) {
console.error("buy error:");
console.error(error);
return;
}
console.log("buy start@" + buyStartTime + " end@" + Date.now() + " symbol:" + buySymbol);
if (order.executedQty === order.origQty) {
console.log("买入全部成交");
createdBuyOrder = true;
setTimeout(()=>{
sellOrder();
},95);
returnOrder();
} else if (parseFloat(order.executedQty) > 0) {
returnAmount = parseFloat(returnAmount) * parseFloat(order.executedQty) / parseFloat(amount);
returnAmount = collector.processAmount(baseCurrency2, baseCurrency1, returnAmount);
amount = collector.processAmount(midCurrency, baseCurrency2, parseFloat(order.executedQty));
console.log(`买入部分成交${order.executedQty} 回归量调整为${returnAmount}`);
order.remark = "部分成交@amount " + order.executedQty + ";";
createdBuyOrder = true;
if (parseFloat(amount) > 0)
setTimeout(()=>{
sellOrder();
},95);
if (parseFloat(returnAmount) > 0)
returnOrder();
else {
console.log("回归数量太小,不执行回归");
}
} else {
console.warn("买入失败");
retryTime = 0;
}
doSaveOrder(order, baseCurrency1, midCurrency, constants.OrderTypeBuy);
})
// if(!this.collector.isBaseCurrency(midCurrency) && this.collector.getCurrencyBalance(midCurrency,true) < amount){
// for(let i=0;i<2;i++){
// setTimeout(()=>{
// sellOrder();
// },i*200+100);
// }
// }
}
_getTrades(order, callback) {
callback([]);
}
_getMinReturnAmount(currency) {
return STRATEGY3_RETURN_MIN_AMOUNT_MAP[currency] || 1;
}
_getMinTradeInterval(){
return 5000;
}
_needConsiderDepthCount(){
return [[2,1],[3,2,1],[2,1]];
}
}
const BiboxCollector = require('./biboxCollector');
const collector = new BiboxCollector(null);
collector.runStrategy3();
const strategy3 = new BiboxStrategy3(collector);
strategy3.run();
module.exports = {
TimeInForceGTC: 'GTC',
TimeInForceIOC: 'IOC',
TimeInForceFOK: 'FOK',
OrderStatusNew: 'NEW',
OrderStatusPartiallyFilled: 'PARTIALLY_FILLED',
OrderStatusFilled: 'FILLED',
OrderStatusCanceled: 'CANCEL',
OrderStatusPendingCancel: 'CANCELING',
// OrderStatusRejected: 'REJECTED',
// OrderStatusExpired: 'EXPIRED',
// STRATEGY3_MIN_MARGIN: 0.07,
STRATEGY3_RETURN_MIN_AMOUNT_MAP: {
USDT:18,
BTC:0.002,
ETH:0.03,
OKB:6
},
STRATEGY3_AMOUNT_RATIO: 1.0,
RecordHost: process.env["RecordHost"] || "127.0.0.1",
RecordPort: process.env["RecordPort"] || "8200",
SaveOrderPath: 'api/order/',
SaveRecordPath: 'api/record/',
OrderTypeBuy: 'BUY',
OrderTypeSell: 'SELL',
OrderTypeReturn: 'RETURN',
OrderTypeOther: 'OTHER',
// Platform: 'GATEIO',
// MinInterval: 1000*60*2,
RealOrder:true,
SocketReadyStateConnecting:0,
SocketReadyStateOpen:1,
SocketReadyStateClosing:2,
SocketReadyStateClosed:3,
OrderSideBuy:"buy",
OrderSideSell:"sell",
}
\ No newline at end of file
const BaseCollector = require('./baseCollector');
const baseCurrencies = ["BIX","ETH","BTC","USDT"];
const machine = process.env['MACHINE'];
const biboxApi = require('./api_lbank');
const zlib = require('zlib');
const Strategy3MaxAmountMap = {
USDT: 1000,
BTC: 0.15,
ETH: 1.5,
BIX:600
}
class BiboxCollector extends BaseCollector{
constructor(wantedSymbols){
super("LBANK",baseCurrencies,machine,wantedSymbols);
this.api = new biboxApi('','');
}
_convertSymbolName(symbol){
return symbol.replace("_","").toUpperCase();
}
_fetchSymbols(callback){
this.api.fetchSymbols((error,data)=>{
if(error){
console.error("fetch symbol error");
console.error(error);
this._fetchSymbols(callback);
}else{
const symbolDetails = data;
const symbolMap = {};
for(let detail of symbolDetails){
symbolMap[detail.symbol] = detail;
}
callback(null,symbolMap);
}
})
}
_runMonitorInterval(){
return 10 *1000;
}
_subscribeSymbols(symbols,callback,subscribeDepth){
this.api.subscribeSymbols(symbols,(error,data)=>{
if(error){
console.error("subscribe error");
console.error(error);
}else{
const symbol = data['pair'];
// const symbol = result.pair.replace("_","");
const timeStamp = data['TS'];
const depth = data['depth'];
const asks = depth.asks.slice(0,subscribeDepth).map((item)=>[item[0],item[1]]);
const bids = depth.bids.slice(0,subscribeDepth).map((item)=>[item[0],item[1]]);
callback(asks, bids, symbol, timeStamp);
}
})
}
_runMonitor(callback){
this.api.balance((error,result)=>{
if(error){
console.error("get balance error");
console.error(error);
callback(null);
}else{
const balanceList = result.info.free;
const balanceMap = {};
for(let detail in balanceList){
balanceMap[detail] = {available:balanceList[detail],onOrder:0};
}
const freezes = result.info.freeze;
for(let fz in freezes){
if(balanceMap[fz]){
balanceMap[fz]['onOrder'] = freezes[fz];
}else{
balanceMap[fz] = {available:0,onOrder:freezes[fz]};
}
}
callback(balanceMap);
}
})
}
getSymbol(fromCurrency,toCurrency){
let symbolDetail = this._getSymbolDetail(fromCurrency,toCurrency);
return symbolDetail.pair;
}
getFeeRate(fromCurrency,toCurrency){
return 0.001;
}
processAmount(fromCurrency,toCurrency,amount){
//有可能会由于数值过小,传进来的amount被表示为科学计数法法
const amountStr = parseFloat(amount).toFixed(10);
const nums = amountStr.split('.');
if(nums.length ===2 && nums[1].length>4){
return nums[0]+"."+nums[1].slice(0,4);
}
return amount;
}
processPrice(fromCurrency,toCurrency,price){
// const amountStr = price+'';
// const nums = amountStr.split('.');
// if(nums.length ===2 && nums[1].length>4){
// return nums[0]+"."+nums[1].slice(0,4);
// }
return price;
}
getCurrencyMaxReturnAmount(currency){
const balance = this.getCurrencyBalance(currency);
return Math.min(Strategy3MaxAmountMap[currency],balance);
}
getDepthPrintStr(fromCurrency,toCurrency,depth=1){
return super.getDepthPrintStr(fromCurrency,toCurrency,3);
}
}
module.exports = BiboxCollector;
const Strategy3 = require('./strategy3');
const machine = process.env['MACHINE'];
const Order = require('./order');
const constants = require('./constants');
const STRATEGY3_RETURN_MIN_AMOUNT_MAP = {
USDT: 20,
BTC: 0.002,
ETH: 0.03,
BIX: 15,
};
class BiboxStrategy3 extends Strategy3 {
constructor(collector) {
super(collector, machine);
this.orderService = new Order();
}
_doTrade(baseCurrency1, midCurrency, baseCurrency2, buyPrice, sellPrice, returnPrice, amount, returnAmount, doSaveOrder) {
const buySymbol = this.collector.getSymbol(baseCurrency1, midCurrency);
const buyStartTime = Date.now();
const collector = this.collector;
const orderService = this.orderService;
const sellSymbol = this.collector.getSymbol(midCurrency, baseCurrency2);
const returnSymbol = this.collector.getSymbol(baseCurrency2, baseCurrency1);
let createdSellOrder = false;
let createdBuyOrder = false;
let retryTime = 8;
function sellOrder() {
console.log("sell@" + sellSymbol + " amount:" + amount + " price:" + sellPrice);
const sellStartTime = Date.now();
orderService.order(
sellSymbol, sellPrice, amount, constants.OrderSideSell
, (error, order) => {
if (error) {
if(error.code === "2027"){
if(retryTime>0 && !createdSellOrder){
console.log("提示余额不足,再次尝试");
retryTime -- ;
// setTimeout(()=>{
sellOrder();
// },50);
}else if(!createdSellOrder && createdBuyOrder){
console.log("已没有重试次数,但是买单已创建成功,继续重试");
setTimeout(()=>{
sellOrder();
},500);
}
}
console.error("sell error:" + JSON.stringify(error) + ";sell price:" + sellPrice + " @amount:" + amount);
return;
}
createdSellOrder = true;
doSaveOrder(order, midCurrency, baseCurrency2, constants.OrderTypeSell);
console.log("sell start@" + sellStartTime + " end@" + Date.now() + " symbol:" + sellSymbol);
})
}
function returnOrder() {
console.log("return@" + returnSymbol + " amount:" + returnAmount + " price:" + returnPrice);
const returnStartTime = Date.now();
orderService.order(returnSymbol, returnPrice, returnAmount, collector.getTradeSide(baseCurrency2, baseCurrency1)
, (error, order) => {
if (error) {
console.error("return error:");
console.error(error);
return;
}
console.log("return start@" + returnStartTime + " end@" + Date.now() + " symbol:" + returnSymbol);
doSaveOrder(order, baseCurrency2, baseCurrency1, constants.OrderTypeReturn);
}, true);
}
console.log("buy@" + buySymbol + " amount:" + amount + " price:" + buyPrice);
orderService.FOKLikeOrder(buySymbol, buyPrice, amount, constants.OrderSideBuy
, (error, order) => {
if (error) {
console.error("buy error:");
console.error(error);
return;
}
console.log("buy start@" + buyStartTime + " end@" + Date.now() + " symbol:" + buySymbol);
if (order.executedQty === order.origQty) {
console.log("买入全部成交");
createdBuyOrder = true;
setTimeout(()=>{
sellOrder();
},95);
returnOrder();
} else if (parseFloat(order.executedQty) > 0) {
returnAmount = parseFloat(returnAmount) * parseFloat(order.executedQty) / parseFloat(amount);
returnAmount = collector.processAmount(baseCurrency2, baseCurrency1, returnAmount);
amount = collector.processAmount(midCurrency, baseCurrency2, parseFloat(order.executedQty));
console.log(`买入部分成交${order.executedQty} 回归量调整为${returnAmount}`);
order.remark = "部分成交@amount " + order.executedQty + ";";
createdBuyOrder = true;
if (parseFloat(amount) > 0)
setTimeout(()=>{
sellOrder();
},95);
if (parseFloat(returnAmount) > 0)
returnOrder();
else {
console.log("回归数量太小,不执行回归");
}
} else {
console.warn("买入失败");
retryTime = 0;
}
doSaveOrder(order, baseCurrency1, midCurrency, constants.OrderTypeBuy);
})
// if(!this.collector.isBaseCurrency(midCurrency) && this.collector.getCurrencyBalance(midCurrency,true) < amount){
// for(let i=0;i<2;i++){
// setTimeout(()=>{
// sellOrder();
// },i*200+100);
// }
// }
}
_getTrades(order, callback) {
callback([]);
}
_getMinReturnAmount(currency) {
return STRATEGY3_RETURN_MIN_AMOUNT_MAP[currency] || 1;
}
_getMinTradeInterval(){
return 5000;
}
_needConsiderDepthCount(){
return [[2,1],[3,2,1],[2,1]];
}
}
const BiboxCollector = require('./lbankCollector');
const collector = new BiboxCollector(null);
collector.runStrategy3();
const strategy3 = new BiboxStrategy3(collector);
strategy3.run();
const constants = require('./constants');
const biboxApi = require('./api');
const StateFilled = 3;
const StateNew = 1;
const StatePartiallyFilled = 2;
const StatePartiallyCancelled = 4;
const StateCancelled = 5;
const StateCancelling = 6;
function returnFakeOrder(symbol, price, amount) {
return {
orderId: "testOrder",
price: price,
status: constants.OrderStatusCanceled,
transactTime: Date.now(),
origQty: amount,
executedQty: 0,
symbol: symbol,
}
}
function convertToRecordOrder(order) {
let status;
switch (order.status) {
case StateFilled:
case StatePartiallyCancelled:
status = constants.OrderStatusFilled;
break;
case StateCancelled:
status = constants.OrderStatusCanceled;
break;
case StateNew:
status = constants.OrderStatusNew;
break;
case StatePartiallyFilled:
status = constants.OrderStatusPartiallyFilled;
break;
case StateCancelling:
status = constants.OrderStatusPendingCancel;
break;
}
return {
orderId: order.id + '',
price: order.price,
status: status,
transactTime: order.createdAt,
origQty: order.amount,
executedQty: order.deal_amount,
symbol: order.pair,
type: order.order_side,
}
}
function isTimeOutError(error){
return error.code === 'ESOCKETTIMEDOUT' || error.code === 'ETIMEDOUT';
}
class Order {
constructor() {
this.api = new biboxApi();
}
_handleFOKSearchResult(orderId, finalCallback, error, result) {
if (error) {
console.error("搜索订单出错");
console.error(error);
setTimeout(() => {
this.api.searchOrder(orderId, this._handleFOKSearchResult.bind(this, orderId, finalCallback));
}, 100);
return;
}
const order = result.result;
if(!order.amount && !order.deal_amount){
console.error("没有返回amount 和deal amount字段,继续搜索");
this.api.searchOrder(orderId, this._handleFOKSearchResult.bind(this, orderId, finalCallback));
}else if (order.status === StateFilled || order.status === StateCancelled || order.status === StatePartiallyCancelled) {
finalCallback(null, convertToRecordOrder(order));
} else if (order.status === StateNew || order.status === StatePartiallyFilled) {
this.api.cancelOrder(orderId, (error, result) => {
// setTimeout(() => {
console.log("尝试取消,准备搜索订单");
this.api.searchOrder(orderId, this._handleFOKSearchResult.bind(this, orderId, finalCallback));
// }, 80)
})
} else {
setTimeout(() => {
console.log("订单尚未完成或取消,再次搜索");
this.api.searchOrder(orderId, this._handleFOKSearchResult.bind(this, orderId, finalCallback));
}, 200);
}
}
FOKLikeOrder(symbol, price, amount, side, callback) {
if (!constants.RealOrder) {
callback(null, returnFakeOrder(symbol, price, amount));
return;
}
this.api.order(price, amount, symbol, side, (error, result) => {
if (error) {
callback(error, null);
return;
}
const orderId = result.result;
setTimeout(()=>{
this.api.searchOrder(orderId, this._handleFOKSearchResult.bind(this, orderId, callback));
},50);
})
}
order(symbol, price, amount, side, callback,mustSuccess = false) {
if (!constants.RealOrder) {
callback(null, returnFakeOrder(symbol, price, amount));
return;
}
this.api.order(price, amount, symbol, side, (error, result) => {
if (error) {
callback(error, null);
return;
}
const orderId = result.result;
const api2 = this.api;
function handleSearchResult(error, result) {
if (error) {
console.error("搜索订单出错:" + orderId);
// setTimeout(()=>{
api2.searchOrder(orderId, handleSearchResult.bind(this));
// },200);
return;
}
if(!result.result.amount){
console.error("没有返回amount,再次搜索");
api2.searchOrder(orderId, handleSearchResult.bind(this));
return;
}
callback(null, convertToRecordOrder(result.result));
}
this.api.searchOrder(orderId, handleSearchResult.bind(this));
})
}
}
module.exports = Order;
\ No newline at end of file
{
"name": "gate",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"strategy2": "node $NODE_DEBUG_OPTION strategy2.js",
"test": "node $NODE_DEBUG_OPTION test_lbank.js",
"strategy3": "export MACHINE='L'; node $NODE_DEBUG_OPTION lbankStrategy3.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"crypto": "^1.0.1",
"crypto-js": "^3.1.9-1",
"redis": "^2.8.0",
"request": "^2.87.0",
"socks-proxy-agent": "^4.0.1",
"ws": "^5.2.0"
}
}
const request = require('request');
const constants = require('./constants');
module.exports = class Service {
constructor(ip, port = 8300,platform) {
this.ip = ip;
this.port = port;
this.platform = platform;
}
saveOrder({origQty, fromCurrency, toCurrency, price, orderId, executedQty, status, remark, operationType, source, relatedRecordId}, callback) {
const url = `http://${constants.RecordHost}:${constants.RecordPort}/${constants.SaveOrderPath}`;
// console.log("do save order:"+fromCurrency+"=>"+toCurrency+" @amount:"+origQty+" @price:"+price);
request.post(url, {
form: {
prefer_amount: origQty,
from_currency: fromCurrency.toUpperCase(),
to_currency: toCurrency.toUpperCase(),
prefer_price: price,
price,
platform_id: orderId,
amount: executedQty,
state: status,
remark,
operation_type: operationType,
source,
related_record: relatedRecordId,
platform: this.platform,
}
}, (err, res) => {
if (err) {
console.log("save order error:" + relatedRecordId);
console.error(err);
} else if (callback) {
callback(null, JSON.parse(res.body));
}
});
}
saveRecord({buyPrice, sellPrice, returnPrice, buyFromCurrency, buyToCurrency, sellToCurrency, buyRemark, sellRemark, returnRemark}, callback) {
const url = `http://${constants.RecordHost}:${constants.RecordPort}/${constants.SaveRecordPath}`;
request.post(url, {
form: {
buy_price: buyPrice,
sell_price: sellPrice,
return_price: returnPrice,
buy_from_currency: buyFromCurrency.toUpperCase(),
buy_to_currency: buyToCurrency.toUpperCase(),
sell_from_currency: buyToCurrency.toUpperCase(),
sell_to_currency: sellToCurrency.toUpperCase(),
buy_remark: buyRemark,
sell_remark: sellRemark,
return_remark: returnRemark,
buy_platform: this.platform,
sell_platform: this.platform,
return_platform: this.platform,
}
}, (err, res) => {
if (err) {
console.log("save record error");
console.error(err);
} else if (callback) {
callback(null, JSON.parse(res.body))
// const fakeId = Date.now() + ''
// callback(null, {data: {id: fakeId}})
}
});
}
}
\ No newline at end of file
const RecordService = require('./recordService');
class Strategy3 {
constructor(collector, machine) {
this.collector = collector;
this.service = new RecordService(null,null,collector.platformName);
this.lastFuckTime = 0;
this.machine = machine;
}
run() {
this.collector.onSymbolUpdate = this.handleSymbolUpdate.bind(this);
}
handleSymbolUpdate(symbol, source) {
if (symbol) {
const midCurrency = this.collector.getMidCurrency(symbol);
const symbols = this.collector.getSymbols(midCurrency);
for (const currentSymbol of symbols) {
if (currentSymbol != symbol && Date.now() - this.lastFuckTime > this._getMinTradeInterval()) {
if (this.handleSymbolPairs(currentSymbol, symbol, source)) {
this.lastFuckTime = Date.now();
}
}
}
}
}
handleSymbolPairs(symbol1, symbol2, source) {
const startTime = Date.now();
const result = this.calculateSymbolsMargin(symbol1, symbol2, source);
const endTime = Date.now();
if (result != -1) {
console.log('计算开始:' + startTime + ' 计算结束:' + endTime);
const buyDepth = this.collector.getDepthPrintStr(result[0], result[1]);
const sellDepth = this.collector.getDepthPrintStr(result[1], result[2]);
const returnDepth = this.collector.getDepthPrintStr(result[2], result[0]);
const lastBuyDepth = this.collector.getLastDepthPrintStr(result[0],result[1]);
const lastSellDepth = this.collector.getLastDepthPrintStr(result[1], result[2]);
const buyRemark = `<p>通量${result[7]}<br/>now:${buyDepth.toString()}<br/>last:${lastBuyDepth}</p>`;
const sellRemark = `<p>通量${result[7]}<br/>now:${sellDepth}<br/>last:${lastSellDepth}</p>`;
const returnRemark = `<p>通量${result[8]}<br/>${returnDepth.toString()}</p>`;
const baseCurrency1 = result[0];
const midCurrency = result[1];
const baseCurrency2 = result[2];
const buyPrice = result[9];
const sellPrice = result[10];
const returnPrice = result[11];
let amount = result[7];
let returnAmount = result[8];
// console.log({buyRemark, sellRemark, returnRemark});
if(this._logDelay()){
const buySymbol = this.collector.getSymbol(baseCurrency1, midCurrency);
const sellSymbol = this.collector.getSymbol(midCurrency, baseCurrency2);
const buyDelay = endTime - this.collector.getSymbolEventTime(buySymbol);
const sellDelay = endTime - this.collector.getSymbolEventTime(sellSymbol);
console.log('买入交易对延迟:' + buyDelay + " 卖出交易对延迟:" + sellDelay);
}
const service = this.service;
let savedRecord = null;
const finishedOrders = [];
const that = this;
function tryToSaveOrder(order, fromCurrency = null, toCurrency = null, operationType = null) {
if (fromCurrency)
order.fromCurrency = fromCurrency;
if (toCurrency)
order.toCurrency = toCurrency;
if (operationType)
order.operationType = operationType;
if (savedRecord) {
order.relatedRecordId = savedRecord.id;
order.source = that.machine;
if(source){
order.source = order.source + `(${source})`;
}
that._getTrades(order, (samePriceTrade) => {
if (!order.remark) {
order.remark = '';
}
if (!samePriceTrade.length) {
order.remark = order.remark + ",订单落地:" + order.transactTime;
service.saveOrder(order);
} else {
samePriceTrade = samePriceTrade.reverse();
order.remark = order.remark + "," + samePriceTrade.toString() + " 订单落地:" + order.transactTime;
service.saveOrder(order);
}
})
} else {
finishedOrders.push(order);
}
}
this._doTrade(baseCurrency1, midCurrency, baseCurrency2, buyPrice, sellPrice, returnPrice, amount, returnAmount, tryToSaveOrder);
//保存利差记录
service.saveRecord({
buyPrice: result[4], sellPrice: result[5], returnPrice: result[6], buyRemark, sellRemark, returnRemark,
buyFromCurrency: baseCurrency1, buyToCurrency: midCurrency, sellToCurrency: baseCurrency2
}, (err, res) => {
if (err) {
console.error(err);
} else {
savedRecord = res.data;
for (const order of finishedOrders) {
tryToSaveOrder(order);
}
}
});
return true;
}
return false;
}
_doTrade(baseCurrency1, midCurrency, baseCurrency2, buyPrice, sellPrice, returnPrice, amount, returnAmount, doSaveOrder) {
throw "覆盖此方法,完成交易";
}
/**
* @param callback function(samePriceOrder),samePriceOrder是数组,每个元素是一个订单的json,每个订单需要time,price,amount
*/
_getTrades(order,callback) {
throw "覆盖方法_getTrades(symbol,filterDate,callback),获取当前时间前后1秒的同价订单"
}
_logDelay(){
return false;
}
/**
* 手续费扣除是否通过平台币等币种另外扣除
* 默认是true
* @returns {boolean}
*/
_isFeeDeducedByOther(){
return true;
}
/**
*
* @returns {number} 百分比
*/
_getMinMargin(){
return 0.07;
}
_getMinReturnAmount(currency){
throw '返回最小回归利差量';
}
_getMinTradeInterval(){
return 1000 *5;
}
/**
* 可覆盖此方法,添加额外的放弃订单的规则,默认采取相对保守的措施
* 如果子类仍需要默认的保守措施,记得调用super方法
*/
_giveUpOrder(baseCurrency1, midCurrency, baseCurrency2,totalMarginRate,buyDepth,sellDepth){
const buyAmount = this._getTotalAmount(baseCurrency1, midCurrency, buyDepth)[0];
const sellAmount = this._getTotalAmount(midCurrency, baseCurrency2, sellDepth)[0];
if (parseFloat(buyAmount) > parseFloat(sellAmount)) {
return true;
}
const buyLastDepth = this.collector.getLastDepth(baseCurrency1, midCurrency);
const buyNowDepth = this.collector.getDepth(baseCurrency1, midCurrency);
const sellLastDepth = this.collector.getLastDepth(midCurrency, baseCurrency2);
const sellNowDepth = this.collector.getDepth(midCurrency, baseCurrency2);
if (buyLastDepth && buyNowDepth && sellLastDepth && sellNowDepth) {
if ((parseFloat(buyLastDepth[0][0]) - parseFloat(buyNowDepth[0][0])) / parseFloat(buyNowDepth[0][0]) < (parseFloat(sellNowDepth[0][0]) - parseFloat(sellLastDepth[0][0])) / parseFloat(sellLastDepth[0][0])) {
return true;
}
}
return false;
}
_adjustPrice(buyRawPrice,sellRawPrice,returnRawPrice,returnSide,totalMargin){
return [buyRawPrice,sellRawPrice,returnRawPrice];
}
/**
* 计算利差时,买,卖和回归分别看几个深度,默认都只看一个深度
*/
_needConsiderDepthCount(){
return [[1],[1],[1]];
}
calculateSymbolsMargin(symbol1, symbol2, source) {
//判断是不是同一个交易对
if (symbol1 == symbol2) {
return -1;
}
//判断是同一个山寨币
const midCurrency1 = this.collector.getMidCurrency(symbol1);
const midCurrency2 = this.collector.getMidCurrency(symbol2);
if (midCurrency1 != midCurrency2)
return -1;
//判断是否用了基础币来作为中间币
// if (this.collector.isBaseCurrency(midCurrency1))
// return -1;
//获取基础币交易对
const baseCurrency1 = this.collector.getBaseCurrency(symbol1);
const baseCurrency2 = this.collector.getBaseCurrency(symbol2);
// let result = this.calculateRouteMargin(baseCurrency1, midCurrency1, baseCurrency2, source);
// if (result === -1){
let result = this.calculateRouteMargin(baseCurrency2, midCurrency1, baseCurrency1, source);
if(result === -1){
result = this.calculateRouteMargin(baseCurrency1,midCurrency1,baseCurrency2,source);
}
// }
return result;
}
calculateRouteMargin(baseCurrency1, midCurrency, baseCurrency2, source) {
const best5SellDepth = this.collector.getDepth(midCurrency,baseCurrency2,5);
if(best5SellDepth.length <5){
console.error(`${midCurrency}${baseCurrency2}深度不足5个,放弃此轮`);
return -1;
}
const depthCount = this._needConsiderDepthCount();
const buyDepthCount = depthCount[0];
const sellDepthCount = depthCount[1];
const returnDepthCount = depthCount[2];
let finalResult = -1;
for(let i=0;i<buyDepthCount.length;i++){
for(let j=0;j<sellDepthCount.length;j++){
for(let k=0;k<returnDepthCount.length;k++){
const buyDepth = buyDepthCount[i];
const sellDepth = sellDepthCount[j];
const returnDepth = returnDepthCount[k];
const result = this.calculateBestSolution(baseCurrency1, midCurrency, baseCurrency2,buyDepth,sellDepth,returnDepth);
const amount = result[0];
const returnAmount = result[1];
const totalMarginRate = result[2];
const buyPrice = result[3];
const sellPrice = result[4];
const returnPrice = result[5];
const rawBuyPrice = result[6];
const rawSellPrice = result[7];
const rawReturnPrice = result[8];
const buyFirst = result[9];
if (totalMarginRate > this._getMinMargin()) {
console.log(`发现利差:${totalMarginRate},buyDepth:${buyDepth},sellDepth${sellDepth},returnDepth${returnDepth}`);
return [baseCurrency1, midCurrency, baseCurrency2, totalMarginRate, buyPrice, sellPrice, returnPrice, amount, returnAmount, rawBuyPrice, rawSellPrice, rawReturnPrice, buyFirst];
}
}
}
}
return finalResult;
}
_getTotalAmount(fromCurrency,toCurrency,depth){
let amount =0;
let currency;
for(let i=1;i<=depth;i++){
const result = this.collector.getAmount(fromCurrency,toCurrency,i);
amount += parseFloat(result[0]);
currency = result[1];
}
return [amount,currency];
}
/**
* 用于控制是否把当前允许的最大的通量全吃掉
* @returns {number}
*/
_getAmountRatio(baseCurrency1,midCurrency,baseCurrency2){
return 1;
}
calculateBestSolution(baseCurrency1, midCurrency, baseCurrency2,buyDepth=1,sellDepth=1,returnDepth=1) {
let bestProfit = -1;
let bestAmount = 0;
let bestReturnAmount = 0;
let bestTotalMarginRate = 0;
const buyFeeRate = this.collector.getFeeRate(baseCurrency1, midCurrency);
const sellFeeRate = this.collector.getFeeRate(midCurrency, baseCurrency2);
const returnFeeRate = this.collector.getFeeRate(baseCurrency2, baseCurrency1);
let bestBuyPrice = 0;
let bestSellPrice = 0;
let bestReturnPrice = 0;
let bestRawBuyPrice = 0;
let bestRawSellPrice = 0;
let bestRawReturnPrice = 0;
const buyPrice = 1.0 / this.collector.getPrice(baseCurrency1, midCurrency, buyDepth);
const sellPrice = this.collector.getPrice(midCurrency, baseCurrency2, sellDepth);
const returnPrice = 1.0 / this.collector.getPrice(baseCurrency2, baseCurrency1, returnDepth);
if (buyPrice < 0 || sellPrice < 0 || returnPrice < 0)
return [0, 0, -2, 0, 0, 0, 0, 0, 0];
// const buyAmount = this.collector.getAmount(baseCurrency1, midCurrency, buyDepth)[0];
const buyAmount = this._getTotalAmount(baseCurrency1,midCurrency,buyDepth)[0];
// const sellAmount = this.collector.getAmount(midCurrency, baseCurrency2, sellDepth)[0];
const sellAmount = this._getTotalAmount(midCurrency,baseCurrency2,sellDepth)[0];
const returnResult = this._getTotalAmount(baseCurrency2, baseCurrency1, returnDepth);
const returnAmount = Math.min(returnResult[0], this.collector.getCurrencyMaxReturnAmount(returnResult[1]));
const returnAmountCurrency = returnResult[1];
let calculatedByReturnAmount = (returnAmountCurrency === baseCurrency2 ? (returnAmount / sellPrice) : (returnAmount / buyPrice));
if(!this._isFeeDeducedByOther()){
//手续费不是由平台币抵扣的情况回归通量计算要考虑手续费
calculatedByReturnAmount = returnAmountCurrency === baseCurrency2 ? (returnAmount / (sellPrice*(1-sellFeeRate))) : (returnAmount / (buyPrice*(1+buyFeeRate)));
}
let amount = Math.min(buyAmount, sellAmount, calculatedByReturnAmount) * this._getAmountRatio(baseCurrency1,midCurrency,baseCurrency2);
const m1 = 1.0 / (buyPrice * (1.0 + buyFeeRate));
const m2 = m1 * sellPrice * (1.0 - sellFeeRate);
const m3 = m2 / returnPrice * (1.0 - returnFeeRate);
const totalMarginRate = (m3 - 1.0) * 100.0;
if (totalMarginRate > 0) {
const buyAmount = this.collector.processAmount(midCurrency, baseCurrency1, amount);
const sellAmount = this.collector.processAmount(midCurrency, baseCurrency2, amount);
amount = buyAmount.length > sellAmount.length ? sellAmount : buyAmount;
const profit = totalMarginRate * amount;
let return_amount = 0;
if(this._isFeeDeducedByOther()){
return_amount = returnAmountCurrency === baseCurrency2 ? amount * sellPrice : amount * buyPrice;
}else{
return_amount = returnAmountCurrency === baseCurrency2 ? amount * sellPrice * (1-sellFeeRate) : amount * buyPrice * (1+sellFeeRate);
}
return_amount = this.collector.processAmount(baseCurrency2, baseCurrency1, return_amount);
if (profit > 0 && profit > bestProfit && return_amount > this._getMinReturnAmount(returnAmountCurrency)) {
if(this._giveUpOrder(baseCurrency1,midCurrency,baseCurrency2,totalMarginRate,buyDepth,sellDepth)){
return [0, 0, -3, 0, 0, 0, 0, 0, 0];
}
bestReturnAmount = return_amount;
bestProfit = profit;
bestAmount = amount;
bestTotalMarginRate = totalMarginRate;
// bestBuyPrice = this.collector.processPrice(baseCurrency1, midCurrency, buyPrice);
// bestSellPrice = this.collector.processPrice(midCurrency, baseCurrency2, sellPrice);
// bestReturnPrice = this.collector.processPrice(baseCurrency2, baseCurrency1, returnPrice);
bestBuyPrice = buyPrice;
bestSellPrice = sellPrice;
bestReturnPrice = returnPrice;
bestRawBuyPrice = this.collector.getPrice(baseCurrency1, midCurrency, buyDepth, true);
bestRawSellPrice = this.collector.getPrice(midCurrency, baseCurrency2, sellDepth, true);
bestRawReturnPrice = this.collector.getPrice(baseCurrency2, baseCurrency1, returnDepth, true);
const result = this._adjustPrice(bestRawBuyPrice,bestRawSellPrice,bestRawReturnPrice,
this.collector.getTradeSide(baseCurrency2,baseCurrency1),bestTotalMarginRate);
bestRawBuyPrice = result[0];
bestRawSellPrice = result[1];
bestRawReturnPrice = result[2];
bestRawBuyPrice = this.collector.processPrice(baseCurrency1, midCurrency, bestRawBuyPrice);
bestRawSellPrice = this.collector.processPrice(midCurrency, baseCurrency2, bestRawSellPrice);
bestRawReturnPrice = this.collector.processPrice(baseCurrency2, baseCurrency1, bestRawReturnPrice);
}
} else if (totalMarginRate < 0) {
return [0, 0, totalMarginRate, 0, 0, 0, 0, 0, 0];
}
return [bestAmount, bestReturnAmount, bestTotalMarginRate, bestBuyPrice, bestSellPrice, bestReturnPrice, bestRawBuyPrice, bestRawSellPrice, bestRawReturnPrice]
}
}
module.exports = Strategy3;
\ No newline at end of file
const WebSocket = require('ws');
const SocksProxyAgent = require('socks-proxy-agent');
const proxy = process.env.agent;
const agent = proxy ? new SocksProxyAgent(proxy) : null;
const zlib = require('zlib');
const BiboxCollector = require('./biboxCollector');
const biboxApi = require('./api');
const constants = require('./constants');
const Order = require('./order');
function testWs() {
this.ws = new WebSocket('wss://push.bibox.com/', {agent});
const wss = this.ws;
this.ws.on('open', () => {
console.log("成功启动collector");
wss.send(JSON.stringify({"event":"addChannel","channel":"bibox_sub_spot_BTC_USDT_depth","binary":0}));
});
this.ws.on('message', (data)=>{
// console.log(data);
const response = JSON.parse(data)[0];
const decodeStr = Buffer.from(response.data,'base64');
zlib.unzip(decodeStr,(result1,result2)=>{
console.log(result1);
console.log(result2.toString());
})
});
this.ws.on('error', (error) => {
console.log("collector websocket error:");
console.log(error);
})
this.ws.on('close', () => {
console.log("websocket closed");
})
}
// testWs();
function testCollector(){
const collector = new BiboxCollector(null);
collector.runStrategy3();
}
// testCollector();
function printCurrency(){
const currentArray = [,'ETH','BTC','LTC','BCH','USDT','USD','RMB',"RCN","WINGS","TRX","LEND","CMT","POWR","HSR","GAS","RDN","TNT","OAX"
,"ELF","GXS","ETC","FUN","ENG","LUN","BRD","ADA","RLC","SUB","REQ","SNT","SALT","QTUM","VIB","ARN","BCD","EOS"
,"AST","LRC","APPC","VIA","STEEM","LINK","XRP","ADX","XZC"
,"INS","STRAT","LTC","TRIG","GVT","CDT","ENJ","IOST","BNT","SNM","TNB","BTS","EDO","DNT","ICN","VIBE","RPX","ARK","NAV","DGD"
,"AION","CTR","OST","VEN","BLZ","MOD","XMR","NULS","NCASH","BNB","XVG","MCO"
,"IOTA","AE","OMG","WTC","NEBL","BCPT","DLT","ZRX","PIVX","CND","BCC","XLM","BAT"
,"FUEL","GTO","YOYO","SNGLS","ICX","STORJ","QSP"
,"BQX","PPT","MANA","MDA","MTL","WABI","DASH","WAVES","ZEC","KNC","NANO","EVX","CHAT","LSK","BTG"
,"NEO","POE","MTH","AMB","KMD","POA","ONT","ZIL","STORM","BCN","DOGE","DSH","EMC"
,"FCN","NXT","QCN","SBD","SC","XDN","XEM","ARDR","MAID","AMP","BUS","1ST","TRST","TIME","GNO"
,"REP","ZRC","BOS","DCT","ANT","AEON","GUP","PLU","TAAS","NXC","EDG","SWT","TKN","XAUR","PTOY","CFI"
,"PLBT","XDNCO","FYN","CVC","PAY","XTZ","DICE","NET","SNC","BET","DENT","SAN","MNE"
,"MSP","DDF","UET","MYB","SUR","IXT","PLR","TIX","NDC","PRO","AVT","COSS","QAU","FYP","OPT","STX","CAT","XUC","BAS","RVT","ICOS","PPC","VERI"
,"IGNIS","PRG","BMC","SKIN","EMGO","HVN","MCAP","AIR","NTO","ICO","PING"
,"RKC","GAME","TKR","HPC","WMGO","CSNO","ORME","PIX","IND","KICK","YOYOW","MIPS","DGB","DCN","LAT","CCT","EBET","VOISE","ZSC"
,"ETBS","ART","QVT", "EBTCOLD","BKB","EXN","TGT","ATS","BMT","CNX","ATB","ODN"
,"BTM","B2X","ATM","LIFE","DRT","STU","SMART","CL","LA","CLD"
,"ELM","HGT","POLL","SCL","ATL","EBTC","ETP","OTX","CDX","DRPU","HAC","CTX","ELE","SISA"
,"INDI","BTX","ITS","AMM","DBIX","PRE","KBR","TBT","ERO","SMS","ZAP","DOV","FRD","OTN","SPF"
,"SBTC","BTCA","WRC","LOC","SWFTC","STAR","DIM","NGC","ECH","CPAY","DATA"
,"UTT","EKO","TIO","WAX","ULTC","EET","C20","IDH","IPL","COV","SENT","SMT","W3C","CAS"
,"GRMD","AVH","TRAC","JNT","PCL","CLOUT","UTK","GNX","CHSB","NEU","TAU","MEK","BAR","FLP","R","PKT","WLK","EVN","CPG","BPTN","BETR"
,"ARCT","DBET","RNTB","HAND","BEZ","ACO","CTE","UTNP"
,"CPY","CHP","ACT","HIRE","SIG","RPM","MTX","BGG","SETH","WIZ","DADI","BDG","DATX","TRUE","DRG","BANCA","AUTO","NOAH","SOC","WILD"
,"INSUR","OCN","STQ","CVH","IFT","CGC","WAN","QLC","SYS","WPR","GRS","CLOAK","GNT","LOOM","BCN","BIFI","DBC","SRN","TOPC"
,"MDS","DAT","MEET","BCX","HT","PROPY","LET","EDU","ELA"
,"QUN","CTXC","ABT","AIDOC","THETA","ZLA","NAS","YEE","STK","QASH","RUFF"
,"MTN","DTA","BFT","ITC","WICC","REP","TUSD","ZEN","SKY","IOTX","QKC","AGI","NXS","ZB","QC"
,'UBTC','INK','TV','BTH','LBTC','HLC','BCW','BTP'
,'BITCNY','ENT','SAFE','BTN','CDC','DDM','BITE','HOTC'
,'EPC','BDS','GRAM','HPY','MITH','EOSDAC','KAN',"NPXS","SUNC"
,"ADH","AXP","BERRY","BSTN","DAXT","BMH","BUBO"
,"CAPP","DAY","CLR","WEALTH","CRPT","CVT","DAN","XDNICCO"
,"ERT","FOTA","WTT","GBX","HRB","HDG","HLW","HQX"
,"IHT","IML","MPK","KIN","LDC","XLC","LNC","MRV","MESH","MLD","XMO","NCT"
,"PQT","PBKX","PREMINE","ROOTS","GRPH","SHIP","CRS","SCC"
,"TEL","8BT","TFL","UGT","UNC","VIT","YCC","BBC","GET","TKY","ACAT","TCN","VIO","WIKI"
,"CVCOIN","FTX","FREC","NAVI","VME","BTCP"
,"LND","CSM","NANJ","MTC","NTK","AUC","CMCT"
,"MAN","TKA","PNT","FXT","NEXO","CHX","PAT","XMC"
,"EJOY","TBAR","HERO","STAK","FDZ","SPD","LUC","MITX"
,"TIV","B2G","LATX","ZPT","HBZ","FACE","MORPH","EBKC","CPT","WITH"
,"HTML","JOT","JBC","BNK","CBC","COIN","PMNT","ABYSS","BCI"
,"PITCH","TDS","DPN","UUU","KBC","BTV","XBP","CLN"
,"IVY","TTU","DOR","SPC","KEY",'OKB',"MFT",
,'AAC','ACE','BEC','BKX','CAG','CAI','CAN','CBT','CIC','DCR','DNA','DPY','EGT', 'FAIR','GSC','GTC'
,'HMC','HOT','INT','IPC','KCASH','LBA','LEV','LIGHT','MAG'
,'MDT','MKR','MOF','MOT','MVP','OF','OK06ETT','ORS','PRA','PST','RCT', 'READ','REF','REN','RFR','RNT', 'SHOW','SSC','STC','TCT','TRA'
, 'TRIO','UCT','UGC','UKG','VEE','VIU', 'WFEE','WIN','XAS','YOU'
,'ZIP','HPB','CIT','HYC','SDA','TESTA','TESTB','TESTC'
,'BT2', 'KRM', 'LCC', 'ELEC', 'QNTU','CENNZ', 'SWM', 'CLO', 'MXM', 'DAI', 'DWS', 'PROC', 'BIT', 'REX', 'COSM', 'DCNT', 'EURS', 'MNX', 'WBTC'
,'ZCO','BIX','BTO','SNOV','BLT','SXUT','CZR','TNC','CPC','FSN','BBN','MED','DXT','LGO','NPER','IPSX','BOT','MT'
,'LKN','INSTAR','RED','PAI','CWV','BCV','HDAC','BOE','AT','UPP','SGC','HER','DCC','RTE','TTC','CAR','BZNT','BU'
,'AC3','TTT','XNK'];
const api = new biboxApi('','');
api.fetchSymbols((error,data)=>{
if (!error) {
const unknowCurrencies = [];
for (let detail of data.result) {
const symbol = detail.pair;
const currencies = symbol.split("_");
const midCurrency = currencies[0].toUpperCase();
const baseCurrency = currencies[1].toUpperCase();
if (!currentArray.includes(midCurrency) && !unknowCurrencies.includes(midCurrency)) {
console.log(`CNY_${midCurrency} = '${midCurrency}'`);
unknowCurrencies.push(midCurrency)
// console.log(`(CNY_${midCurrency}, CNY_${midCurrency})`);
}
if (!currentArray.includes(baseCurrency) && !unknowCurrencies.includes(baseCurrency)) {
console.log(`CNY_${baseCurrency} = '${baseCurrency}'`);
unknowCurrencies.push(baseCurrency);
// console.log(`(CNY_${baseCurrency}, CNY_${baseCurrency})`);
}
}
console.log("========================")
unknowCurrencies.map((item) => console.log(`(CNY_${item}, CNY_${item}),`))
}
})
}
printCurrency()
function testOrder(){
const order = new Order();
// order.order("BTC_USDT","0.01","0.01",constants.OrderSideBuy,(error,result)=>{
// console.log(error);
// console.log(result);
// })
// api.balance((error,data)=>{
// console.log(error);
// console.log(data);
// })
// api.getTrades("BTC_USDT",(error,data)=>{
// console.log(error);
// console.log(data);
// })
const api = new biboxApi();
// api.fetchHistorOrders(1,20,"BU_ETH",constants.OrderSideSell,(error,result)=>{
// console.log(error);
// console.log(result);
// })
api.searchOrder('873502366',(error,result)=>{
console.log(result);
})
}
// testOrder();
\ No newline at end of file
const WebSocket = require('ws');
const SocksProxyAgent = require('socks-proxy-agent');
const proxy = process.env.agent;
const agent = proxy ? new SocksProxyAgent(proxy) : null;
const zlib = require('zlib');
const BiboxCollector = require('./lbankCollector');
const biboxApi = require('./api_lbank');
const constants = require('./constants');
const Order = require('./order');
function testWs() {
this.ws = new WebSocket('wss://api.lbkex.com/ws/V2/', {agent});
const wss = this.ws;
this.ws.on('open', () => {
console.log("成功启动collector");
wss.send(JSON.stringify({"action":"subscribe","subscribe":"depth","depth":10,"pair": "dx_eth"}));
});
this.ws.on('message', (data)=>{
console.log(data);
});
this.ws.on('error', (error) => {
console.log("collector websocket error:");
console.log(error);
})
this.ws.on('close', () => {
console.log("websocket closed");
})
}
// testWs();
function testCollector(){
const collector = new BiboxCollector(null);
collector.runStrategy3();
}
// testCollector();
function printCurrency(){
const currentArray = [,'ETH','BTC','LTC','BCH','USDT','USD','RMB',"RCN","WINGS","TRX","LEND","CMT","POWR","HSR","GAS","RDN","TNT","OAX"
,"ELF","GXS","ETC","FUN","ENG","LUN","BRD","ADA","RLC","SUB","REQ","SNT","SALT","QTUM","VIB","ARN","BCD","EOS"
,"AST","LRC","APPC","VIA","STEEM","LINK","XRP","ADX","XZC"
,"INS","STRAT","LTC","TRIG","GVT","CDT","ENJ","IOST","BNT","SNM","TNB","BTS","EDO","DNT","ICN","VIBE","RPX","ARK","NAV","DGD"
,"AION","CTR","OST","VEN","BLZ","MOD","XMR","NULS","NCASH","BNB","XVG","MCO"
,"IOTA","AE","OMG","WTC","NEBL","BCPT","DLT","ZRX","PIVX","CND","BCC","XLM","BAT"
,"FUEL","GTO","YOYO","SNGLS","ICX","STORJ","QSP"
,"BQX","PPT","MANA","MDA","MTL","WABI","DASH","WAVES","ZEC","KNC","NANO","EVX","CHAT","LSK","BTG"
,"NEO","POE","MTH","AMB","KMD","POA","ONT","ZIL","STORM","BCN","DOGE","DSH","EMC"
,"FCN","NXT","QCN","SBD","SC","XDN","XEM","ARDR","MAID","AMP","BUS","1ST","TRST","TIME","GNO"
,"REP","ZRC","BOS","DCT","ANT","AEON","GUP","PLU","TAAS","NXC","EDG","SWT","TKN","XAUR","PTOY","CFI"
,"PLBT","XDNCO","FYN","CVC","PAY","XTZ","DICE","NET","SNC","BET","DENT","SAN","MNE"
,"MSP","DDF","UET","MYB","SUR","IXT","PLR","TIX","NDC","PRO","AVT","COSS","QAU","FYP","OPT","STX","CAT","XUC","BAS","RVT","ICOS","PPC","VERI"
,"IGNIS","PRG","BMC","SKIN","EMGO","HVN","MCAP","AIR","NTO","ICO","PING"
,"RKC","GAME","TKR","HPC","WMGO","CSNO","ORME","PIX","IND","KICK","YOYOW","MIPS","DGB","DCN","LAT","CCT","EBET","VOISE","ZSC"
,"ETBS","ART","QVT", "EBTCOLD","BKB","EXN","TGT","ATS","BMT","CNX","ATB","ODN"
,"BTM","B2X","ATM","LIFE","DRT","STU","SMART","CL","LA","CLD"
,"ELM","HGT","POLL","SCL","ATL","EBTC","ETP","OTX","CDX","DRPU","HAC","CTX","ELE","SISA"
,"INDI","BTX","ITS","AMM","DBIX","PRE","KBR","TBT","ERO","SMS","ZAP","DOV","FRD","OTN","SPF"
,"SBTC","BTCA","WRC","LOC","SWFTC","STAR","DIM","NGC","ECH","CPAY","DATA"
,"UTT","EKO","TIO","WAX","ULTC","EET","C20","IDH","IPL","COV","SENT","SMT","W3C","CAS"
,"GRMD","AVH","TRAC","JNT","PCL","CLOUT","UTK","GNX","CHSB","NEU","TAU","MEK","BAR","FLP","R","PKT","WLK","EVN","CPG","BPTN","BETR"
,"ARCT","DBET","RNTB","HAND","BEZ","ACO","CTE","UTNP"
,"CPY","CHP","ACT","HIRE","SIG","RPM","MTX","BGG","SETH","WIZ","DADI","BDG","DATX","TRUE","DRG","BANCA","AUTO","NOAH","SOC","WILD"
,"INSUR","OCN","STQ","CVH","IFT","CGC","WAN","QLC","SYS","WPR","GRS","CLOAK","GNT","LOOM","BCN","BIFI","DBC","SRN","TOPC"
,"MDS","DAT","MEET","BCX","HT","PROPY","LET","EDU","ELA"
,"QUN","CTXC","ABT","AIDOC","THETA","ZLA","NAS","YEE","STK","QASH","RUFF"
,"MTN","DTA","BFT","ITC","WICC","REP","TUSD","ZEN","SKY","IOTX","QKC","AGI","NXS","ZB","QC"
,'UBTC','INK','TV','BTH','LBTC','HLC','BCW','BTP'
,'BITCNY','ENT','SAFE','BTN','CDC','DDM','BITE','HOTC'
,'EPC','BDS','GRAM','HPY','MITH','EOSDAC','KAN',"NPXS","SUNC"
,"ADH","AXP","BERRY","BSTN","DAXT","BMH","BUBO"
,"CAPP","DAY","CLR","WEALTH","CRPT","CVT","DAN","XDNICCO"
,"ERT","FOTA","WTT","GBX","HRB","HDG","HLW","HQX"
,"IHT","IML","MPK","KIN","LDC","XLC","LNC","MRV","MESH","MLD","XMO","NCT"
,"PQT","PBKX","PREMINE","ROOTS","GRPH","SHIP","CRS","SCC"
,"TEL","8BT","TFL","UGT","UNC","VIT","YCC","BBC","GET","TKY","ACAT","TCN","VIO","WIKI"
,"CVCOIN","FTX","FREC","NAVI","VME","BTCP"
,"LND","CSM","NANJ","MTC","NTK","AUC","CMCT"
,"MAN","TKA","PNT","FXT","NEXO","CHX","PAT","XMC"
,"EJOY","TBAR","HERO","STAK","FDZ","SPD","LUC","MITX"
,"TIV","B2G","LATX","ZPT","HBZ","FACE","MORPH","EBKC","CPT","WITH"
,"HTML","JOT","JBC","BNK","CBC","COIN","PMNT","ABYSS","BCI"
,"PITCH","TDS","DPN","UUU","KBC","BTV","XBP","CLN"
,"IVY","TTU","DOR","SPC","KEY",'OKB',"MFT",
,'AAC','ACE','BEC','BKX','CAG','CAI','CAN','CBT','CIC','DCR','DNA','DPY','EGT', 'FAIR','GSC','GTC'
,'HMC','HOT','INT','IPC','KCASH','LBA','LEV','LIGHT','MAG'
,'MDT','MKR','MOF','MOT','MVP','OF','OK06ETT','ORS','PRA','PST','RCT', 'READ','REF','REN','RFR','RNT', 'SHOW','SSC','STC','TCT','TRA'
, 'TRIO','UCT','UGC','UKG','VEE','VIU', 'WFEE','WIN','XAS','YOU'
,'ZIP','HPB','CIT','HYC','SDA','TESTA','TESTB','TESTC'
,'BT2', 'KRM', 'LCC', 'ELEC', 'QNTU','CENNZ', 'SWM', 'CLO', 'MXM', 'DAI', 'DWS', 'PROC', 'BIT', 'REX', 'COSM', 'DCNT', 'EURS', 'MNX', 'WBTC'
,'ZCO','BIX','BTO','SNOV','BLT','SXUT','CZR','TNC','CPC','FSN','BBN','MED','DXT','LGO','NPER','IPSX','BOT','MT'
,'LKN','INSTAR','RED','PAI','CWV','BCV','HDAC','BOE','AT','UPP','SGC','HER','DCC','RTE','TTC','CAR','BZNT','BU'
,'AC3','TTT','XNK'];
const api = new biboxApi('','');
api.fetchSymbols((error,data)=>{
if (!error) {
const unknowCurrencies = [];
for (let detail of data.result) {
const symbol = detail.pair;
const currencies = symbol.split("_");
const midCurrency = currencies[0].toUpperCase();
const baseCurrency = currencies[1].toUpperCase();
if (!currentArray.includes(midCurrency) && !unknowCurrencies.includes(midCurrency)) {
console.log(`CNY_${midCurrency} = '${midCurrency}'`);
unknowCurrencies.push(midCurrency)
// console.log(`(CNY_${midCurrency}, CNY_${midCurrency})`);
}
if (!currentArray.includes(baseCurrency) && !unknowCurrencies.includes(baseCurrency)) {
console.log(`CNY_${baseCurrency} = '${baseCurrency}'`);
unknowCurrencies.push(baseCurrency);
// console.log(`(CNY_${baseCurrency}, CNY_${baseCurrency})`);
}
}
console.log("========================")
unknowCurrencies.map((item) => console.log(`(CNY_${item}, CNY_${item}),`))
}
})
}
// printCurrency()
function testOrder(){
const order = new Order();
// order.order("BTC_USDT","0.01","0.01",constants.OrderSideBuy,(error,result)=>{
// console.log(error);
// console.log(result);
// })
// api.balance((error,data)=>{
// console.log(error);
// console.log(data);
// })
// api.getTrades("BTC_USDT",(error,data)=>{
// console.log(error);
// console.log(data);
// })
const api = new biboxApi();
// api.fetchHistorOrders(1,20,"BU_ETH",constants.OrderSideSell,(error,result)=>{
// console.log(error);
// console.log(result);
// })
api.searchOrder('873502366',(error,result)=>{
console.log(result);
})
}
// testOrder();
function testAPI() {
const api = new biboxApi();
// api.fetchSymbols((error,result)=>{
// console.log(error);
// console.log(result);
// })
api.balance((error,result)=>{
console.log(error);
console.log(result);
})
}
testAPI();
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment