Market improvements

-All external market apis have been normalized with a similar coding format, improved error handling with new wait times in between api calls to prevent abuse issues with sending too many requests too quickly
-All general market code has been reviewed and improved where necessary to help prevent sync issues
-Inactive markets are now removed from the markets collection on startup of the explorer to help prevent bloating the database
-The yobit api url has been changed to the new url
-The poloniex market has been updated to use the newest api
-The southxchange exchange trading link has been changed to the new url
-Miscellaneous locale string changes and reorganization
This commit is contained in:
Joe Uhren
2023-10-27 18:33:52 -06:00
parent 83d7f4b182
commit 74ca66d44e
13 changed files with 1279 additions and 929 deletions
+3 -3
View File
@@ -780,7 +780,7 @@ if (settings.markets_page.enabled == true) {
} else if (!ex[ex_name].enabled) {
// exchange is not enabled
ex_error = 'Default exchange is disabled in settings' + ': ' + ex_name;
} else if (ex[ex_name].trading_pairs.findIndex(p => p.toLowerCase() == ex_pair.toLowerCase()) == -1) {
} else if (ex[ex_name].trading_pairs.findIndex(p => p.toUpperCase() == ex_pair.toUpperCase()) == -1) {
// invalid default exchange trading pair
ex_error = 'Default exchange trading pair is not valid' + ': ' + ex_pair;
}
@@ -808,10 +808,10 @@ if (settings.markets_page.enabled == true) {
settings.markets_page.enabled = false;
} else {
// a valid and enabled market was found to replace the default
console.log('WARNING: ' + ex_error + '. ' + 'Default exchange will be set to' + ': ' + ex_keys[new_default_index] + ' (' + ex[ex_keys[new_default_index]].trading_pairs[0] + ')');
console.log('WARNING: ' + ex_error + '. ' + 'Default exchange will be set to' + ': ' + ex_keys[new_default_index] + '[' + ex[ex_keys[new_default_index]].trading_pairs[0].toUpperCase() + ']');
// set new default exchange data
settings.markets_page.default_exchange.exchange_name = ex_keys[new_default_index];
settings.markets_page.default_exchange.trading_pair = ex[ex_keys[new_default_index]].trading_pairs[0];
settings.markets_page.default_exchange.trading_pair = ex[ex_keys[new_default_index]].trading_pairs[0].toUpperCase();
}
}
}
+109 -51
View File
@@ -131,7 +131,7 @@ function get_market_data(market, coin_symbol, pair_symbol, cb) {
if (fs.existsSync('./lib/markets/' + market + '.js')) {
exMarket = require('./markets/' + market);
exMarket.get_data({coin: coin_symbol, exchange: pair_symbol}, function(err, obj) {
exMarket.get_data({coin: coin_symbol, exchange: pair_symbol, api_error_msg: locale.mkt_unexpected_api_data}, function(err, obj) {
return cb(err, obj);
});
} else
@@ -214,9 +214,11 @@ function hex_to_ascii(hex) {
}
function init_markets(cb) {
let installed_markets = [];
// check if markets/exchanges feature is enabled
if (settings.markets_page.enabled == true) {
var marketCounter = 0;
let marketCounter = 0;
// loop through and test all exchanges defined in the settings.json file
Object.keys(settings.markets_page.exchanges).forEach(function (key, index, map) {
@@ -224,20 +226,29 @@ function init_markets(cb) {
if (settings.markets_page.exchanges[key].enabled == true) {
// check if exchange is installed/supported
if (module.exports.fs.existsSync('./lib/markets/' + key + '.js')) {
var pairCounter = 0;
let pairCounter = 0;
// loop through all trading pairs
settings.markets_page.exchanges[key].trading_pairs.forEach(function (pair_key, pair_index, pair_map) {
// split the pair data
var split_pair = pair_key.split('/');
let split_pair = pair_key.toUpperCase().split('/');
// check if this is a valid trading pair
if (split_pair.length == 2) {
// add this pair to the list of installed markets
installed_markets.push({
market: key,
coin_symbol: split_pair[0],
pair_symbol: split_pair[1]
});
// lookup the exchange in the market collection
module.exports.check_market(key, split_pair[0], split_pair[1], function(market, exists) {
// check if exchange trading pair exists in the market collection
if (!exists) {
// exchange doesn't exist in the market collection so add a default definition now
console.log('No %s: %s entry found. Creating new entry now..', market, pair_key);
console.log('No %s[%s] entry found. Creating new entry now..', market, split_pair[0] + '/' + split_pair[1]);
module.exports.create_market(split_pair[0], split_pair[1], market, function() {
pairCounter++;
@@ -248,7 +259,7 @@ function init_markets(cb) {
// check if all exchanges have been tested
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
// finished initializing markets
return cb();
return cb(installed_markets);
}
});
} else {
@@ -262,7 +273,7 @@ function init_markets(cb) {
// check if all exchanges have been tested
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
// finished initializing markets
return cb();
return cb(installed_markets);
}
});
} else {
@@ -282,10 +293,47 @@ function init_markets(cb) {
// check if all exchanges have been tested
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
// finished initializing markets
return cb();
return cb(installed_markets);
}
} else
return cb(installed_markets);
}
function remove_inactive_markets(installed_markets, cb) {
// lookup the list of markets in the database collection
Markets.find({}).then((db_markets) => {
// check if the database has any markets installed
if (db_markets != null && db_markets.length > 0) {
// loop through the list of markets in the database
lib.syncLoop(db_markets.length, function(market_loop) {
let m = market_loop.iteration();
// check if this market is installed
if (installed_markets.findIndex(x => x.market.toUpperCase() == db_markets[m].market.toUpperCase() && x.coin_symbol.toUpperCase() == db_markets[m].coin_symbol.toUpperCase() && x.pair_symbol.toUpperCase() == db_markets[m].pair_symbol.toUpperCase()) == -1) {
// remove this market from the database because it is not installed or active
Markets.deleteOne({market: db_markets[m].market, coin_symbol: db_markets[m].coin_symbol, pair_symbol: db_markets[m].pair_symbol}).then(() => {
// move to the next market record
market_loop.next();
}).catch((err) => {
console.log(err);
// move to the next market record
market_loop.next();
});
} else {
// move to the next market record
market_loop.next();
}
}, function() {
// finished removing inactive markets
return cb();
});
} else
return cb();
}).catch((err) => {
console.log(err);
return cb();
});
}
function init_heavy(cb) {
@@ -945,7 +993,7 @@ module.exports = {
});
newMarkets.save().then(() => {
console.log("Initial market entry created for %s: %s", market, coin_symbol +'/' + pair_symbol);
console.log("Initial market entry created for %s[%s]", market, coin_symbol + '/' + pair_symbol);
return cb();
}).catch((err) => {
console.log(err);
@@ -1308,30 +1356,37 @@ module.exports = {
// check if the default market pair is found in the coin list
if (index > -1) {
// get the usd value of the default market pair from coingecko
coingecko.get_data(coin_list[index].id, function (err, last_usd) {
// check for errors
if (err == null) {
// get current stats
Stats.findOne({coin: settings.coin.name}).then((stats) => {
// update the last usd price
Stats.updateOne({coin: settings.coin.name}, {
last_usd_price: (last_usd * stats.last_price)
}).then(() => {
// last usd price updated successfully
return cb(null);
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
var rateLimitLib = require('./ratelimit');
var rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
// automatically pause for 2 seconds in between requests
rateLimit.schedule(function() {
// get the usd value of the default market pair from coingecko
coingecko.get_data(coin_list[index].id, function (err, last_usd) {
// check for errors
if (err == null) {
// get current stats
Stats.findOne({coin: settings.coin.name}).then((stats) => {
// update the last usd price
Stats.updateOne({coin: settings.coin.name}, {
last_usd_price: (last_usd * stats.last_price)
}).then(() => {
// last usd price updated successfully
return cb(null);
}).catch((err) => {
// return error msg
return cb(err);
});
}).catch((err) => {
// return error msg
return cb(err);
});
}).catch((err) => {
} else {
// return error msg
return cb(err);
});
} else {
// return error msg
return cb(err);
}
}
});
});
} else {
// return error msg
@@ -1778,32 +1833,35 @@ module.exports = {
// initialize the stats collection
module.exports.create_stats(settings.coin.name, skip, function() {
// check and initialize the markets collection
init_markets(function() {
// add new field(s) to tx collection if missing
module.exports.check_txes(function(txes_exists) {
// add new field(s) to masternode collection if missing
module.exports.check_masternodes(function(masternodes_exists) {
// add new field(s) and/or rename old field(s) in networkhistory collection if applicable
module.exports.check_networkhistory(function(networkhistory_exists) {
// check if richlist collection is initialized
module.exports.check_richlist(settings.coin.name, function(richlist_exists) {
skip = true;
init_markets(function(installed_markets) {
// remove inactive markets from the database collection
remove_inactive_markets(installed_markets, function() {
// add new field(s) to tx collection if missing
module.exports.check_txes(function(txes_exists) {
// add new field(s) to masternode collection if missing
module.exports.check_masternodes(function(masternodes_exists) {
// add new field(s) and/or rename old field(s) in networkhistory collection if applicable
module.exports.check_networkhistory(function(networkhistory_exists) {
// check if richlist collection is initialized
module.exports.check_richlist(settings.coin.name, function(richlist_exists) {
skip = true;
// determine if richlist collection already exists
if (richlist_exists == false) {
console.log('No richlist entry found. Creating new entry now..');
skip = false;
}
// determine if richlist collection already exists
if (richlist_exists == false) {
console.log('No richlist entry found. Creating new entry now..');
skip = false;
}
// initialize the richlist collection
module.exports.create_richlist(settings.coin.name, skip, function() {
// check and initialize the heavycoin collection
init_heavy(function() {
// check and initialize the claimaddress collection
init_claimaddress(settings.coin.name, function() {
// finished initializing startup data
console.log('Database initialization complete');
return cb();
// initialize the richlist collection
module.exports.create_richlist(settings.coin.name, skip, function() {
// check and initialize the heavycoin collection
init_heavy(function() {
// check and initialize the claimaddress collection
init_claimaddress(settings.coin.name, function() {
// finished initializing startup data
console.log('Database initialization complete');
return cb();
});
});
});
});
+65 -53
View File
@@ -7,53 +7,7 @@ var fs = require("fs");
var jsonminify = require("jsonminify");
var settings = require("./settings");
exports.menu_explorer = "Explorer",
exports.menu_api = "API",
exports.menu_markets = "Markets",
exports.menu_richlist = "Rich List",
exports.menu_reward = "Reward",
exports.menu_movement = "Movement",
exports.menu_node = "Nodes",
exports.menu_network = "Network",
exports.menu_claim_address = "Claim Address",
exports.menu_orphans = "Orphaned Blocks",
exports.ex_title = "{1} Block Explorer",
exports.ex_description = "A listing of all verified {1} transactions",
exports.ex_search_title = "Search",
exports.ex_search_button = "Search",
exports.ex_search_message = "Search by block height, block hash, tx hash or address",
exports.ex_error = "Error!",
exports.ex_warning = "Warning",
exports.ex_search_error = "Search found no results.",
exports.ex_latest_transactions = "Latest Transactions",
exports.ex_summary = "Block Summary",
exports.ex_supply = "Coin Supply",
exports.ex_block = "Block",
exports.tx_title = "{1} Transaction Details",
exports.tx_description = "Viewing tx data from {1} block # {2}",
exports.tx_block_hash = "Block Hash",
exports.tx_recipients = "Recipients",
exports.tx_contributors = "Contributor(s)",
exports.tx_hash = "Tx Hash",
exports.tx_address = "Address",
exports.tx_nonstandard = "NONSTANDARD TX",
exports.view_raw_tx_data = "View Raw Transaction Data",
exports.view_block = "View Block",
exports.block_title = "{1} Block Details",
exports.block_description = "Viewing block data from {1} block # {2}",
exports.block_previous = "Previous Block",
exports.block_next = "Next Block",
exports.block_genesis = "GENESIS",
exports.view_raw_block_data = "View Raw Block Data",
exports.view_tx = "View Transaction",
exports.error_title = "{1} Block Explorer Error",
exports.error_description = "The page you are looking for cannot be found",
exports.error_description_alt = "An error occurred which prevented the page from loading correctly",
// global
exports.difficulty = "Difficulty",
exports.network = "Network",
exports.masternodecount = "Masternodes",
@@ -79,6 +33,59 @@ exports.unknown_recipient = "Unknown Recipient",
exports.last_updated = "Last Updated",
exports.initial_index_alert = "Blockchain data is currently being synchronized. You may browse the site during this time, but keep in mind that data may not yet be fully accurate and some functionality may not work until synchronization is complete.",
// menu items
exports.menu_explorer = "Explorer",
exports.menu_api = "API",
exports.menu_markets = "Markets",
exports.menu_richlist = "Rich List",
exports.menu_reward = "Reward",
exports.menu_movement = "Movement",
exports.menu_node = "Nodes",
exports.menu_network = "Network",
exports.menu_claim_address = "Claim Address",
exports.menu_orphans = "Orphaned Blocks",
// explorer view
exports.ex_title = "{1} Block Explorer",
exports.ex_description = "A listing of all verified {1} transactions",
exports.ex_search_title = "Search",
exports.ex_search_button = "Search",
exports.ex_search_message = "Search by block height, block hash, tx hash or address",
exports.ex_error = "Error",
exports.ex_warning = "Warning",
exports.ex_search_error = "Search found no results.",
exports.ex_latest_transactions = "Latest Transactions",
exports.ex_summary = "Block Summary",
exports.ex_supply = "Coin Supply",
exports.ex_block = "Block",
// transaction view
exports.tx_title = "{1} Transaction Details",
exports.tx_description = "Viewing tx data from {1} block # {2}",
exports.tx_block_hash = "Block Hash",
exports.tx_recipients = "Recipients",
exports.tx_contributors = "Contributor(s)",
exports.tx_hash = "Tx Hash",
exports.tx_address = "Address",
exports.tx_nonstandard = "NONSTANDARD TX",
exports.view_raw_tx_data = "View Raw Transaction Data",
exports.view_block = "View Block",
// block view
exports.block_title = "{1} Block Details",
exports.block_description = "Viewing block data from {1} block # {2}",
exports.block_previous = "Previous Block",
exports.block_next = "Next Block",
exports.block_genesis = "GENESIS",
exports.view_raw_block_data = "View Raw Block Data",
exports.view_tx = "View Transaction",
// error view
exports.error_title = "{1} Block Explorer Error",
exports.error_description = "The page you are looking for cannot be found",
exports.error_description_alt = "An error occurred which prevented the page from loading correctly",
// address view
exports.a_title = "{1} Wallet Address Details",
exports.a_description = "Viewing balance and transaction data from {1} address {2}",
exports.a_menu_showing = "Showing",
@@ -86,13 +93,16 @@ exports.a_menu_txs = "transactions",
exports.a_menu_all = "All",
exports.a_qr = "QR Code",
// masternode view
exports.mn_title = "{1} Masternodes",
exports.mn_description = "A listing of all masternodes known to be active on the {1} network",
exports.mn_masternode_list = "Masternode List",
// movement view
exports.move_title = "{1} Coin Movements",
exports.move_description = "A listing of larger movements where {1} or more {2} coins were sent in a single transaction",
// richlist view
exports.rl_title = "Top {1} Coin Holders",
exports.rl_description = "A listing of the richest {1} wallet addresses and breakdown of the current coin distribution",
exports.rl_received_coins = "Top 100 - Received Coins",
@@ -106,6 +116,7 @@ exports.rl_top75 = "Top 51-75",
exports.rl_top100 = "Top 76-100",
exports.rl_hundredplus = "101+",
// network view
exports.net_title = "{1} Network Peers",
exports.net_description = "A listing of {1} network peers that have connected to the explorer node in the last 24 hours",
exports.net_addnodes = "Add Nodes",
@@ -115,6 +126,7 @@ exports.net_protocol = "Protocol",
exports.net_subversion = "Sub-version",
exports.net_country = "Country",
// api view
exports.api_title = "{1} Public API",
exports.api_description = "A listing of public API endpoints for retrieving {1} coin data from the network without the need for a local wallet",
exports.api_documentation = "API Documentation",
@@ -138,7 +150,7 @@ exports.api_getsupply = 'Returns the current money supply.',
exports.api_getnextrewardestimate = 'Returns an estimate for the next block reward based on the current state of decentralized voting.',
exports.api_getnextrewardwhenstr = 'Returns a string describing how long until the votes are tallied and the next block reward is computed.',
// Markets view
// markets view
exports.mkt_title = "{1} Market Details",
exports.mkt_description = "Viewing {1} market data for the {2} exchange",
exports.mkt_hours = "24 hours",
@@ -162,12 +174,13 @@ exports.mkt_trade_history = "Trade History",
exports.mkt_type = "Type",
exports.mkt_time_stamp = "Time Stamp",
exports.mkt_select = "Market Select",
exports.mkt_unexpected_api_data = "Received unexpected API data response",
// Claim address view
// claim address view
exports.claim_title = "{1} Wallet Address Claim",
exports.claim_description = "Verify ownership of your {1} wallet address and set a custom display name in the explorer",
// Orphans view
// orphans view
exports.orphan_title = "{1} Orphaned Blocks",
exports.orphan_description = "A listing of valid blocks that have been orphaned and do not belong to the main blockchain",
exports.orphan_block_list = "Orphaned Block List",
@@ -177,12 +190,11 @@ exports.orphan_prev_block = "Previous Block",
exports.orphan_next_block = "Next Block",
exports.view_orphan = "View Orphaned Block",
// Heavycoin
exports.heavy_vote = "Vote",
// Heavycoin rewards view
// heavycoin rewards view
exports.heavy_title = "{1} Reward/Voting Details",
exports.heavy_description = "Viewing {1} voting data and coin reward change details",
exports.heavy_reward_voting_info = "Reward/voting information",
exports.heavy_vote = "Vote",
exports.heavy_cap = "Coin Cap",
exports.heavy_phase = "Phase",
exports.heavy_maxvote = "Max Vote",
+149 -126
View File
@@ -1,153 +1,165 @@
var request = require('postman-request');
var base_url = 'https://v2.altmarkets.io/api/v2/peatio/public/markets/';
var api_error_msg = 'api did not return any data';
const request = require('postman-request');
const base_url = 'https://v2.altmarkets.io/api/v2/peatio/public/markets/';
const market_url_template = 'https://v2.altmarkets.io/trading/{coin}{base}';
function get_summary(coin, exchange, cb) {
var req_url = base_url + coin.toLowerCase() + exchange.toLowerCase() + '/tickers';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else {
// check for null body as the apis do not work all the time for some reason
if (body != null) {
if (body.errors)
return cb(body.errors, null);
else {
req_url = base_url + coin.toLowerCase() + exchange.toLowerCase() + '/order-book?asks_limit=1&bids_limit=1';
request({uri: req_url, json: true}, function (error, response, order_body) {
if (error)
return cb(error, null);
function get_summary(coin, exchange, api_error_msg, cb) {
const ticker_url = base_url + coin + exchange + '/tickers';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: ticker_url, json: true}, function (tic_error, tic_response, tic_body) {
if (tic_error)
return cb(tic_error, null);
else if (tic_body == null || tic_body == '' || typeof tic_body !== 'object')
return cb(api_error_msg, null);
else if (tic_body.errors != null)
return cb(tic_body.errors, null);
else {
const order_url = base_url + coin + exchange + '/order-book?asks_limit=1&bids_limit=1';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: order_url, json: true}, function (order_error, order_response, order_body) {
if (order_error)
return cb(order_error, null);
else if (order_body == null || order_body == '' || typeof order_body !== 'object')
return cb(api_error_msg, null);
else if (order_body.errors != null)
return cb(order_body.errors, null);
else {
// check for null body as the apis do not work all the time for some reason
if (body != null) {
if (body.errors)
return cb(body.errors, null);
else {
var summary = {};
try {
const summary = {
'high': parseFloat(tic_body.ticker.high),
'low': parseFloat(tic_body.ticker.low),
'volume': parseFloat(tic_body.ticker.amount),
'volume_btc': parseFloat(tic_body.ticker.volume),
'bid': parseFloat(order_body != null && order_body.bids != null && order_body.bids.length > 0 ? order_body.bids[0].price : 0),
'ask': parseFloat(order_body != null && order_body.asks != null && order_body.asks.length > 0 ? order_body.asks[0].price : 0),
'last': parseFloat(tic_body.ticker.last),
'change': parseFloat(tic_body.ticker.price_change_percent.toString().replace('%', ''))
};
summary['bid'] = (order_body != null && order_body['bids'] != null && order_body['bids'].length > 0 ? order_body['bids'][0]['price'] : 0);
summary['ask'] = (order_body != null && order_body['asks'] != null && order_body['asks'].length > 0 ? order_body['asks'][0]['price'] : 0);
summary['volume'] = body['ticker']['amount'];
summary['volume_btc'] = body['ticker']['volume'];
summary['high'] = body['ticker']['high'];
summary['low'] = body['ticker']['low'];
summary['last'] = body['ticker']['last'];
summary['change'] = parseFloat(body['ticker']['price_change_percent'].replace('%', ''));
return cb(null, summary);
}
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
}
});
}
}
});
});
}
function get_trades(coin, exchange, cb) {
var req_url = base_url + coin.toLowerCase() + exchange.toLowerCase() + '/trades?limit=50&order_by=desc';
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + coin + exchange + '/trades?limit=50&order_by=desc';
request({uri: req_url, json: true}, function (error, response, body) {
// check for null body as the apis do not work all the time for some reason
if (body != null) {
if (body.errors != null)
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.errors != null)
return cb(body.errors, null);
else {
var trades = [];
try {
let trades = [];
if (body.length > 0) {
for (var i = 0; i < body.length; i++) {
var trade = {
ordertype: body[i]['taker_type'].toUpperCase(),
price: body[i]['price'],
quantity: body[i]['amount'],
total: body[i]['total'],
timestamp: body[i]['created_at']
};
trades.push(trade);
for (let t = 0; t < body.length; t++) {
trades.push({
ordertype: body[t].taker_type.toString().toUpperCase(),
price: parseFloat(body[t].price),
quantity: parseFloat(body[t].amount),
timestamp: parseInt(body[t].created_at)
});
}
}
return cb(null, trades);
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
} else
return cb(api_error_msg, null);
});
});
}
function get_orders(coin, exchange, cb) {
var req_url = base_url + coin.toLowerCase() + exchange.toLowerCase() + '/depth';
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + coin + exchange + '/depth';
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
// check for null body as the apis do not work all the time for some reason
if (body != null) {
if (body.errors)
return cb(body.errors, [], []);
else {
var orders = body;
var buys = [];
var sells = [];
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.errors != null)
return cb(body.errors, null, null);
else {
try {
let buys = [];
let sells = [];
if (orders['bids'].length > 0) {
for (var i = 0; i < orders['bids'].length; i++) {
var order = {
price: orders.bids[i][0],
quantity: orders.bids[i][1]
};
buys.push(order);
}
for (let b = 0; b < body.bids.length; b++) {
buys.push({
price: parseFloat(body.bids[b][0]),
quantity: parseFloat(body.bids[b][1])
});
}
if (orders['asks'].length > 0) {
for (var i = orders['asks'].length - 1; i >= 0; i--) {
var order = {
price: orders.asks[i][0],
quantity: orders.asks[i][1]
};
sells.push(order);
}
for (let s = 0; s < body.asks.length; s++) {
sells.push({
price: parseFloat(body.asks[s][0]),
quantity: parseFloat(body.asks[s][1])
});
}
return cb(null, buys, sells.reverse());
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
} else
return cb(api_error_msg, [], []);
}
});
}
function get_chartdata(coin, exchange, cb) {
var end = Date.now();
function get_chartdata(coin, exchange, api_error_msg, cb) {
const end = Date.now() / 1000;
const start = end - 86400;
const req_url = base_url + coin + exchange + '/k-line?time_from=' + parseInt(start).toString() + '&time_to=' + parseInt(end).toString() + '&period=15';
end = end / 1000;
start = end - 86400;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else if (body.errors != null)
return cb(body.errors, null);
else {
try {
let chartdata = [];
var req_url = base_url + coin.toLowerCase() + exchange.toLowerCase() + '/k-line?time_from=' + parseInt(start) + '&time_to=' + parseInt(end) + '&period=15';
for (let c = 0; c < body.length; c++)
chartdata.push([
parseInt(body[c][0]) * 1000,
parseFloat(body[c][1]),
parseFloat(body[c][2]),
parseFloat(body[c][3]),
parseFloat(body[c][4])
]);
request({uri: req_url, json: true}, function (error, response, chartdata) {
if (error)
return cb(error, []);
else {
// check for null chartdata as the apis do not work all the time for some reason
if (chartdata != null) {
if (chartdata.errors == null) {
var processed = [];
for (var i = 0; i < chartdata.length; i++)
processed.push([chartdata[i][0] * 1000, chartdata[i][1], chartdata[i][2], chartdata[i][3], chartdata[i][4]]);
return cb(null, processed);
} else
return cb(chartdata.errors, []);
} else
return cb(api_error_msg, []);
}
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
@@ -157,19 +169,30 @@ module.exports = {
market_url_template: market_url_template,
market_url_case: 'l',
get_data: function(settings, cb) {
var error = null;
get_chartdata(settings.coin, settings.exchange, function (err, chartdata) {
if (err) { chartdata = []; error = err; }
get_orders(settings.coin, settings.exchange, function(err, buys, sells) {
if (err) { error = err; }
get_trades(settings.coin, settings.exchange, function(err, trades) {
if (err) { error = err; }
get_summary(settings.coin, settings.exchange, function(err, stats) {
if (err) { error = err; }
return cb(error, {buys: buys, sells: sells, chartdata: chartdata, trades: trades, stats: stats});
});
// ensure coin info is lowercase
settings.coin = settings.coin.toLowerCase();
settings.exchange = settings.exchange.toLowerCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null) {
get_chartdata(settings.coin, settings.exchange, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
});
} else
return cb(order_error, null);
});
}
};
+158 -114
View File
@@ -1,130 +1,167 @@
var request = require('postman-request');
var base_url = 'https://api.bittrex.com/v3';
const market_url_template = 'https://global.bittrex.com/Market/Index?MarketName={base}-{coin}';
const request = require('postman-request');
const base_url = 'https://api.bittrex.com/v3';
const market_url_template = 'https://global.bittrex.com/trade/{coin}-{base}';
function get_summary(coin, exchange, cb) {
var req_url = base_url + '/markets/' + coin + '-' + exchange + '/summary';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
request({uri: req_url, json: true}, function (error, response, summary) {
if (error)
return cb(error, null);
else {
if (summary.code)
return cb(summary.code, null);
function get_summary(coin, exchange, api_error_msg, cb) {
const summary_url = base_url + '/markets/' + coin + '-' + exchange + '/summary';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: summary_url, json: true}, function (sum_error, sum_response, sum_body) {
if (sum_error)
return cb(sum_error, null);
else if (sum_body == null || sum_body == '' || typeof sum_body !== 'object')
return cb(api_error_msg, null);
else if (sum_body.code != null)
return cb(sum_body.code, null);
else {
req_url = base_url + '/markets/' + coin + '-' + exchange + '/ticker';
request({uri: req_url, json: true}, function (error, response, ticker) {
if (error)
return cb(error, null);
else {
if (ticker.code)
return cb(ticker.code, null);
else {
var retVal = {
'high': summary.high,
'low': summary.low,
'volume': summary.volume,
'bid': ticker.bidRate,
'ask': ticker.askRate,
'last': ticker.lastTradeRate,
'change': summary.percentChange
};
const ticket_url = base_url + '/markets/' + coin + '-' + exchange + '/ticker';
return cb (null, retVal);
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: ticket_url, json: true}, function (tic_error, tic_response, tic_body) {
if (tic_error)
return cb(tic_error, null);
else if (tic_body == null || tic_body == '' || typeof tic_body !== 'object')
return cb(api_error_msg, null);
else if (tic_body.code != null)
return cb(tic_body.code, null);
else {
try {
const summary = {
'high': parseFloat(sum_body.high),
'low': parseFloat(sum_body.low),
'volume': parseFloat(sum_body.volume),
'bid': parseFloat(tic_body.bidRate),
'ask': parseFloat(tic_body.askRate),
'last': parseFloat(tic_body.lastTradeRate),
'change': parseFloat(sum_body.percentChange)
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
}
});
});
}
}
});
});
}
function get_trades(coin, exchange, cb) {
var req_url = base_url + '/markets/' + coin + '-' + exchange + '/trades';
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/markets/' + coin + '-' + exchange + '/trades';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.code != null)
return cb(body.code, null);
else {
try {
let trades = [];
for (let t = 0; t < body.length; t++) {
trades.push({
ordertype: body[t].takerSide,
price: parseFloat(body[t].rate),
quantity: parseFloat(body[t].quantity),
timestamp: parseInt(new Date(body[t].executedAt).getTime() / 1000)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/markets/' + coin + '-' + exchange + '/orderbook?depth=25';
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.code != null)
return cb(body.code, null);
else {
var trades = [];
try {
let buys = [];
let sells = [];
if (body.length > 0) {
for (var i = 0; i < body.length; i++) {
var trade = {
ordertype: body[i]['takerSide'],
price: body[i]['rate'],
quantity: body[i]['quantity'],
timestamp: parseInt(new Date(body[i]['executedAt']).getTime()/1000)
};
trades.push(trade);
for (let b = 0; b < body.bid.length; b++) {
buys.push({
price: parseFloat(body.bid[b].rate),
quantity: parseFloat(body.bid[b].quantity)
});
}
}
return cb(null, trades);
for (let s = 0; s < body.ask.length; s++) {
sells.push({
price: parseFloat(body.ask[s].rate),
quantity: parseFloat(body.ask[s].quantity)
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
function get_orders(coin, exchange, cb) {
var req_url = base_url + '/markets/' + coin + '-' + exchange + '/orderbook?depth=25';
function get_chartdata(coin, exchange, api_error_msg, cb) {
const end = Date.now() / 1000;
const start = end - 86400;
const req_url = base_url + '/markets/' + coin + '-' + exchange + '/candles/MINUTE_5/recent';
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, [], []);
else {
var buys = [];
var sells = [];
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else if (body.code != null)
return cb(body.code, null);
else {
try {
let chartdata = [];
if (body['bid'].length > 0) {
for (var i = 0; i < body['bid'].length; i++) {
var order = {
price: body.bid[i].rate,
quantity: body.bid[i].quantity
};
for (let c = 0; c < body.length; c++) {
// only display every 3rd data point (every 15 mins) and only more recent than the last 24 hours
if (new Date(body[c].startsAt).getTime() / 1000 > start && (c % 3) == 0)
chartdata.push([
parseInt(new Date(body[c].startsAt).getTime()),
parseFloat(body[c].open),
parseFloat(body[c].high),
parseFloat(body[c].low),
parseFloat(body[c].close)
]);
}
buys.push(order);
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
if (body['ask'].length > 0) {
for (var i = 0; i < body['ask'].length; i++) {
var order = {
price: body.ask[i].rate,
quantity: body.ask[i].quantity
};
sells.push(order);
}
}
return cb(null, buys, sells);
}
});
}
function get_chartdata(coin, exchange, cb) {
var end = Date.now();
end = end / 1000;
start = end - 86400;
var req_url = base_url + '/markets/' + coin + '-' + exchange + '/candles/MINUTE_5/recent';
request({ uri: req_url, json: true}, function (error, response, chartdata) {
if (error)
return cb(error, []);
else {
var processed = [];
for (var i = 0; i < chartdata.length; i++) {
// only display every 3rd data point (every 15 mins) and only more recent than the last 24 hours
if (new Date(chartdata[i].startsAt).getTime()/1000 > start && (i % 3) == 0)
processed.push([new Date(chartdata[i].startsAt).getTime(), parseFloat(chartdata[i].open), parseFloat(chartdata[i].high), parseFloat(chartdata[i].low), parseFloat(chartdata[i].close)]);
}
return cb(null, processed);
}
});
});
}
@@ -132,21 +169,28 @@ module.exports = {
market_name: 'Bittrex',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACjElEQVR4nHWTzWtdZRCHn3nf95x789GWlJs2mgRdiEhAEKQhFGmsIBSyFtG1BCy2oII7DUW3biwYyD8QKF0IIrqKxK+NC6GLi8WvhTEkN+GaxBPvPee874yL3GhMdRazmt8sZp5HADATRAyAd79/BhcWwa6gaRIA3CbOraNxhbef+OpkRv4OL33eJJ96H3GL4rPgUgmaBnkPoQEpxqRphWrjTW5d7WMmwgt3PDOXMnz1CaPnn6PYMaIptTrECRgcNQUcrYvCn9016nyB9re1AHCr/SFnL7zqi53KKs2vPn6GN+bG6NWGd4O4wF4/8dqn29Vh3sql6Czb0sx1Yak9Rxa+QVWdmNci8vyT55h9uMnaDwWh4UlqZE744NpFFlZ/ZWMvJsmDs6q+HHDckKwp1isYaXpWX3mUMhpFqTw9P05MSu4d7325y71OSfACphAaQqxvBJB5YglqbmzIM5I57rb3Gc0dX/9ySKqM159tcXl6GDVDBmclloDMB4QJNAIiXuDHbkUjOMaHPd/9fAjAxkGNF7CjRwMiaARhwnGqGl7IHEQ1EIHgaO9WtHdKMi+nxwkYW/gwCZUBIiJ0e4mbs2PMPdQkyz2/9xLBwVMTTQ5KBTHDZUKMWwFsndB4mbLSZPjWsOfj+wX3tkuamaCVMfvIEL3aeOuzbfZKBSdqoeGJ9XpAuU0sX8I5ikqZPhv46MUp+tEQgbpWHmvlvLO+y0+bfcK5AOKgLg3l9r9Akj861dhQyIczQY7vLVBGZa+vxGQoVnHmQs5BZ5mlmesPorzfMWyArchgixlOFMExOi4U3TXSMcqnZBJxi/gsHLHxj0wWGpDqSNIV4kmZ/k9nsyvYQGfxvyHyxX/p/BcTSUaGzEtUTgAAAABJRU5ErkJggg==',
market_url_template: market_url_template,
market_url_case: 'u',
market_url_case: 'l',
get_data: function(settings, cb) {
var error = null;
get_chartdata(settings.coin, settings.exchange, function (err, chartdata) {
if (err) { chartdata = []; error = err; }
get_orders(settings.coin, settings.exchange, function(err, buys, sells) {
if (err) { error = err; }
get_trades(settings.coin, settings.exchange, function(err, trades) {
if (err) { error = err; }
get_summary(settings.coin, settings.exchange, function(err, stats) {
if (err) { error = err; }
return cb(error, {buys: buys, sells: sells, chartdata: chartdata, trades: trades, stats: stats});
});
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null) {
get_chartdata(settings.coin, settings.exchange, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
});
} else
return cb(order_error, null);
});
}
};
+138 -96
View File
@@ -1,119 +1,150 @@
const request = require('postman-request');
const base_url = 'https://api.dex-trade.com/v1/public/';
const base_chart_url = 'https://socket.dex-trade.com/graph/';
const api_error_msg = 'api did not return any data';
const market_url_template = 'https://dex-trade.com/spot/trading/{coin}{base}';
function get_summary(coin, exchange, bid, ask, cb) {
var summary = {};
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
request({ uri: base_url + 'ticker?pair=' + coin + exchange, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body.status == null || body.status == false)
return cb(body.error, null);
else {
summary['bid'] = bid;
summary['ask'] = ask;
summary['high'] = body.data['high'];
summary['low'] = body.data['low'];
summary['volume'] = body.data['volume_24H'];
summary['last'] = body.data['last'];
function get_summary(coin, exchange, api_error_msg, bid, ask, cb) {
const req_url = base_url + 'ticker?pair=' + coin + exchange;
return cb(null, summary);
}
}).on('error', function(err) {
return cb(error, null);
});
}
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.status == null || body.status == false)
return cb((body.error != null ? body.error : api_error_msg), null);
else {
try {
const summary = {
'high': parseFloat(body.data.high),
'low': parseFloat(body.data.low),
'volume': parseFloat(body.data.volume_24H),
'bid': parseFloat(bid),
'ask': parseFloat(ask),
'last': parseFloat(body.data.last)
};
function get_trades(coin, exchange, cb) {
var req_url = base_url + 'trades?pair=' + coin + exchange;
request({ uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body.status == null || body.status == false)
return cb(body.error, null);
else {
var trade_body = body.data;
var trades = [];
for (var i = 0; i < trade_body.length; i++) {
trades.push({
ordertype: trade_body[i].type,
price: trade_body[i].rate,
quantity: trade_body[i].volume,
timestamp: trade_body[i].timestamp
});
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
return cb(null, trades);
}
}).on('error', function(err) {
return cb(error, null);
});
});
}
function get_orders(coin, exchange, cb) {
var req_url = base_url + 'book?pair=' + coin + exchange;
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'trades?pair=' + coin + exchange;
request({ uri: req_url, json: true}, function (error, response, body) {
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.status == null || body.status == false)
return cb((body.error != null ? body.error : api_error_msg), null);
else {
try {
let trades = [];
for (let t = 0; t < body.data.length; t++) {
trades.push({
ordertype: body.data[t].type,
price: parseFloat(body.data[t].rate),
quantity: parseFloat(body.data[t].volume),
timestamp: parseInt(body.data[t].timestamp)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'book?pair=' + coin + exchange;
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, [], []);
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.status == null || body.status == false)
return cb(body.error, null);
return cb((body.error != null ? body.error : api_error_msg), null, null);
else {
var orders = body.data;
var buys = [];
var sells = [];
try {
let buys = [];
let sells = [];
if (orders['buy'].length > 0){
for (var i = 0; i < orders['buy'].length; i++) {
for (let b = 0; b < body.data.buy.length; b++) {
buys.push({
price: orders['buy'][i].rate,
quantity: orders['buy'][i].volume
price: parseFloat(body.data.buy[b].rate),
quantity: parseFloat(body.data.buy[b].volume)
});
}
}
if (orders['sell'].length > 0) {
for (var i = 0; i < orders['sell'].length; i++) {
for (let s = 0; s < body.data.sell.length; s++) {
sells.push({
price: orders['sell'][i].rate,
quantity: orders['sell'][i].volume
price: parseFloat(body.data.sell[s].rate),
quantity: parseFloat(body.data.sell[s].volume)
});
}
}
return cb(null, buys, sells);
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
}).on('error', function(err) {
return cb(error, null, null);
});
}
function get_chartdata(coin, exchange, cb) {
var end = Date.now();
var start = end - 86400000;
var req_url = base_chart_url + 'hist?t=' + coin + exchange + '&r=15&limit=100';
function get_chartdata(coin, exchange, api_error_msg, cb) {
const end = Date.now();
const start = end - 86400000;
const req_url = base_chart_url + 'hist?t=' + coin + exchange + '&r=15&limit=100';
request({ uri: req_url, json: true}, function (error, response, chartdata) {
if (error)
return cb(error, []);
else if (chartdata == null)
return cb(api_error_msg, null);
else {
var processed = [];
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else {
try {
let chartdata = [];
for (var i = 0; i < chartdata.length; i++) {
// only take values more recent than the last 24 hours
if (chartdata[i].time * 1000 > start)
processed.push([chartdata[i].time * 1000, chartdata[i].open, chartdata[i].high, chartdata[i].low, chartdata[i].close]);
for (let c = 0; c < body.length; c++) {
// only take values more recent than the last 24 hours
if ((body[c].time * 1000) > start)
chartdata.push([
parseInt(body[c].time * 1000),
parseFloat(body[c].open),
parseFloat(body[c].high),
parseFloat(body[c].low),
parseFloat(body[c].close)
]);
}
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
return cb(null, processed);
}
});
});
}
@@ -123,19 +154,30 @@ module.exports = {
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
var error = null;
get_chartdata(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function (err, chartdata) {
if (err) { chartdata = []; error = err; }
get_orders(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function(err, buys, sells) {
if (err) { error = err; }
get_trades(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function(err, trades) {
if (err) { error = err; }
get_summary(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), (buys == null || buys.length == 0 ? null : buys[0].price), (sells == null || sells.length == 0 ? null : sells[0].price), function(err, stats) {
if (err) { error = err; }
return cb(error, {buys: buys, sells: sells, chartdata: chartdata, trades: trades, stats: stats});
});
// ensure coin info is uppercase
settings.coin = settings.coin.toUpperCase();
settings.exchange = settings.exchange.toUpperCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, (buys == null || buys.length == 0 ? null : buys[0].price), (sells == null || sells.length == 0 ? null : sells[0].price), function(summary_error, stats) {
if (summary_error == null) {
get_chartdata(settings.coin, settings.exchange, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
});
} else
return cb(order_error, null);
});
}
};
+101 -69
View File
@@ -1,91 +1,114 @@
var request = require('postman-request');
var base_url = 'https://api.freiexchange.com/public/';
const request = require('postman-request');
const base_url = 'https://api.freiexchange.com/public/';
const market_url_template = '{url_prefix}/market/{coin}/{base}';
function get_summary(coin, exchange, cb) {
var req_url = base_url + '/ticker/' + coin;
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body.success != null && body.success == false)
return cb(body.result.messsage, null);
else {
var summary = {};
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/ticker/' + coin;
if (body[`${coin}_${exchange}`] != null && body[`${coin}_${exchange}`].length > 0) {
summary['bid'] = body[`${coin}_${exchange}`][0].highestBuy;
summary['ask'] = body[`${coin}_${exchange}`][0].lowestSell;
summary['volume'] = body[`${coin}_${exchange}`][0].volume24h;
summary['volume_btc'] = body[`${coin}_${exchange}`][0].volume24h_btc;
summary['low'] = body[`${coin}_${exchange}`][0].low;
summary['high'] = body[`${coin}_${exchange}`][0].high;
summary['last'] = body[`${coin}_${exchange}`][0].last;
summary['change'] = body[`${coin}_${exchange}`][0].percent_change_24h;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.success != null && body.success == false)
return cb((body.result != null && body.result.message != null ? body.result.message : api_error_msg), null);
else {
try {
const prefix = body[coin + '_' + exchange];
const summary = {
'high': parseFloat(prefix[0].high),
'low': parseFloat(prefix[0].low),
'volume': parseFloat(prefix[0].volume24h),
'volume_btc': parseFloat(prefix[0].volume24h_btc),
'bid': parseFloat(prefix[0].highestBuy),
'ask': parseFloat(prefix[0].lowestSell),
'last': parseFloat(prefix[0].last),
'change': parseFloat(prefix[0].percent_change_24h)
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
return cb(null, summary);
}
});
});
}
function get_trades(coin, exchange, cb) {
var req_url = base_url + '/trades/' + coin + (exchange == 'LTC' ? '/LTC' : '');
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/trades/' + coin + (exchange == 'LTC' ? '/LTC' : '');
request({ uri: req_url, json: true }, function (error, response, body) {
if (error)
return cb(error, null);
else if (body.success != null && body.success == false)
return cb(body.result.messsage, null);
else {
var trades = [];
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.success != null && body.success == false)
return cb((body.result != null && body.result.message != null ? body.result.message : api_error_msg), null);
else {
try {
let trades = [];
for (var i = 0; i < body.length; i++) {
// NOTE: timestamp is reduced by 7 hours (3600000ms * 7) to account for the fact the server time seems to display local time to the webserver instead of UTC time)
trades.push({
ordertype: body[i].type,
price: body[i].price,
quantity: body[i].total_coin,
timestamp: parseInt((new Date(body[i].time).getTime()-(3600000 * 7))/1000)
});
for (let t = 0; t < body.length; t++) {
trades.push({
ordertype: body[t].type,
price: parseFloat(body[t].price),
quantity: parseFloat(body[t].total_coin),
timestamp: parseInt(new Date(body[t].time.toString().replace(' ', 'T') + 'Z').getTime() / 1000)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
return cb(null, trades);
}
});
});
}
function get_orders(coin, exchange, cb) {
var req_url = base_url + '/orderbook/' + coin + (exchange == 'LTC' ? '/LTC' : '');
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/orderbook/' + coin + (exchange == 'LTC' ? '/LTC' : '');
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.success != null && body.success == false)
return cb(body.result.messsage, null);
return cb((body.result != null && body.result.message != null ? body.result.message : api_error_msg), null, null);
else {
var buys = [];
var sells = [];
try {
let buys = [];
let sells = [];
if (body['BUY'].length > 0) {
for (var i = 0; i < body['BUY'].length; i++) {
for (let b = 0; b < body.BUY.length; b++) {
buys.push({
price: body['BUY'][i].price,
quantity: body['BUY'][i].amount
price: parseFloat(body.BUY[b].price),
quantity: parseFloat(body.BUY[b].amount)
});
}
}
if (body['SELL'].length > 0) {
for (var i = 0; i < body['SELL'].length; i++) {
for (let s = 0; s < body.SELL.length; s++) {
sells.push({
price: body['SELL'][i].price,
quantity: body['SELL'][i].amount
price: parseFloat(body.SELL[s].price),
quantity: parseFloat(body.SELL[s].amount)
});
}
}
return cb(null, buys, sells);
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
@@ -104,16 +127,25 @@ module.exports = {
return settings.exchange.toUpperCase() == 'LTC';
},
get_data: function(settings, cb) {
var error = null;
get_orders(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function(err, buys, sells) {
if (err) { error = err; }
get_trades(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function(err, trades) {
if (err) { error = err; }
get_summary(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function(err, stats) {
if (err) { error = err; }
return cb(error, {buys: buys, sells: sells, chartdata: [], trades: trades, stats: stats});
// ensure coin info is uppercase
settings.coin = settings.coin.toUpperCase();
settings.exchange = settings.exchange.toUpperCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: null});
else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
});
} else
return cb(order_error, null);
});
}
};
+148 -105
View File
@@ -1,139 +1,182 @@
var request = require('postman-request');
var base_url = 'https://poloniex.com/public?command=';
const market_url_template = 'https://www.poloniex.com/exchange/{base}_{coin}';
const request = require('postman-request');
const base_url = 'https://api.poloniex.com/markets/';
const market_url_template = 'https://poloniex.com/trade/{coin}_{base}?type=spot';
function get_summary(coin, exchange, cb) {
var req_url = base_url + 'returnTicker';
var ticker = exchange + '_' + coin;
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
request({uri: req_url, json: true}, function (error, response, body) {
if (body.error)
return cb(body.error, null);
else {
var retVal = {
'high': body[ticker].high24hr,
'low': body[ticker].low24hr,
'volume': body[ticker].baseVolume,
'bid': body[ticker].highestBid,
'ask': body[ticker].lowestAsk,
'last': body[ticker].last,
'change': body[ticker].percentChange
};
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + coin + '_' + exchange + '/ticker24h';
return cb(null, retVal);
}
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.message != null)
return cb(body.message, null);
else {
try {
const summary = {
'high': parseFloat(body.high),
'low': parseFloat(body.low),
'volume': parseFloat(body.quantity),
'volume_btc': parseFloat(body.amount),
'bid': parseFloat(body.bid),
'ask': parseFloat(body.ask),
'change': parseFloat(body.dailyChange) * 100
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, cb) {
var req_url = base_url + 'returnTradeHistory&currencyPair=' + exchange + '_' + coin;
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + coin + '_' + exchange + '/trades';
request({uri: req_url, json: true}, function (error, response, body) {
if (body.error)
return cb(body.error, []);
else {
var trades = [];
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.message != null)
return cb(body.message, null);
else {
try {
let trades = [];
if (body.length > 0) {
for (var i = 0; i < body.length; i++) {
var trade = {
ordertype: body[i]['type'],
price: body[i]['rate'],
quantity: body[i]['amount'],
total: body[i]['total'],
timestamp: parseInt(new Date(body[i]['date'] + 'Z').getTime()/1000)
};
for (let t = 0; t < body.length; t++) {
trades.push({
ordertype: body[t].takerSide,
price: parseFloat(body[t].price),
quantity: parseFloat(body[t].quantity),
timestamp: parseInt(new Date(body[t].ts).getTime() / 1000)
});
}
trades.push(trade);
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
return cb(null, trades);
}
});
});
}
function get_orders(coin, exchange, cb) {
var req_url = base_url + 'returnOrderBook&currencyPair=' + exchange + '_' + coin + '&depth=50';
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + coin + '_' + exchange + '/orderBook?limit=50';
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (body.error)
return cb(body.error, []);
else {
var buys = [];
var sells = [];
if (body['bids'].length > 0) {
for (var i = 0; i < body['bids'].length; i++) {
var order = {
price: body.bids[i][0],
quantity: body.bids[i][1]
};
buys.push(order);
}
}
if (body['asks'].length > 0) {
for (var i = 0; i < body['asks'].length; i++) {
var order = {
price: body.asks[i][0],
quantity: body.asks[i][1]
};
sells.push(order);
}
}
return cb(null, buys, sells);
}
});
}
function get_chartdata(coin, exchange, cb) {
var end = Date.now();
end = end / 1000;
start = end - 86400;
var req_url = base_url + 'returnChartData&currencyPair=' + exchange + '_' + coin + '&start=' + start + '&end=' + end + '&period=1800';
request({uri: req_url, json: true}, function (error, response, chartdata) {
if (error)
return cb(error, []);
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.message != null)
return cb(body.message, null, null);
else {
if (chartdata.error == null) {
var processed = [];
try {
let buys = [];
let sells = [];
for (var i = 0; i < chartdata.length; i++)
processed.push([chartdata[i].date * 1000, parseFloat(chartdata[i].open), parseFloat(chartdata[i].high), parseFloat(chartdata[i].low), parseFloat(chartdata[i].close)]);
for (let b = 0; b < body.bids.length; b += 2) {
buys.push({
price: parseFloat(body.bids[b]),
quantity: parseFloat(body.bids[b + 1])
});
}
return cb(null, processed);
} else
return cb(chartdata.error, []);
for (let s = 0; s < body.asks.length; s += 2) {
sells.push({
price: parseFloat(body.asks[s]),
quantity: parseFloat(body.asks[s + 1])
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
function get_chartdata(coin, exchange, api_error_msg, cb) {
const end = Date.now();
const start = end - 86400000;
const req_url = base_url + coin + '_' + exchange + '/candles?interval=MINUTE_15&limit=96&startTime=' + start.toString() + '&endTime=' + end.toString();
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else if (body.message != null)
return cb(body.message, null);
else {
try {
let chartdata = [];
for (let c = 0; c < body.length; c++)
chartdata.push([
parseInt(body[c][9]),
parseFloat(body[c][2]),
parseFloat(body[c][1]),
parseFloat(body[c][0]),
parseFloat(body[c][3])
]);
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
module.exports = {
market_name: 'Poloniex',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDIgNzkuMTY0NDYwLCAyMDIwLzA1LzEyLTE2OjA0OjE3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMiAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIwLTEyLTI1VDIwOjU1OjMzLTA3OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIwLTEyLTI1VDIwOjU1OjMzLTA3OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMC0xMi0yNVQyMDo1NTozMy0wNzowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDphMzU0YTQ5My02M2VlLTQ3NDUtOTAyMC1jZjQ5ZTZlODRlNDQiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDowZTZlOTkxZi05YTM4LTgxNDAtYTlmMS0yMGU3MThjOTU5YjMiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplNzcwYmQ5Zi1kMzM2LTliNGQtYmVhMC0wOTIwNjZkNDIwZDIiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmU3NzBiZDlmLWQzMzYtOWI0ZC1iZWEwLTA5MjA2NmQ0MjBkMiIgc3RFdnQ6d2hlbj0iMjAyMC0xMi0yNVQyMDo1NTozMy0wNzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjIgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphMzU0YTQ5My02M2VlLTQ3NDUtOTAyMC1jZjQ5ZTZlODRlNDQiIHN0RXZ0OndoZW49IjIwMjAtMTItMjVUMjA6NTU6MzMtMDc6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4yIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4yAdy4AAACnUlEQVQ4y11TS09TQRid9raFloIY45/wHUNijEsXBjeKC40r3Wrig7b0AS229AVIotISATdiSohuVJDYEkXjxsSFCQlEDSASdvIwo4BiheOZK1x6bTLp3PnOOd/3nZlPOJKpOVs8IUWDXwqPT4p6rxTBkHSn0tKWSEqNq5J7EQgy5iGGcV+DVBw7ucIajRX33exAW6GA8PM8EoURnM/1QzQ2wZVMoZJLhBpxNpdDYmQE4Xwe7fw/QI6NXLGLGXY0hTH2eQalvzM9PbAEgrAFQ6jr7jbFxme+oCocgeIKF8uzU2B/uhW/VlYM0PzCAjR/AO5IM1alNM5//1zFoXQbLKzQmUxJobEXVSr7w6X+flOm7KvX2Hndg8WlJePs8sAAsV5UkWNV3pWxDJoFZ0tcD7wZHzeJnLvTiaPxhL4fm5qElYlcxNJAKK5wbApUsAUX+zrIwOL3H4bAV5Zf4fHB+/ARau9264a6iVUcx5YAFwSzVDMgvD5cuN9nquLdh48QV67CwgS2VHqLbBawlAhc7HtgEng7MQGNAlokAjsF7PH/BOz8cLe2wklnD7e149vyskH+ND+Psmv1SAwOoa73HkQgpLegbQnoJipDoi3QmH1scsqU/TiFT9y6re8nZ2dRRkx5LLZtInuXbnWNvC7/00ETOfD4CXaTgLU148w/NKRfeTVbsahrZDnSzgdzKtMFrK8bwPdT0xStRzkf2cRMySvd2MDpbBds5FSoGXFFY3IPK0BJ33/4ImtS9ISuq1WTTqO4srotQuxechRXWCPNxWOZLDpGRxEaHkacg3Kyp5dzEEI5y3TSMAvnoZZnsXwBgWfDaH/xEkc6M9CabxQFQXMi1vJvTL2b49zYJFV52uY466XyTB9nhVFYZlfcv+GHou2DaH9cAAAAAElFTkSuQmCC',
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
var error = null;
get_chartdata(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function (err, chartdata) {
if (err) { chartdata = []; error = err; }
get_orders(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function (err, buys, sells) {
if (err) { error = err; }
get_trades(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function (err, trades) {
if (err) { error = err; }
get_summary(settings.coin.toUpperCase(), settings.exchange.toUpperCase(), function (err, stats) {
if (err) { error = err; }
return cb(error, {buys: buys, sells: sells, chartdata: chartdata, trades: trades, stats: stats});
});
// ensure coin info is uppercase
settings.coin = settings.coin.toUpperCase();
settings.exchange = settings.exchange.toUpperCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null) {
get_chartdata(settings.coin, settings.exchange, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
});
} else
return cb(order_error, null);
});
}
};
+155 -114
View File
@@ -1,142 +1,183 @@
var request = require('postman-request');
var base_url = 'https://www.southxchange.com/api/v3/';
var api_error_msg = 'api did not return any data';
const market_url_template = 'https://main.southxchange.com/Market/Book/{coin}/{base}';
const request = require('postman-request');
const base_url = 'https://www.southxchange.com/api/v3/';
const market_url_template = 'https://market.southxchange.com/Market/Book/{coin}/{base}';
function get_summary(coin, exchange, cb) {
var summary = {};
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
request({ uri: base_url + 'price/' + coin + '/' + exchange, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body != null && body == '')
return cb(api_error_msg, null);
else {
summary['bid'] = body['Bid'];
summary['ask'] = body['Ask'];
summary['volume'] = body['Volume24Hr'];
summary['last'] = body['Last'];
summary['change'] = body['Variation24Hr'];
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'price/' + coin + '/' + exchange;
return cb(null, summary);
}
}).on('error', function(err) {
return cb(error, null);
});
}
function get_trades(coin, exchange, cb) {
var req_url = base_url + 'trades/' + coin + '/' + exchange;
request({ uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else {
var trades = [];
for (var i = 0; i < body.length; i++) {
var trade = {
ordertype: body[i].Type,
price: body[i].Price,
quantity: body[i].Amount,
timestamp: body[i].At
};
trades.push(trade);
}
return cb(null, trades);
}
}).on('error', function(err) {
return cb(error, null);
});
}
function get_orders(coin, exchange, cb) {
var req_url = base_url + 'book/' + coin + '/' + exchange;
request({ uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, [], []);
else if (body != null && body == '')
return cb(api_error_msg, [], []);
else {
var orders = body;
var buys = [];
var sells = [];
if (orders['BuyOrders'].length > 0){
for (var i = 0; i < orders['BuyOrders'].length; i++) {
var order = {
price: orders['BuyOrders'][i].Price,
quantity: orders['BuyOrders'][i].Amount
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.Message != null)
return cb(body.Message, null);
else {
try {
const summary = {
'volume': parseFloat(body.Volume24Hr),
'bid': parseFloat(body.Bid),
'ask': parseFloat(body.Ask),
'last': parseFloat(body.Last),
'change': parseFloat(body.Variation24Hr)
};
buys.push(order);
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
if (orders['SellOrders'].length > 0) {
for (var i = 0; i < orders['SellOrders'].length; i++) {
var order = {
price: orders['SellOrders'][i].Price,
quantity: orders['SellOrders'][i].Amount
};
sells.push(order);
}
}
return cb(null, buys, sells);
}
}).on('error', function(err) {
return cb(error, null, null);
});
});
}
function get_chartdata(coin, exchange, cb) {
var end = Date.now();
var start = end - 86400000;
var req_url = base_url + 'history/' + coin + '/' + exchange + '/' + start + '/' + end + '/90';
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'trades/' + coin + '/' + exchange;
request({ uri: req_url, json: true}, function (error, response, chartdata) {
if (error)
return cb(error, []);
else if (typeof chartdata == 'string' || chartdata instanceof String)
return cb(chartdata, []);
else {
var processed = [];
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.Message != null)
return cb(body.Message, null);
else {
try {
let trades = [];
for (var i = 0; i < chartdata.length; i++) {
// only display every 3rd data point (every 15 mins)
if ((i % 3) == 0)
processed.push([new Date(chartdata[i]['Date']).getTime(), parseFloat(chartdata[i]['PriceOpen']), parseFloat(chartdata[i]['PriceHigh']), parseFloat(chartdata[i]['PriceLow']), parseFloat(chartdata[i]['PriceClose'])]);
for (let t = 0; t < body.length; t++) {
trades.push({
ordertype: body[t].Type,
price: parseFloat(body[t].Price),
quantity: parseFloat(body[t].Amount),
timestamp: parseInt(body[t].At)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
return cb(null, processed);
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'book/' + coin + '/' + exchange;
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.Message != null)
return cb(body.Message, null, null);
else {
try {
let buys = [];
let sells = [];
for (let b = 0; b < body.BuyOrders.length; b++) {
buys.push({
price: parseFloat(body.BuyOrders[b].Price),
quantity: parseFloat(body.BuyOrders[b].Amount)
});
}
for (let s = 0; s < body.SellOrders.length; s++) {
sells.push({
price: parseFloat(body.SellOrders[s].Price),
quantity: parseFloat(body.SellOrders[s].Amount)
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
function get_chartdata(coin, exchange, api_error_msg, cb) {
const end = Date.now();
const start = end - 86400000;
const req_url = base_url + 'history/' + coin + '/' + exchange + '/' + start.toString() + '/' + end.toString() + '/96';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else if (body.Message != null)
return cb(body.Message, null);
else {
try {
let chartdata = [];
for (let c = 0; c < body.length; c++) {
// only display every 3rd data point (every 15 mins)
if ((c % 3) == 0)
chartdata.push([
parseInt(new Date(body[c].Date.toString() + 'Z').getTime()),
parseFloat(body[c].PriceOpen),
parseFloat(body[c].PriceHigh),
parseFloat(body[c].PriceLow),
parseFloat(body[c].PriceClose)
]);
}
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
module.exports = {
market_name: 'SouthXchange',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDIgNzkuMTY0NDYwLCAyMDIwLzA1LzEyLTE2OjA0OjE3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMiAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIxLTA0LTE5VDIwOjIyOjMwLTA2OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIxLTA0LTE5VDIwOjIyOjMwLTA2OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMS0wNC0xOVQyMDoyMjozMC0wNjowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1MTkzODFlNC1lZDllLWE0NDAtOWE4OC0xZWI1YWU2NjNhZDIiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpmNGVmOTA2Ny0yMDgxLTVlNDUtYTE1NS1iN2I2MjM5ZTc5MDgiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjNWIwOWE5Ni0xOGU1LTNjNDAtODNkZi0wNDExNTliNWQxYTIiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmM1YjA5YTk2LTE4ZTUtM2M0MC04M2RmLTA0MTE1OWI1ZDFhMiIgc3RFdnQ6d2hlbj0iMjAyMS0wNC0xOVQyMDoyMjozMC0wNjowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjIgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo1MTkzODFlNC1lZDllLWE0NDAtOWE4OC0xZWI1YWU2NjNhZDIiIHN0RXZ0OndoZW49IjIwMjEtMDQtMTlUMjA6MjI6MzAtMDY6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4yIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4izsm6AAABl0lEQVQ4EWNw6j61F4j/AvEnKL4NxFzuc54yWObNZpAT42dQVJBnUFJS8gDiD0D8CYr/A3EpA1CxLhD/R8M73Oc+Y7DImc4gK8LDoKiowAVU/BWqCYYfATEbyAAQTkY3BOiCZMvcWQyyQpycQAN2o2kGYWkgZoAZAMLbkA1wmXjlv1PvWQ4VDW0xOWHO/0oqqsiaU0Ca0Q3gBOKvcEO6Tvz3mP/ymEX2NAZpXsYORXk5mOYdMM3oBoCwJ4pXes/+91z4PlvHJZJBipPhm7KqGsgAbnwGgPB8ZFe4Trvz32XydUkVDS0jSTaGRDlhLgZZJIzNABA+DTPEsePof/e5zz87tB1i0HGJYNDzTGTQ906BY8IGdB7/7z7r8Wf7hh0Muq5RRBkwH0Xz7CcgWlJBWtwIGA4EvYAIxK6TwKi8/N9j7vNsTSt3BmkeYCBCohJnIKJGY/dpoN+fHTMKK2GQ5mLoQEoDOKMRNSFNvv7foe0wh5Kigpi8uMB/JWVlvAkJS1J+kmyZPxeYmfg4gZkJb1KmODNRlJ0BM1qMnKOfxJsAAAAASUVORK5CYII=',
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
var error = null;
get_chartdata(settings.coin.toLowerCase(), settings.exchange.toLowerCase(), function (err, chartdata) {
if (err) { chartdata = []; error = err; }
get_orders(settings.coin.toLowerCase(), settings.exchange.toLowerCase(), function(err, buys, sells) {
if (err) { error = err; }
get_trades(settings.coin.toLowerCase(), settings.exchange.toLowerCase(), function(err, trades) {
if (err) { error = err; }
get_summary(settings.coin.toLowerCase(), settings.exchange.toLowerCase(), function(err, stats) {
if (err) { error = err; }
return cb(error, {buys: buys, sells: sells, chartdata: chartdata, trades: trades, stats: stats});
});
// ensure coin info is lowercase
settings.coin = settings.coin.toLowerCase();
settings.exchange = settings.exchange.toLowerCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null) {
get_chartdata(settings.coin, settings.exchange, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
});
} else
return cb(order_error, null);
});
}
};
+99 -82
View File
@@ -2,102 +2,114 @@ const request = require('postman-request');
const base_url = 'https://api.xeggex.com/api/v2';
const market_url_template = 'https://xeggex.com/market/{coin}_{base}';
function get_summary(coin, exchange, cb) {
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/market/getbysymbol/' + coin + '_' + exchange;
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body.error != null)
return cb(body.error.message, null);
else {
var retVal = {
'high': body.highPriceNumber,
'low': body.lowPriceNumber,
'volume': body.volumeNumber,
'volume_btc': body.volumeUsdNumber,
'bid': body.bestBidNumber,
'ask': body.bestAskNumber,
'last': body.lastPriceNumber,
'prev': body.yesterdayPriceNumber,
'change': body.changePercentNumber
};
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.error != null)
return cb((body.error.message != null ? body.error.message : api_error_msg), null);
else {
try {
const summary = {
'high': parseFloat(body.highPriceNumber),
'low': parseFloat(body.lowPriceNumber),
'volume': parseFloat(body.volumeNumber),
'volume_btc': parseFloat(body.volumeUsdNumber),
'bid': parseFloat(body.bestBidNumber),
'ask': parseFloat(body.bestAskNumber),
'last': parseFloat(body.lastPriceNumber),
'prev': parseFloat(body.yesterdayPriceNumber),
'change': parseFloat(body.changePercentNumber)
};
return cb(null, retVal);
}
}).on('error', function(err) {
return cb(err, null);
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, cb) {
const req_url = base_url + '/historical_trades?ticker_id=' + coin + '_' + exchange + '&limit=300' ;
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/historical_trades?ticker_id=' + coin + '_' + exchange + '&limit=300';
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body.error != null)
return cb(body.error.message, null);
else {
var trades = [];
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.error != null)
return cb((body.error.message != null ? body.error.message : api_error_msg), null);
else {
try {
let trades = [];
for (var i = 0; i < body.length; i++) {
var trade = {
ordertype: body[i]['type'],
price: parseFloat(body[i]['price']),
quantity: parseFloat(body[i]['base_volume']),
timestamp: parseInt(new Date(body[i]['trade_timestamp']).getTime()/1000)
};
for (let t = 0; t < body.length; t++) {
trades.push({
ordertype: body[t].type,
price: parseFloat(body[t].price),
quantity: parseFloat(body[t].base_volume),
timestamp: parseInt(new Date(body[t].trade_timestamp).getTime() / 1000)
});
}
trades.push(trade);
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
return cb(null, trades);
}
}).on('error', function(err) {
return cb(err, null);
});
});
}
function get_orders(coin, exchange, cb) {
const req_url = base_url + '/market/getorderbookbysymbol/' + coin + '_' + exchange
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/market/getorderbookbysymbol/' + coin + '_' + exchange;
request({uri: req_url, json: true}, function (error, response, body) {
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, [], []);
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.error != null)
return cb(body.error.message, [], []);
return cb((body.error.message != null ? body.error.message : api_error_msg), null, null);
else {
var orders = body;
var buys = [];
var sells = [];
try {
let buys = [];
let sells = [];
if (orders['bids'].length > 0) {
for (var i = 0; i < orders['bids'].length; i++) {
var order = {
price: orders.bids[i].numberprice,
quantity: parseFloat(orders.bids[i].quantity)
};
buys.push(order);
for (let b = 0; b < body.bids.length; b++) {
buys.push({
price: parseFloat(body.bids[b].numberprice),
quantity: parseFloat(body.bids[b].quantity)
});
}
}
if (orders['asks'].length > 0) {
for (var i = 0; i < orders['asks'].length; i++) {
var order = {
price: orders.asks[i].numberprice,
quantity: parseFloat(orders.asks[i].quantity)
};
sells.push(order);
for (let s = 0; s < body.asks.length; s++) {
sells.push({
price: parseFloat(body.asks[s].numberprice),
quantity: parseFloat(body.asks[s].quantity)
});
}
}
return cb(null, buys, sells);
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
}).on('error', function(err) {
return cb(err, null, null);
});
}
@@ -107,16 +119,21 @@ module.exports = {
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
var error = null;
get_orders(settings.coin, settings.exchange, function(err, buys, sells) {
if (err) { error = err; }
get_trades(settings.coin, settings.exchange, function(err, trades) {
if (err) { error = err; }
get_summary(settings.coin, settings.exchange, function(err, stats) {
if (err) { error = err; }
return cb(error, {buys: buys, sells: sells, trades: trades, stats: stats});
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: null});
else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
});
} else
return cb(order_error, null);
});
}
};
+103 -75
View File
@@ -1,95 +1,114 @@
var request = require('postman-request');
var base_url = 'https://yobit.io/api/3';
const request = require('postman-request');
const base_url = 'https://yobit.net/api/3';
const market_url_template = 'https://yobit.net/en/trade/{coin}/{base}';
function get_summary(coin, exchange, cb) {
var req_url = base_url + '/ticker/' + coin + '_' + exchange;
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else {
if (body.message)
return cb(body.message, null);
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/ticker/' + coin + '_' + exchange;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.success == 0)
return cb((body.error != null ? body.error : api_error_msg), null);
else {
var summary = {};
try {
const prefix = body[coin + '_' + exchange];
const summary = {
'high': parseFloat(prefix.high),
'low': parseFloat(prefix.low),
'volume': parseFloat(prefix.vol),
'bid': parseFloat(prefix.buy),
'ask': parseFloat(prefix.sell),
'last': parseFloat(prefix.last)
};
summary['bid'] = body[coin + '_' + exchange]['buy'];
summary['ask'] = body[coin + '_' + exchange]['sell'];
summary['volume'] = body[coin + '_' + exchange]['vol'];
summary['high'] = body[coin + '_' + exchange]['high'];
summary['low'] = body[coin + '_' + exchange]['low'];
summary['last'] = body[coin + '_' + exchange]['last'];
return cb(null, summary);
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
}
});
});
}
function get_trades(coin, exchange, cb) {
var req_url = base_url + '/trades/' + coin + '_' + exchange;
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/trades/' + coin + '_' + exchange;
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else {
if (body.message)
return cb(body.message, null);
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.success == 0)
return cb((body.error != null ? body.error : api_error_msg), null);
else {
var trades = [];
try {
const prefix = body[coin + '_' + exchange];
let trades = [];
for (var i = 0; i < body[coin + '_' + exchange].length; i++) {
var trade = {
ordertype: (body[coin + '_' + exchange][i]['type'].toLowerCase() == 'bid' ? 'BUY' : 'SELL'),
price: body[coin + '_' + exchange][i].price,
quantity: body[coin + '_' + exchange][i].amount,
timestamp: body[coin + '_' + exchange][i].timestamp
};
for (let t = 0; t < prefix.length; t++) {
trades.push({
ordertype: (prefix[t].type.toLowerCase() == 'bid' ? 'BUY' : 'SELL'),
price: parseFloat(prefix[t].price),
quantity: parseFloat(prefix[t].amount),
timestamp: parseInt(prefix[t].timestamp)
});
}
trades.push(trade);
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
return cb(null, trades);
}
}
});
});
}
function get_orders(coin, exchange, cb) {
var req_url = base_url + '/depth/' + coin + '_' + exchange;
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/depth/' + coin + '_' + exchange;
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (body.success == 0)
return cb(body.error, null, null);
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.success == 0)
return cb((body.error != null ? body.error : api_error_msg), null, null);
else {
var orders = body[coin + '_' + exchange];
var buys = [];
var sells = [];
try {
const prefix = body[coin + '_' + exchange];
let buys = [];
let sells = [];
if (orders['bids'].length > 0) {
for (var i = 0; i < orders['bids'].length; i++) {
var order = {
price: orders.bids[i][0],
quantity: orders.bids[i][1]
};
buys.push(order);
for (let b = 0; b < prefix.bids.length; b++) {
buys.push({
price: parseFloat(prefix.bids[b][0]),
quantity: parseFloat(prefix.bids[b][1])
});
}
}
if (orders['asks'].length > 0) {
for (var i = 0; i < orders['asks'].length; i++) {
var order = {
price: orders.asks[i][0],
quantity: orders.asks[i][1]
};
sells.push(order);
for (let s = 0; s < prefix.asks.length; s++) {
sells.push({
price: parseFloat(prefix.asks[s][0]),
quantity: parseFloat(prefix.asks[s][1])
});
}
}
return cb(null, buys, sells);
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
@@ -100,16 +119,25 @@ module.exports = {
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
var error = null;
get_orders(settings.coin.toLowerCase(), settings.exchange.toLowerCase(), function(err, buys, sells) {
if (err) { error = err; }
get_trades(settings.coin.toLowerCase(), settings.exchange.toLowerCase(), function(err, trades) {
if (err) { error = err; }
get_summary(settings.coin.toLowerCase(), settings.exchange.toLowerCase(), function(err, stats) {
if (err) { error = err; }
return cb(error, {buys: buys, sells: sells, chartdata: [], trades: trades, stats: stats});
// ensure coin info is lowercase
settings.coin = settings.coin.toLowerCase();
settings.exchange = settings.exchange.toLowerCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: null});
else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
});
} else
return cb(order_error, null);
});
}
};
+31 -28
View File
@@ -1,5 +1,31 @@
/* This file must be valid JSON. But comments are allowed */
{
// global
"difficulty": "Difficulty",
"masternodecount": "Masternodes",
"network": "Network",
"height": "Height",
"timestamp": "Timestamp",
"size": "Size",
"transactions": "Transactions",
"total_sent": "Total Sent",
"total_received": "Total Received",
"confirmations": "Confirmations",
"total": "Total",
"total_top_100": "Top 1-100 Total",
"bits": "Bits",
"nonce": "Nonce",
"new_coins": "New Coins",
"proof_of_stake": "PoS",
"hidden_address": "Hidden Address",
"hidden_sender": "Hidden Sender",
"hidden_recipient": "Hidden Recipient",
"unknown_address": "Unknown Address",
"unknown_sender": "Unknown Sender",
"unknown_recipient": "Unknown Recipient",
"last_updated": "Last Updated",
"initial_index_alert": "Blockchain data is currently being synchronized. You may browse the site during this time, but keep in mind that data may not yet be fully accurate and some functionality may not work until synchronization is complete.",
// menu items
"menu_explorer": "Explorer",
"menu_api": "API",
@@ -18,7 +44,8 @@
"ex_search_title": "Search",
"ex_search_button": "Search",
"ex_search_message": "Search by block height, block hash, tx hash or address",
"ex_error": "Error!",
"ex_error": "Error",
"ex_warning": "Warning",
"ex_search_error": "Search found no results for: ",
"ex_latest_transactions": "Latest Transactions",
"ex_summary": "Block Summary",
@@ -51,32 +78,6 @@
"error_description": "The page you are looking for cannot be found",
"error_description_alt": "An error occurred which prevented the page from loading correctly",
// global
"difficulty": "Difficulty",
"masternodecount": "Masternodes",
"network": "Network",
"height": "Height",
"timestamp": "Timestamp",
"size": "Size",
"transactions": "Transactions",
"total_sent": "Total Sent",
"total_received": "Total Received",
"confirmations": "Confirmations",
"total": "Total",
"total_top_100": "Top 1-100 Total",
"bits": "Bits",
"nonce": "Nonce",
"new_coins": "New Coins",
"proof_of_stake": "PoS",
"hidden_address": "Hidden Address",
"hidden_sender": "Hidden Sender",
"hidden_recipient": "Hidden Recipient",
"unknown_address": "Unknown Address",
"unknown_sender": "Unknown Sender",
"unknown_recipient": "Unknown Recipient",
"last_updated": "Last Updated",
"initial_index_alert": "Blockchain data is currently being synchronized. You may browse the site during this time, but keep in mind that data may not yet be fully accurate and some functionality may not work until synchronization is complete.",
// address view
"a_title": "{1} Wallet Address Details",
"a_description": "Viewing balance and transaction data from {1} address {2}",
@@ -94,7 +95,7 @@
"move_title": "{1} Coin Movements",
"move_description": "A listing of larger movements where {1} or more {2} coins were sent in a single transaction",
// richlist
// richlist view
"rl_title": "Top {1} Coin Holders",
"rl_description": "A listing of the richest {1} wallet addresses and breakdown of the current coin distribution",
"rl_received_coins": "Top 100 - Received Coins",
@@ -108,6 +109,7 @@
"rl_top100": "Top 76-100",
"rl_hundredplus": "101+",
// network view
"net_title": "{1} Network Peers",
"net_description": "A listing of {1} network peers that have connected to the explorer node in the last 24 hours",
"net_addnodes": "Add Nodes",
@@ -165,6 +167,7 @@
"mkt_type": "Type",
"mkt_time_stamp": "Time Stamp",
"mkt_select": "Market Select",
"mkt_unexpected_api_data": "Received unexpected API data response",
// claim address view
"claim_title": "{1} Wallet Address Claim",
+20 -13
View File
@@ -1014,6 +1014,8 @@ function check_show_sync_message(blocks_to_sync) {
}
function get_last_usd_price() {
console.log('Calculating market price.. Please wait..');
// get the last usd price for coinstats
db.get_last_usd_price(function(err) {
// check for errors
@@ -1514,7 +1516,6 @@ if (lib.is_locked([database]) == false) {
} else {
// check if market feature is enabled
if (settings.markets_page.enabled == true) {
var complete = 0;
var total_pairs = 0;
var exchanges = Object.keys(settings.markets_page.exchanges);
@@ -1541,6 +1542,8 @@ if (lib.is_locked([database]) == false) {
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
var rateLimitLib = require('../lib/ratelimit');
var rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
var complete = 0;
// loop through and test all exchanges defined in the settings.json file
exchanges.forEach(function(key, index, map) {
// check if market is enabled via settings
@@ -1561,28 +1564,32 @@ if (lib.is_locked([database]) == false) {
rateLimit.schedule(function() {
// update market data
db.update_markets_db(key, split_pair[0], split_pair[1], function(err) {
if (!err) {
console.log('%s[%s]: Market data updated successfully.', key, pair_key);
complete++;
if (complete == total_pairs || stopSync)
get_last_usd_price();
} else {
if (!err)
console.log('%s[%s]: Market data updated successfully', key, pair_key);
else
console.log('%s[%s] Error: %s', key, pair_key, err);
complete++;
if (complete == total_pairs || stopSync)
get_last_usd_price();
}
complete++;
if (complete == total_pairs || stopSync)
get_last_usd_price();
});
});
} else {
console.log('Error: Entry for %s[%s] does not exist in markets database.', key, pair_key);
console.log('%s[%s] Error: Market not found in local database. Please restart the explorer', key, pair_key);
complete++;
if (complete == total_pairs || stopSync)
get_last_usd_price();
}
});
} else {
// market pair not formatted correctly
console.log('%s market pair is invalid', pair_key);
complete++;
if (complete == total_pairs || stopSync)
get_last_usd_price();
}
});
} else {