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:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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¤cyPair=' + 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¤cyPair=' + 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¤cyPair=' + 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user