Skip to content

Instantly share code, notes, and snippets.

@plu
Created September 2, 2017 04:24
Show Gist options
  • Save plu/6db0f58e3246461e0e0ae66182be7fa6 to your computer and use it in GitHub Desktop.
Save plu/6db0f58e3246461e0e0ae66182be7fa6 to your computer and use it in GitHub Desktop.
// These vars are passed to JS from PHP
// var loggedIn = true;
// var makerFee = 0.0015;
// var takerFee = 0.0025;
// These will only be used if the user has no local storage
// primaryCurrency = 'BTC';
// secondaryCurrency = 'XMR';
// currencyPair = 'BTC_XMR';
// *********
if (loggedIn === undefined) { loggedIn = false; }
var marketBTCTable, sellOrdersTable, buyOrdersTable, tradeHistoryTable, myOrdersTable, marketETHTable, marketXMRTable, marketUSDTTable;
var loadCheckInterval;
var initalLoad = true;
var hasHashCurrencyPair = false;
var maxDecimals = 8;
var updateAskSums = false;
var updateBidSums = false;
var defaultOrderbookDisplayLimit = 50;
var orderbookDisplayLimit = defaultOrderbookDisplayLimit;
var lastHeartbeat = Math.floor(Date.now()/1000);
var allBalances;
var privateInfoFetched = false;
var orderBookInitialLoad = 2;
var privateRefreshInterval = 35000;
var candleStickRefreshInterval = 60000;
var depthChartRefreshInterval = 15000;
var reinits = {};
var windowActive = true;
var updatesPaused = false;
var marketEventInProgress = false;
var marketEventQueue = {};
var marketSubscription = null;
var seq = 0;
var liveOrderBooks = true;
var fullOrderBookLoading = false;
var quickOrderBookLoading = false;
var wNonce = 0;
var openOrders = {limit: [],stopLimit: [],loansAvailable: []};
var updateChart = false;
var limitPrecision = false;
var orderBookPrecision = 6;
var orderBookPrecisionIncrement = 1 / Math.pow(10,orderBookPrecision);
var minPrecision = 2;
var showStarOnly = false;
var public_url = 'https://public.poloniex.com';
function trace(s) {
console.log(s);
}
function doubleToString(product) {
product = parseFloat(product);
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
return productString;
}
// ----------- local storage ------------------
Storage.prototype.setObject = function (key, value) {
this.setItem(key, JSON.stringify(value));
};
Storage.prototype.getObject = function (key) {
var value = this.getItem(key);
try {
return JSON.parse(value);
}
catch(err) {
console.log("JSON parse failed for lookup of ", key, "\n error was: ", err);
return null;
}
};
function saveExchangeSettings(){
var chartTypeID = $('.candlesticks .chartButtonActive').attr('id');
if (chartTypeID == undefined) {
chartTypeID = 1800;
} else {
chartTypeID = chartTypeID.substr(11, chartTypeID.length);
}
var localEX = localStorage["exchangeSettings"];
if (typeof(localEX) != 'undefined') {
var oldSettings = JSON.parse(localEX);
} else {
var oldSettings = {};
}
var settings = {
currencyPair: currencyPair,
primaryCurrency: primaryCurrency,
secondaryCurrency: secondaryCurrency,
fibLevels: $('#fibCheckbox').is(':checked'),
sma: $('#smaCheckbox').is(':checked'),
smaPeriod: $('#smaPeriod').val(),
ema: $('#emaCheckbox').is(':checked'),
emaPeriod: $('#emaPeriod').val(),
ema2: $('#ema2Checkbox').is(':checked'),
ema2Period: $('#ema2Period').val(),
bollinger: $('#bollingerCheckbox').is(':checked'),
chartType: Number(chartTypeID),
chartLeftPercent: chartLeftPercent,
chartRightPercent: chartRightPercent,
chartWidth: chartCanvasWidth,
throttleToggle: $('#throttleToggle').is(":checked"),
throttleFreq: $('#throttleFreq').val(),
groupToggle: $('#groupToggle').is(":checked"),
groupPoints: $('#groupPoints').val(),
showStarOnly: $('#marketStar').is(":checked"),
lendingOrderBooks: $('.mainBox.buyOrders').hasClass('alt'),
hideDepthChart: $('.marketDepth').hasClass('collapsed')
};
var rowSettings = $('#rowButtons .button.active').html();
var colSettings = $('#colButtons .button.active').attr('data-url');
if (rowSettings != undefined) {
settings.marketRows = rowSettings;
} else {
if (oldSettings.marketRows != undefined) {
settings.marketRows = oldSettings.marketRows;
} else {
settings.marketRows = '20';
}
}
if (colSettings != undefined) {
settings.marketCols = colSettings;
} else {
if (oldSettings.marketCols != undefined) {
settings.marketCols = oldSettings.marketCols;
} else {
settings.marketCols = 'Name';
}
}
// save all settings to local storage
localStorage.setItem('exchangeSettings', JSON.stringify(settings));
//saveTrollboxSettings();
//console.log("SAVING SETTINGS")
};
var starSettings = [];
function saveNonStarredMarket(dataPair, push){
if(push) {
starSettings.push(dataPair);
} else {
index = starSettings.indexOf(dataPair);
if (index > -1) {
starSettings.splice(index, 1);
}
}
localStorage.setItem('starSettings', JSON.stringify(starSettings));
//console.log("SAVING starSettings")
};
function restoreSettingsFromStorage(s) {
if (s.fibLevels) {
$('#fibCheckbox').prop('checked', s.fibLevels);
showFib = s.fibLevels
}
if (typeof(s.sma) != 'undefined') {
$('#smaCheckbox').prop('checked', s.sma);//
showSma = s.sma;
}
if (s.smaPeriod) {
$('#smaPeriod').val(s.smaPeriod);
smaPeriod = Number(s.smaPeriod);
}
if (typeof(s.ema) != 'undefined') {
// trace('s.ema is not undefined, = ' + s.ema);
$('#emaCheckbox').prop('checked', s.ema);
showEma = s.ema;
}
if (s.emaPeriod) {
$('#emaPeriod').val(s.emaPeriod);
emaPeriod = Number(s.emaPeriod);
}
if (typeof(s.ema2) != 'undefined') {
$('#ema2Checkbox').prop('checked', s.ema2);
showEma2 = s.ema2;
}
if (s.ema2Period) {
$('#ema2Period').val(s.ema2Period);
ema2Period = Number(s.ema2Period);
}
if (typeof(s.bollinger) != 'undefined') {
$('#bollingerCheckbox').prop('checked', s.bollinger);
bollingerBand = s.bollinger;
}
if (typeof(s.chartType) != 'undefined') {
$('.candlesticks .button').find('.active').removeClass('active');
$('.chartButton' + s.chartType).addClass('active');
chartType = Number(s.chartType);
}
if (typeof(s.chartLeftPercent) != 'undefined') {
chartLeftPercent = s.chartLeftPercent;
}
if (typeof(s.chartRightPercent) != 'undefined') {
chartRightPercent = s.chartRightPercent;
}
if (s.throttleFreq) {
$('#throttleFreq').val(s.throttleFreq);
throttleFreq = Number(s.throttleFreq);
}
if (typeof(s.throttleToggle) != 'undefined') {
if(s.throttleToggle === true){
$('#throttleToggle').click();
}
}
if (s.groupPoints) {
$('#groupPoints').val(s.groupPoints);
groupPoints = Number(s.groupPoints);
}
if (typeof(s.groupToggle) != 'undefined') {
if(s.groupToggle === true){
limitPrecision = true;
$('#groupToggle').prop('checked', true);
orderBookPrecision = $('#groupPoints').removeClass("disabled").val();
orderBookPrecisionIncrement = 1 / Math.pow(10,orderBookPrecision);
}
}
if (typeof(s.showStarOnly) != 'undefined'){
showStarOnly = s.showStarOnly;
if (showStarOnly === true) {
$('#marketStar').prop("checked", true);
}
function waitForMarketTables(){
if(marketTablesLoaded > 3){
filterNonStarred();
setTimeout(function(){
resetMatketTableHeights();
},250);
} else {
setTimeout(function(){
waitForMarketTables();
},250);
}
}
waitForMarketTables();
}
if (typeof(s.lendingOrderBooks) != 'undefined'){
if (s.lendingOrderBooks === true) {
$('.mainBox.buyOrders, .mainBox.sellOrders').addClass('alt');
}
}
if (typeof(s.hideDepthChart) != 'undefined'){
if (s.hideDepthChart === true) {
$('.marketDepth').addClass('collapsed');
$('#depthChartInfo').addClass('collapsed');
$('#depthChartYline').addClass('collapsed');
$('#depthChartDot').addClass('collapsed');
}
}
// Restore ToolPanel settings
if (s.marketRows != undefined) {
$('#rowButtons').find('.show' + s.marketRows).addClass('active');
} else {
$('#rowButtons').find('.show20').addClass('active');
}
if (s.marketCols != undefined) {
$('#colButtons').find('[data-url="' + s.marketCols + '"]').addClass('active');
} else {
$('#colButtons').find('.showName').addClass('active');
}
}
function loadExchangeSettings(){
var settings;
var localEX = localStorage["exchangeSettings"];
if(localEX === undefined){
// if we have no local storage, write the settings for the first time
saveExchangeSettings();
localEX = localStorage["exchangeSettings"];
}
settings = JSON.parse(localEX);
// Stars
var localPairs = localStorage["starSettings"];
if (typeof(localPairs) !== 'undefined') {
starSettings = JSON.parse(localPairs);
} else {
starSettings = [];
}
if (hasHashCurrencyPair) {
//trace('dont override hash-set currency pair with localStorage');
} else {
// if we have settings grab the currency pair from local storage
if(localEX != undefined){
if (currencyPairArray.indexOf(settings.currencyPair) != -1) {
currencyPair = settings.currencyPair;
primaryCurrency = settings.primaryCurrency;
secondaryCurrency = settings.secondaryCurrency;
}
}
// Replace the url with the hash
window.location.replace((margin ? '/marginTrading' : '/exchange') + '#' + primaryCurrency.toLowerCase() + '_' + secondaryCurrency.toLowerCase());
}
restoreSettingsFromStorage(settings);
//loadTrollboxSettings();
};
function initMarketBox() {
$('.markets .tools').click(function(){
if(!$(this).hasClass('active')){
hideAllToolPanels();
}
$(this).parent().find('.toolPanel').fadeToggle(200);
$(this).addClass('active');
});
}
function initBigChart() {
$('.bigChart .tools').click(function(){
$('.bigChart .toolPanel').fadeToggle();
});
$('.group.zoom button').click(function(){
var id = $(this).attr('id');
var n = id.substr(4, id.length);
$(this).parent().parent().find('.chartButtonActive').removeClass('chartButtonActive');
$(this).addClass('chartButtonActive');
chartSnapZoom(n);
saveExchangeSettings();
});
$('.group.candlesticks button').click(function(){
var id = $(this).attr('id');
var n = id.substr(11, id.length);
$(this).parent().parent().find('.chartButtonActive').removeClass('chartButtonActive');
$(this).addClass('chartButtonActive');
changeChartType(n);
saveExchangeSettings();
});
}
function initStopLimits() {
$('#stopLimitBuy').click(function(){
$('#stopLimitCommand').val('stopLimitBuy');
});
$('#stopLimitSell').click(function(){
$('#stopLimitCommand').val('stopLimitSell');
});
}
function initBookControls() {
// lending orderbooks positions
$('.switcher').click(function(){
$('.mainBox.buyOrders, .mainBox.sellOrders').toggleClass('alt');
saveExchangeSettings();
});
$('#throttleToggle').click(function() {
if (this.checked)
$('#throttleFreq').change();
else {
$("#throttleFreq").addClass("disabled");
setOrderBookUpdateInterval(0);
}
});
$("#throttleFreq").change(function(){
$('#throttleToggle').prop("checked",true);
$(this).removeClass("disabled");
setOrderBookUpdateInterval(Number(this.value) * 1000);
});
$('#groupToggle').click(function() {
if (this.checked)
$('#groupPoints').change();
else {
limitPrecision = false;
$('#groupPoints').addClass("disabled");
changeOrderBookPrecision(6);
}
});
$('#groupPoints').change(function(){
limitPrecision = true;
$("#groupToggle").prop("checked",true);
$(this).removeClass("disabled");
changeOrderBookPrecision(this.value);
});
if ($id("throttleToggle").checked)
$("#throttleFreq").change();
}
function initMarketDepth() {
$('.marketDepth .head').click(function(){
$('.marketDepth').toggleClass('collapsed');
$('#depthChartInfo').toggleClass('collapsed');
$('#depthChartYline').toggleClass('collapsed');
$('#depthChartDot').toggleClass('collapsed');
saveExchangeSettings();
});
}
function initTradeHistory() {
$('.tradeHistory button').click(function() {
$('.tradeHistory button.active').removeClass('active');
$(this).addClass('active');
var id = $(this).attr('id');
});
}
function initNonMarketTables(){
$(window).resize(function(){
$('#sellOrderBookTable').DataTable().draw();
$('#buyOrderBookTable').DataTable().draw();
$('#tradeHistoryTable').DataTable().draw();
$('#myOrdersTable').DataTable().draw();
$('#userTradeHistoryTable').DataTable().draw();
});
}
function initEscToolpanels() {
$(document).keyup(function(e) {
// if (e.keyCode == 13) { } // enter
if (e.keyCode === 27) { hideAllToolPanels(); } // esc
});
var $menu = $('.toolPanel, .tools, .helpPanel, .help');
$(document).on('click', function (e) {
// if element is opened and click target is outside it, hide it
if ( !$menu.is(e.target) && !$menu.has(e.target).length) {
hideAllToolPanels();
}
});
}
var myTradeHistory = [];
var myTradeHistory_max = 100;
function writeMyTradesTable(d) {
var pair = currencyPair.split('_');
if (d === undefined)
d = myTradeHistory;
else
myTradeHistory = d;
var t = '<table id="userTradeHistoryTable">'
t += '<thead><tr>';
t += '<th>Date</th>';
t += '<th>Type</th>';
t += '<th>Price (' + pair[0] + ')</th>';
t += '<th>Amount (' + pair[1] + ')</th>';
t += '<th>Total (' + pair[0] + ')</th>';
t += '</tr></thead>';
t += '<tbody>';
var numRows = Math.min(myTradeHistory_max,d.length);
for(var i = 0; i < numRows; i++) {
var item = d[i];
var row = '<tr>';
var sellClass = 'sellClass';
var buySell = 'Sell';
if (item.type === 'buy') {
sellClass = 'buyClass';
buySell = 'Buy';
}
row += '<td class="date"><span class="year">' + item.date.substring(0, 5) + '</span>' + item.date.substring(5,16) + '<span class="seconds">' + item.date.substring(16) + '</span></td>';
row += '<td class="type"><span class="' + sellClass + '">' + buySell + '</span></td>';
row += '<td>' + exactRound(item.rate, maxDecimals) + '</td>';
row += '<td>' + exactRound(item.amount, maxDecimals) + '</td>';
row += '<td>' + exactRound(item.total, maxDecimals) + '</td>';
row += '</tr>';
t += row;
}
t += '</tbody>';
t += '<tbody><tr class="messageTR"><td colspan="5" class="messageTD"><a href="/tradeHistory" class="standard nounderline">Complete Trade History...</a></td></tr></tbody>';
$('.tradeHistory .data.myTrades').html(t);
$('#userTradeHistoryTable').dataTable({
'paging': false,
'autoWidth': true,
'info': false,
'scrollY': 360,
'bSort' : false,
'language': { "emptyTable": "You have not made any trades yet." },
'fnInitComplete': function() {
$('#userTradeHistoryTable_wrapper')
.find('.dataTables_scrollBody')
.jScrollPane({
verticalDragMinHeight: 20
});
}
});
//redraw the table to account for the scrollbar width
$('#userTradeHistoryTable').DataTable().draw();
}
function refreshMyTrades() {
var myTradesURL = '/private?command=returnUserTradeHistoryJSON&currencyPair=' + currencyPair;
$.getJSON(myTradesURL, function(d) {
writeMyTradesTable(d);
});
}
function writeTradeHistoryTable(d) {
var pair = currencyPair.split('_');
var t = '<table id="tradeHistoryTable">'
t += '<thead><tr>';
t += '<th>Date</th>';
t += '<th>Type</th>';
t += '<th>Price (' + pair[0] + ')</th>';
t += '<th>Amount (' + pair[1] + ')</th>';
t += '<th>Total (' + pair[0] + ')</th>';
t += '</tr></thead>';
t += '<tbody id="tradeHistoryTableBody">';
var len = (d instanceof Object) ? d.length : 0;
for(var i = 0; i < len; i++) {
var item = d[i];
var row = '<tr>';
var sellClass = 'sellClass';
var buySell = 'Sell';
if (item.type === 'buy') {
sellClass = 'buyClass';
buySell = 'Buy';
}
row += '<td class="date"><span class="year">' + item.date.substring(0, 5) + '</span>' + item.date.substring(5,16) + '<span class="seconds">' + item.date.substring(16) + '</span></td>';
row += '<td class="type"><span class="' + sellClass + '">' + buySell + '</span></td>';
row += '<td>' + exactRound(item.rate, maxDecimals) + '</td>';
row += '<td>' + exactRound(item.amount, maxDecimals) + '</td>';
row += '<td>' + exactRound(item.total, maxDecimals) + '</td>';
row += '</tr>';
t += row;
}
t += '</tbody>';
$('.tradeHistory .data.marketTrades').html(t);
$('#tradeHistoryTable').dataTable({
'paging': false,
'autoWidth': true,
'info': false,
'scrollY': 360,
'bSort' : false,
'language': { "emptyTable": "There are no trades." },
'fnInitComplete': function() {
$('#tradeHistoryTable_wrapper')
.find('.dataTables_scrollBody')
.jScrollPane({
verticalDragMinHeight: 20
});
}
});
//redraw the table to account for the scrollbar width
$('#tradeHistoryTable').DataTable().draw();
}
function refreshTradeHistory(){
var tradeHistURL = public_url + '?command=returnTradeHistory&currencyPair=' + currencyPair;
$.getJSON(tradeHistURL, function(d) {
writeTradeHistoryTable(d);
});
}
// Fill buy/sell fields with summed order book amounts
function orderBookClick(side,row){
var rate = row.cells[0].innerHTML;
var totalAmount = 0;
var total = 0;
if (side == "bids"){
var targetSide = "sell";
var otherSide = "buy";
} else {
var targetSide = "buy";
var otherSide = "sell";
}
var reversed = false;
var rows = row.parentElement.rows;
for (var i=(reversed ? rows.length-1 : 0); (reversed ? (i >= row.rowIndex-1) : (i < row.rowIndex)); i += (reversed ? -1 : 1)){
var amount = parseFloat(rows[i].cells[1].innerHTML);
totalAmount += amount;
total += parseFloat(rows[i].cells[0].innerHTML) * amount;
}
document.getElementById(targetSide + "Rate").value = rate;
document.getElementById(targetSide + "Amount").value = totalAmount.toFixed(8);
document.getElementById(targetSide + "Total").value = total.toFixed(8);
document.getElementById(otherSide + "Rate").value = rate;
document.getElementById(otherSide + "Amount").value = "";
document.getElementById(otherSide + "Total").value = "";
}
function loadFullOrderbook(numRows){
if (typeof numRows == "undefined")
numRows = 9999999-orderbookDisplayLimit;
orderBookReady = false;
$(".messageTD").html('Loading <i class="fa fa-spinner fa-spin"></i>');
setTimeout(function(){
orderbookDisplayLimit += numRows;
writeBuySellOrdersTable('bids', orderbookDisplayLimit);
writeBuySellOrdersTable('asks', orderbookDisplayLimit);
orderBookReady = true;
processMarketQueue();
},100);
}
function writeBuySellOrdersTable(side, displayLimit){
if (!displayLimit)
displayLimit = orderbookDisplayLimit;
var buySell = (side == 'asks' ? 'sell' : 'buy');
var rates = limitPrecision ? Object.keys(orderBookFixedRates[side]).sort(side == "asks" ? asc : desc) : orderBookRates[side];
var t = '<table id="' + buySell + 'OrderBookTable">';
t += '<thead><tr>';
t += '<th>Price</th>';
t += '<th>' + secondaryCurrency+ '</th>';
t += '<th>' + primaryCurrency + '</th>';
t += '<th>Sum(' + primaryCurrency + ')</th>';
t += '</tr></thead>';
t += '<tbody id="' + side + 'TableBody">';
for (var i in rates){
if (i > displayLimit)
break;
var order = limitPrecision ? sumOrderRow(side,rates[i]) : orderBookCache[side][rates[i]]
t += orderBookRow(order,side);
}
t += '</tbody>';
// Add the load full orderbook button if needed
if (rates.length>displayLimit){
var linkText = '<tbody><tr class="messageTR" id="' + side + 'LoadAll"><td></td><td></td><td></td><td class="messageTD"><a class="standard nounderline" onclick="loadFullOrderbook(100);" href="javascript:void(0);">Load 100 More<i class="fa fa-sort-amount-asc"></i></a></td></tr></tbody>';
t += linkText;
}
var div = $('.' + buySell + 'Orders');
div.find('.data').html(t);
$("#" + side + "TableBody tr").click(function(){orderBookClick(side,this)});
// set currencies, totals, highest bid / lowest ask
// But only if the table is not empty, otherwise it'll fail
if(rates.length > 0){
var cur = div.find('.details .currency');
var topOrder = exactRound(rates[0], maxDecimals);
if (buySell === 'buy') {
cur.html(primaryCurrency);
document.getElementById("highestBid").innerHTML = topOrder;
if (orderBookInitialLoad>0)
document.getElementById("sellRate").value = topOrder;
} else {
cur.html(secondaryCurrency);
document.getElementById("lowestAsk").innerHTML = topOrder;
if (orderBookInitialLoad>0)
document.getElementById("buyRate").value = topOrder;
}
}
orderBookInitialLoad -= 1;
// set total at top
document.getElementById(side + "Total").innerHTML = orderBookTotals[side].toFixed(8);
// reinit datatables
var options = {
'paging': false,
'autoWidth': true,
'info': false,
'scrollY': 360,
'bSort': false,
'language': { "emptyTable": "No orders to display." }
};
$('#' + buySell + 'OrderBookTable').dataTable(options);
// reinit jscrollpane
$('#' + buySell + 'OrderBookTable_wrapper .dataTables_scrollBody').jScrollPane({
verticalDragMinHeight: 20
});
//redraw the table to account for the scrollbar width
$('#' + buySell + 'OrderBookTable').DataTable().draw();
setTimeout(function(){
updateTotals(side,-1,true);
},0);
}
function reinitOrderbookPane(buySell){
reinits['#' + buySell + 'OrderBookTable_wrapper .dataTables_scrollBody'] = true;
}
function executeReinits(){
if (updatesPaused)
return;
for (pane in reinits){
if (reinits[pane])$(pane).data('jsp').reinitialise();
reinits[pane] = false;
}
}
function refreshDepthChart(){
if (updatesPaused)
return;
if (!orderBookReady)
return setTimeout(function(){refreshDepthChart();}, 1000);
var cw = getChartWidth();
$('#depthCanvas').attr({height: 200 * window.devicePixelRatio, width: cw * window.devicePixelRatio}).css({width: cw});
// Reformat the orderbook cache
var formattedOrderBook = {"asks": [], "bids": []};
for (var side in orderBookRates)
for (var i in orderBookRates[side])
formattedOrderBook[side][i] = [parseFloat(orderBookRates[side][i]),parseFloat(orderBookCache[side][orderBookRates[side][i]].amount)];
// Draw the depth chart
depthDetectArrays = depthChart("depthCanvas", formattedOrderBook, dark);
}
function refreshOrderBook_br(){
var url = public_url + '?command=returnOrderBook&depth=9999999&currencyPair=' + currencyPair;
resetOrderBookCache();
$.getJSON(url, function(d) {
delete d.isFrozen;
seq = parseInt(d.seq);
delete d.seq;
for (var side in d)
for (var i in d[side])
cacheOrder(d[side][i],side,false,i);
writeBuySellOrdersTable('bids');
writeBuySellOrdersTable('asks');
for (var i in marketEventQueue)
if (parseInt(i) <= seq)
delete marketEventQueue[i];
orderBookReady = true;
setBookUIstate();
processMarketQueue();
refreshDepthChart();
});
}
function refreshOrderBook_quick(){
var url = public_url + '?command=returnOrderBook&depth=' + orderbookDisplayLimit + '&currencyPair=' + currencyPair;
resetOrderBookCache();
$.getJSON(url, function(d) {
delete d.isFrozen;
delete d.seq;
for (var side in d)
for (var i in d[side])
if (!fullOrderBookLoading && !orderBookReady)
cacheOrder(d[side][i],side,false,i);
quickOrderBookLoading = true;
if (!fullOrderBookLoading && !orderBookReady){
writeBuySellOrdersTable('bids');
writeBuySellOrdersTable('asks');
}
quickOrderBookLoading = false;
});
}
function init3ColActions() {
$(function () {
$("#stopLimitTotal").on("keyup", function () {
var product = document.getElementById('stopLimitTotal').value / document.getElementById('stopLimitRate').value;
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
document.getElementById('stopLimitAmount').value = productString;
});
});
$(function () {
$("#buyTotal").on("keyup", function () {
var product = Math.floor((document.getElementById('buyTotal').value / document.getElementById('buyRate').value)*100000000)/100000000;
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
document.getElementById('buyAmount').value = productString;
});
});
$(function () {
$("#sellTotal").on("keyup", function () {
var product = Math.floor((document.getElementById('sellTotal').value / document.getElementById('sellRate').value)*100000000)/100000000;
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
document.getElementById('sellAmount').value = productString;
});
});
$(function () {
$("#buyAmount").on("keyup", function () {
updateBuyTotal();
});
});
$(function () {
$("#buyRate").on("keyup", function () {
updateBuyTotal();
});
});
$(function () {
$("#sellAmount").on("keyup", function () {
updateSellTotal();
});
});
$(function () {
$("#sellRate").on("keyup", function () {
updateSellTotal();
});
});
$(function () {
$("#stopLimitAmount").on("keyup", function () {
updateStopLimitTotal();
});
});
$(function () {
$("#stopLimitRate").on("keyup", function () {
updateStopLimitTotal();
});
});
$(function () {
$("#highestBid").click(function (e) {
e.preventDefault(); // if desired...
document.getElementById('sellRate').value = $("#highestBid").text();
updateSellTotal();
});
});
$(function () {
$("#lowestAsk").click(function (e) {
e.preventDefault(); // if desired...
document.getElementById('buyRate').value = $("#lowestAsk").text();
updateBuyTotal();
});
});
$(function () {
$("#stopLimitSecondaryBalance").click(function (e) {
e.preventDefault();
document.getElementById('stopLimitAmount').value = $("#stopLimitSecondaryBalance").text();
updateSellTotal();
});
});
$(function () {
$("#stopLimitPrimaryBalance").click(function (e) {
e.preventDefault();
var product = $("#stopLimitPrimaryBalance").text() / document.getElementById('stopLimitRate').value;
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
document.getElementById('stopLimitAmount').value = productString;
document.getElementById('stopLimitTotal').value = $("#stopLimitPrimaryBalance").text();
updateBuyTotal();
});
});
$(function () {
$("#secondaryBalance").click(function (e) {
e.preventDefault();
document.getElementById('sellAmount').value = $("#secondaryBalance").text();
updateSellTotal();
});
});
$(function () {
$("#primaryBalance").click(function (e) {
e.preventDefault();
var product = $("#primaryBalance").text() / document.getElementById('buyRate').value;
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
document.getElementById('buyAmount').value = productString;
document.getElementById('buyTotal').value = $("#primaryBalance").text();
updateBuyTotal();
});
});
}
function updateStopLimitTotal() {
var product = document.getElementById('stopLimitAmount').value * document.getElementById('stopLimitRate').value;
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
document.getElementById('stopLimitTotal').value = productString;
}
function updateSellTotal() {
var product = document.getElementById('sellAmount').value * document.getElementById('sellRate').value;
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
document.getElementById('sellTotal').value = productString;
}
function updateBuyTotal() {
var product = document.getElementById('buyAmount').value * document.getElementById('buyRate').value;
var productString = product.toFixed(8).toString();
if (productString.match(/\./)) {
productString = productString.replace(/\.?0+$/, '');
}
document.getElementById('buyTotal').value = productString;
}
function webSocketCall(params,id){
return false;
if ('conn' in window && window.conn.readyState == 1 && 1000 in window.conn.subscriptions){
if (typeof id == "undefined")
id = ++wNonce + usid;
window.conn.send(JSON.stringify({command: "private",channel: 2000,id: id,params: params}));
return true;
} else {
return false;
}
}
function cancelOrder(orderNumber) {
$("#cancel-" + orderNumber).html('<span class="fa fa-spinner fa-spin"></span>');
var params = {command: 'cancelOrder', currencyPair: currencyPair, orderNumber: orderNumber};
if (webSocketCall(params,orderNumber))
return;
$.post("/private", params,function(data){
data = JSON.parse(data);
if (data.success == 1)
$("#myOrdersTable").DataTable().row("#orderRow-" + orderNumber).remove().draw();
}).always(function(){
updatePrivateInfo();
});
}
function cancelTriggerOrder(orderNumber) {
url = "/private";
var posting = $.post(url, { command: 'cancelTriggerOrder', currencyPair: currencyPair, orderNumber: orderNumber});
posting.done(function (data) {
updatePrivateInfo();
});
}
function myOpenOrdersRow(item){
var split = item.date.split('-');
var year = split[0];
var restOfDate = split[1] + '-' + split[2];
split = restOfDate.split(':');
var seconds = split[2];
restOfDate = split[0] + ':' + split[1];
var row = '<tr id="orderRow-' + item.orderID + '">';
row += '<td class="type"><span class="' + item.type + 'Class">' + capitalize(item.type) + '</span></td>';
row += '<td class="rate">' + item.rate + '</td>';
row += '<td class="amount">' + item.amount + '</td>';
row += '<td class="total">' + exactRound(item.total, maxDecimals) + '</td>';
row += '<td>--</td>';
row += '<td class="date"><span class="year">' + year + '-</span>' + restOfDate + '<span class="seconds">:' + seconds + '</span></td>';
row += '<td class="action" id="cancel-' + item.orderID + '" style="text-align:center;"><a class="standard nounderline" href="javascript:void(0)" onclick="javascript:cancelOrder('+ item.orderID +');">Cancel</a></td>';
row += '</tr>';
return row;
}
function writeMyOpenOrdersTable(d) {
ds = d['stopLimit'];
loansAvailable = d['loansAvailable'];
openOrders = d;
var t = '<table id="myOrdersTable"><thead><tr>';
t += '<th>Type</th>';
t += '<th>Price (' + primaryCurrency + ')</th>';
t += '<th>Amount (' + secondaryCurrency + ')</th>';
t += '<th>Total (' + primaryCurrency + ')</th>';
t += '<th>Rate/Stop</th>';
t += '<th>Date</th>';
t += '<th>Action</th>';
t += '</tr></thead>';
t += '<tbody>';
for (var i in openOrders.limit)
t += myOpenOrdersRow(openOrders.limit[i]);
for (var i = 0; i < loansAvailable.length; i++) {
var item = loansAvailable[i];
var split = item.date.split('-');
var year = split[0];
var restOfDate = split[1] + '-' + split[2];
split = restOfDate.split(':');
var seconds = split[2];
restOfDate = split[0] + ':' + split[1];
var buySell = 'Buy';
if (item.type === 'sell') { buySell = 'Sell'; }
var row = '<tr>';
row += '<td class="type"><span class="' + item.type + 'Class">' + buySell + '</span><span class="description"> (Loans-available)</span></td>';
row += '<td>' + item.rate + '</td>';
row += '<td>' + item.amount + '</td>';
row += '<td>' + exactRound(item.total, maxDecimals) + '</td>';
row += '<td>' + (parseFloat(item.triggerValue)*100).toFixed(4) + '%</td>';
row += '<td class="date"><span class="year">' + year + '-</span>' + restOfDate + '<span class="seconds">:' + seconds + '</span></td>';
row += '<td class="action"><a class="standard nounderline" href="javascript:void(0)" onclick="javascript:cancelTriggerOrder('+ item.orderID +');">Cancel</a></td>';
row += '</tr>';
t += row;
}
for (var i = 0; i < ds.length; i++) {
var item = ds[i];
var split = item.date.split('-');
var year = split[0];
var restOfDate = split[1] + '-' + split[2];
split = restOfDate.split(':');
var seconds = split[2];
restOfDate = split[0] + ':' + split[1];
var buySell = 'Buy';
if (item.type === 'sell') { buySell = 'Sell'; }
var row = '<tr>';
row += '<td class="type"><span class="' + item.type + 'Class">' + buySell + '</span><span class="description"> (Stop-limit)</span></td>';
row += '<td>' + item.rate + '</td>';
row += '<td>' + item.amount + '</td>';
row += '<td>' + exactRound(item.total, maxDecimals) + '</td>';
row += '<td>' + item.stop + '</td>';
row += '<td class="date"><span class="year">' + year + '-</span>' + restOfDate + '<span class="seconds">:' + seconds + '</span></td>';
row += '<td class="action"><a class="standard nounderline" href="javascript:void(0)" onclick="javascript:cancelTriggerOrder('+ item.orderID +');">Cancel</a></td>';
row += '</tr>';
t += row;
}
t += '</tbody></table>';
$('.openOrders .data').html(t);
$('#myOrdersTable').dataTable({
'paging': false,
'autoWidth': true,
'info': false,
'scrollY': 360,
'bSort' : false,
'scrollCollapse' : true,
'language': { "emptyTable": "You have no open orders." },
'fnInitComplete': function() {
$('#myOrdersTable_wrapper')
.find('.dataTables_scrollBody')
.jScrollPane({
verticalDragMinHeight: 20
});
}
});
//redraw the table to account for the scrollbar width
$('#myOrdersTable').DataTable().draw();
}
function initTradeHistoryButtons() {
$('#userTradeHistoryButton').click(function(){
$('#marketTradeHistoryButton').removeClass('active');
$(this).addClass('active');
$('.tradeHistory .data.myTrades').show();
$('.tradeHistory .data.marketTrades').hide();
$('#userTradeHistoryTable').DataTable().draw();
refreshMyTrades();
});
$('#marketTradeHistoryButton').click(function(){
$('#userTradeHistoryButton').removeClass('active');
$(this).addClass('active');
$('.tradeHistory .data.marketTrades').show();
$('.tradeHistory .data.myTrades').hide();
$('#tradeHistoryTable').DataTable().draw();
});
}
function updateTickerBalances (){
var balance,value,oldBalance,oldValue;
var zero = 0.0;
zero = zero.toFixed(4);
for (var pair in allTickerData){
var pairArray = pair.split("_"),
base = pairArray[0],
quote = pairArray[1],
lPair = pair.toLowerCase();
var row = $('#marketRow' + lPair);
var balance = 0.0;
var value = 0.0;
if (allBalances instanceof Object){
balance = parseFloat(allBalances['balances'][quote]) + parseFloat(allBalances['onOrders'][quote]);
value = balance * parseFloat(allTickerData[pair]['highestBid']);
}
balance = balance.toFixed(4);
value = value.toFixed(4);
if (isNaN(balance))balance = zero;
if (isNaN(value))value = zero;
if (!('balance' in allTickerData[pair]))allTickerData[pair]['balance'] = zero;
if (!('value' in allTickerData[pair]))allTickerData[pair]['value'] = zero;
oldBalance = allTickerData[pair]['balance'];
oldValue = allTickerData[pair]['value'];
if (balance != oldBalance | value != oldValue){
allTickerData[pair]['balance'] = balance;
allTickerData[pair]['value'] = value;
var table = $("#market" + base).DataTable();
var balCell = row.find('.colBalance');
var valCell = row.find('.colEstVal');
try {
table.cell(balCell).data(balance).draw();
table.cell(valCell).data(value).draw();
} catch(err) {
// Still not sure why there are blank cells sometimes...
}
}
}
}
function updatePrivateInfo(){
var url = '/private?command=returnPrivateInfoJSON&currencyPair=' + currencyPair;
if (!loggedIn) { privateInfoFetched = true; return; }
$.getJSON(url, function(d) {
if (d.error) {
loggedIn = false;
showLogoutWarning();
return;
}
var primaryBalance = margin ? d.balances.tradable[currencyPair][primaryCurrency] : d.balances.balances[primaryCurrency];
var secondaryBalance = margin ? d.balances.tradable[currencyPair][secondaryCurrency] : d.balances.balances[secondaryCurrency];
$('#primaryBalance').html(primaryBalance);
$('#secondaryBalance').html(secondaryBalance);
$('#stopLimitPrimaryBalance').html(primaryBalance);
$('#stopLimitSecondaryBalance').html(secondaryBalance);
allBalances = d.balances;
if (privateInfoFetched)updateTickerBalances();
privateInfoFetched = true;
var openOrders = d.openOrders;
writeMyOpenOrdersTable(openOrders);
if (margin){
var marginPosition = d.marginPositions[currencyPair];
html = "";
if (marginPosition){
var position = marginPosition['amount'] < 0 ? '<span class="valueNegative">Short</span>' : '<span class="valuePositive">Long</span>';
var amount = marginPosition['amount'];
var liquidationPrice = marginPosition['liquidationPrice'] <= 0 ? "N/A" : marginPosition['liquidationPrice'];
html += "<table class='orderBook'><tr>";
html += "<th>Position</th>";
html += "<th>Amount</th>";
html += "<th>Base Price</th>";
html += "<th>Est. Liquidation Price</th>";
html += "<th>Unrealized P/L</th>";
html += "<th>Unrealized Lending Fees</th>";
html += "<th>Action</th>";
html += "</tr>";
html += "<tr>";
html += "<td>" + position + "</td>";
html += "<td>" + amount + " " + secondaryCurrency + "</td>";
html += "<td>" + (marginPosition['basePrice'] <= 0 ? "N/A" : marginPosition['basePrice']) + "</td>";
html += "<td>" + liquidationPrice + "</td>";
html += "<td><span class=\"value" + (marginPosition['pl'] < 0 ? "Negative" : "Positive") + "\">" + marginPosition['pl'] + " " + primaryCurrency + "</span></td>";
html += "<td><span class=\"value" + (marginPosition['lendingFees'] < 0 ? "Negative" : "Positive") + "\">" + marginPosition['lendingFees'] + " " + primaryCurrency + "</span></td>";
html += "<td><a class='standard' href='javascript:void(0)' onclick='closeMarginPosition(\"" + currencyPair + "\")'>Close</a></td>";
html += "</tr></table>";
} else {
html += "<div class='message'><div>To begin margin trading, you must first <a href='javascript:void(0)' onclick='showBalanceTransfer()' class='standard'>transfer balances</a> into your margin account. Once you open a margin position, it will appear here. <span class='help'>Be sure you have read about <a href='/support/aboutMarginTrading/' class='standard'>Margin Trading on Poloniex</a> and understand the risks before opening a position.</span></div></div>";
}
$("#marginPosition").html(html);
html = "<tr>";
html += "<th>Coin</th>";
html += "<th>Position</th>";
html += "<th>Amount</th>";
html += "<th>P/L (BTC)</th>";
html += "<th>Liq. Price</th>";
html += "</tr>";
atLeastOne = false;
for (marginPair in d.marginPositions){
if (marginPair.indexOf("_") == -1)
continue;
explode = marginPair.split("_");
coin = explode[1];
marginBase = explode[0];
if (d.marginPositions[marginPair]){
position = d.marginPositions[marginPair]['amount'] < 0 ? '<span class="valueNegative">Short</span>' : '<span class="valuePositive">Long</span>';
amount = d.marginPositions[marginPair]['amount'];
pl = (parseFloat(d.marginPositions[marginPair]['pl']) + parseFloat(d.marginPositions[marginPair]['lendingFees'])).toFixed(8);
pl = "<span class=\"value" + (pl < 0 ? "Negative" : "Positive") + "\">" + pl + "</span>";
liquidationPrice = d.marginPositions[marginPair]['liquidationPrice'] <= 0 ? "N/A" : d.marginPositions[marginPair]['liquidationPrice'];
} else {
continue;
}
atLeastOne = true;
marginBalance = d.balances.marginBalances.balances[coin] === undefined ? "-" : d.balances.marginBalances.balances[coin];
html += "<tr>";
html += "<td class=\"coin\">" + coin + "</td>";
html += "<td class=\"position\">" + position + "</td>";
html += "<td>" + amount + "</td>";
html += "<td>" + pl + "</td>";
html += "<td>" + liquidationPrice + "</td>";
html += "</tr>";
}
if (!atLeastOne)
html += "<tr><td class='empty' colspan='5'>You have no open positions.</td></tr>";
$("#positionsSideTable").html(html);
var data = d.balances.marginBalances;
var plClass = "";
var feeClass = "";
if (data['info']['pl']>0)
plClass="valuePositive";
if (data['info']['pl']<0)
plClass="valueNegative";
if (data['info']['lendingFees']<0)
feeClass="valueNegative";
html = '';
/*
for (currency in data['balances']){
html += '<tr>';
html += '<td>' + currency + '</td>';
html += '<td>' + data['balances'][currency] + '</td>';
html += '</tr>';
}
*/
initialMargin = parseFloat(data['info']['initialMargin']);
maintenanceMargin = parseFloat(data['info']['maintenanceMargin']);
currentMargin = parseFloat(data['info']['currentMargin']);
warningScale = Math.floor(100 - ((currentMargin - maintenanceMargin) * (100 / (initialMargin - maintenanceMargin))));
if (warningScale < 0)
warningScale = 0;
if (warningScale > 100)
warningScale = 100;
if (currentMargin >= 1.0){
currentMargin = '>100';
} else {
currentMargin = (currentMargin*100).toFixed(2);
}
leverage = (1 / parseFloat(data['info']['initialMargin'])).toFixed(1);
html += '<tr>';
html += '<td>Total Margin Value</td>';
html += '<td>' + data['info']['totalValue'] + ' BTC</td>';
html += '</tr><tr>';
html += '<td>Unrealized P/L</td>';
html += '<td><span class="' + plClass + '">' + data['info']['pl'] + ' BTC</span></td>';
html += '</tr><tr>';
html += '<td>Unrealized Lending Fees</td>';
html += '<td><span class="' + feeClass + '">' + data['info']['lendingFees'] + ' BTC</span></td>';
html += '</tr><tr>';
html += '<td>Net Value</td>';
html += '<td>' + data['info']['netValue'] + ' BTC</td>';
html += '</tr><tr>';
html += '<td>Total Borrowed Value</td>';
html += '<td>' + data['info']['totalBorrowedValue'] + ' BTC</td>';
html += '</tr><tr>';
html += '<th colspan="2">Margins (' + leverage + 'x Leverage)</th></tr>';
html += '<tr id="marginGraphTR">';
html += '<td colspan="2">';
html += '<div class="heading">';
html += '<div class="maint label">Maintenance <strong>' + (maintenanceMargin*100).toFixed(0) + '%</strong></div>';
html += '<div class="init label">Initial <strong>' + (initialMargin*100).toFixed(0) + '%</strong></div>';
html += '</div>';
html += '<div id="marginGraph" class="label">Current Margin - N/A</div>';
html += '<div class="message">If your Current Margin falls below your Maintenance Margin, your account will be <a href="/support/aboutMarginTrading#forcedLiquidation" class="standard">liquidated</a>.</div>';
html += '</td>';
html += '</tr>';
html += '<tr id="marginCallTR"><td colspan="2"><div class="message"><h3><i class="fa fa-exclamation-triangle"></i> <span class="title">Margin Call</span></h3><div class="description">Your collateral balance is dangerously close to the minimum maintenance margin. To avoid a forced liquidation, <a href="javascript:void(0)" onclick="showBalanceTransfer()">transfer additional collateral</a> to your margin account immediately.</div></div></td></tr>';
$("#marginBalancesTable").html(html);
if(parseFloat(data['info']['totalBorrowedValue']) > 0){
$('#marginGraphTR').addClass('enabled');
xPosition = (0-warningScale) * 3.54 + 354;
$('#marginGraph')
.css('background-position', xPosition + 'px 0')
.html('Current Margin <strong>' + currentMargin + '%');
}
}
if (d.marginPositions.notifications.marginCall == true)
criticalMessage('margin');
});
}
function updateMarketDisplay() {
$.getJSON(tickerAPI_url, function(d) {
for (pair in d){
allTickerData[pair]['last'] = d[pair]['last'];
allTickerData[pair]['lowestAsk'] = d[pair]['lowestAsk'];
allTickerData[pair]['highestBid'] = d[pair]['highestBid'];
allTickerData[pair]['percentChange'] = d[pair]['percentChange'];
allTickerData[pair]['baseVolume'] = d[pair]['baseVolume'];
allTickerData[pair]['quoteVolume'] = d[pair]['quoteVolume'];
allTickerData[pair]['isFrozen'] = d[pair]['isFrozen'];
allTickerData[pair]['high24hr'] = d[pair]['high24hr'];
allTickerData[pair]['low24hr'] = d[pair]['low24hr'];
}
setCurrentMarketRowActive();
drawFullMarket();
});
}
function hardRefreshTicker(){
$.getJSON(tickerAPI_url, function(d) {
for (pair in d){
last = d[pair]['last'];
lowestAsk = d[pair]['lowestAsk'];
highestBid = d[pair]['highestBid'];
percentChange = d[pair]['percentChange'];
baseVolume = d[pair]['baseVolume'];
quoteVolume = d[pair]['quoteVolume'];
isFrozen = d[pair]['isFrozen'];
high24hr = d[pair]['high24hr'];
low24hr = d[pair]['low24hr'];
args = [last,lowestAsk,highestBid,percentChange,baseVolume,quoteVolume,isFrozen,high24hr,low24hr];
tickerEvent(args);
}
});
}
function drawFullMarket() {
var d = getCurrentPairDetails();
unsubscribeAll();
orderBookReady = false;
setBookUIstate();
document.title = d.last + ' ' + d.pair + ' Market - Poloniex Bitcoin/Digital Asset Exchange';
var titleString = 'null'; // Shorten the <h1> string if it's getting too long
if(d.name.length > (margin ? 10 : 17)){
titleString = d.name;
} else {
titleString = d.name + (margin ? ' Margin Trading' : ' Exchange');
};
$('.chartTitle .full').html(titleString);
$('.chartTitle .code').html(d.pair);
$('.col.buyCol .head .name').html('BUY ' + secondaryCurrency);
$('.col.buyCol .link').html('<a href=\"/balances#' + primaryCurrency + '\" class=\"standard\">Deposit ' + primaryCurrency + '</a>');
$('#buyAmount').val('');
$('#buyTotal').val('');
$('#buyFee').html('');
$('#stopLimitStopRate').val('');
$('#stopLimitRate').val('');
$('#stopLimitAmount').val('');
$('#stopLimitTotal').val('');
$('.col.sellCol .head .name').html('SELL ' + secondaryCurrency);
$('.col.sellCol .link').html('<a href=\"/balances#' + secondaryCurrency + '\" class=\"standard\">Deposit ' + secondaryCurrency + '</a>');
$('#sellAmount').val('');
$('#sellTotal').val('');
$('.col .primaryCurrency').html(primaryCurrency);
$('.col .secondaryCurrency').html(secondaryCurrency);
$('.hilights .lastPrice .info').html(d.last);
$('.hilights .change .info').html(d.change);
$('.hilights .change .info').removeClass('neg').addClass(d.chPosNeg);
$('.hilights .high .info').html(d.high24hr);
$('.hilights .low .info').html(d.low24hr);
$('.hilights .volume .name1').html(primaryCurrency);
$('.hilights .volume .name2').html(secondaryCurrency);
$('.hilights .volume .info .vol1').html(d.baseVol);
$('.hilights .volume .info .vol2').html(d.quoteVol);
$('.group.zoom').find('.chartButtonActive').removeClass('chartButtonActive');
//Market Specific Alert
if(d.p1=='DAO'){
$('#marketAlert').show().find('.message').html('We have a tool available to <a class="standard" href="/dao">convert your DAO to ETH</a> on the blockchain. The rate of conversion will remain 1 ETH for every 100 DAO.');
} else if (d.p1 in disabledCurrencies){
if (disabledCurrencies[d.p1].length > 0)
var disabledNote = disabledCurrencies[d.p1];
else
var disabledNote = d.p1 + " is currently under maintenance or experiencing wallet/network issues. Deposits and withdrawals will remain disabled until a solution is found, which may require an update from the " + d.p1 + " team. Any updates must be tested and audited before enabling.";
$('#marketAlert').show().find('.message').html(disabledNote);
} else if (d.p1 in currencyNotesPermanent){
$('#marketAlert').show().find('.message').html(currencyNotesPermanent[d.p1]);
} else {
$('#marketAlert').hide().find('.message').html('');
}
refreshAll();
}
function setBookUIstate() {
if (orderBookReady){
$('body').addClass('booksReady');
$('.cols input, .cols button').prop("disabled", false);
} else {
$('body').removeClass('booksReady');
$('.cols input, .cols button').prop("disabled", true);
}
}
function refreshAll() {
resetWebsocket(true);
refreshCandleSticksFirst();
refreshTradeHistory();
refreshMyTrades();
privateInfoFetched = false;
updatePrivateInfo();
}
function initClicks() {
initMarketBox();
//initTrollBox();
initBigChart();
initStopLimits();
initBookControls();
initMarketDepth();
initTradeHistory();
initEscToolpanels();
init3ColActions();
initTradeHistoryButtons();
}
var hashTimer;
function evaluateHash(h) {
// this should happen with a new currencyPair, clicked from marketTables. BUT it's possible we get an invalid pair.
var pair = h.toUpperCase();
pair = pair.substr(1, pair.length); // trim #
if (currencyPairArray.indexOf(pair) != -1) {
// legit
var arr = pair.split('_');
currencyPair = pair;
primaryCurrency = arr[0];
secondaryCurrency = arr[1];
setCurrentMarketRowActive();
updateSwitchLink();
try{
// don't bother if it is the inital load of the page as initMarketTables() will call updateMarketDisplay()
if(!initalLoad) {
// set a timout and wait briefly, just in case the user rapid-fire clicks the back/forward button
hashTimer = setTimeout(function() {
updateMarketDisplay();
saveExchangeSettings();
// log with Google Analytics
ga('send', 'pageview', {
'page': margin ? 'marginTrading' : 'exchange' + h,
'title': secondaryCurrency + '/' + primaryCurrency + ' - Ajax navigation event'
});
}, 450);
} else {
initalLoad = false;
}
} catch(e) {}
}
}
function initHashChanges() {
var h = window.location.hash;
var pair = h.toUpperCase();
pair = pair.substr(1, pair.length); // trim #
// trace('on load hash is [' + h + ']');
// set this so we know not to override it with localStorage or default currencyPair
if (currencyPairArray.indexOf(pair) != -1) {
hasHashCurrencyPair = true;
}
evaluateHash(h);
window.onhashchange = function() {
// trace("hash changed: " + window.location.hash);
clearTimeout(hashTimer);
evaluateHash(window.location.hash);
};
}
function tickerEvent(args, kwargs) {
var newTickerData = {
last: args[1],
lowestAsk: args[2],
highestBid: args[3],
percentChange: args[4],
baseVolume: args[5],
quoteVolume: args[6],
isFrozen: args[7],
high24hr: args[8],
low24hr: args[9]
};
var oldTickerData = (args[0] in allTickerData) ? allTickerData[args[0]] : newTickerData;
allTickerData[args[0]] = newTickerData;
var priceChange = '';
var pairArray = args[0].split("_"),
base = pairArray[0],
quote = pairArray[1];
var pair = args[0].toLowerCase();
var row = $("#marketRow" + pair);
if (row.length == 0)
return;
try{
var sortedColumn = $("#market" + base).DataTable().state().order[0][0];
var updateContents = false;
var updateChange = false;
var redraw = [];
// Unfreeze the market
if(oldTickerData.isFrozen != newTickerData.isFrozen){
if (newTickerData.isFrozen == 1)
row.addClass('frozen');
else
row.removeClass('frozen');
}
// PRICE in market table
var oldLast = oldTickerData.last;
var newLast = newTickerData.last;
if (oldLast != newLast){
priceChange = oldLast > newLast ? 'priceChangeDown' : 'priceChangeUp';
redraw[row.find('.price').html(newLast)[0].cellIndex] = true;
row.addClass(priceChange); // flash a price change color
setTimeout(function(){
row.removeClass(priceChange);
}, 600);
updateContents = true;
}
// VOLUME in market table
var oldTickerVolume = exactRound(oldTickerData.baseVolume,3);
var newTickerVolume = exactRound(newTickerData.baseVolume,3);
if (oldTickerVolume != newTickerVolume){
redraw[row.find('.volume').html(newTickerVolume)[0].cellIndex] = true;
updateContents = true;
}
// % CHANGE in market table
var oldPercentChange = exactRound(oldTickerData.percentChange * 100,2);
var newPercentChange = exactRound(newTickerData.percentChange * 100,2);
if (oldPercentChange != newPercentChange){
var cell = row.find('.change');
if(newPercentChange < 0)
cell.html(newPercentChange).addClass('neg');
else
cell.html('+' + newPercentChange).removeClass('neg');
updateContents = true;
updateChange = true;
redraw[cell[0].cellIndex] = true;
}
if (loggedIn){
var cellB = row.find('.colBalance');
var cellV = cell = row.find('.colEstVal');
var cellB_present = cellB.length > 0;
var cellV_present = cellV.length > 0;
if (cellB_present || cellV_present){
var balance = 0.0;
if (allBalances instanceof Object)
balance = (parseFloat(allBalances.balances[quote]) + parseFloat(allBalances.onOrders[quote])).toFixed(4);
if (cellV_present){
var value = (balance * parseFloat(newTickerData.highestBid)).toFixed(4);
redraw[cellV.html(value)[0].cellIndex] = true;
}
if (cellB_present)
redraw[cellB.html(balance)[0].cellIndex] = true;
}
}
// HIGHLIGHTS - Page heading info box
// Only if the user has this market in view
if(currencyPair.toLowerCase() === pair){
// and data has changed
if (updateContents){
$('#hilights .lastPrice .info').html(newLast);
document.title = newLast + ' ' + secondaryCurrency + '/' + primaryCurrency + ' Market - Poloniex Bitcoin/Digital Asset Exchange';
}
if (updateChange){
if(newPercentChange < 0)
$('#hilights .change .info').html(newPercentChange + '%').addClass('neg');
else
$('#hilights .change .info').html(newPercentChange + '%').removeClass('neg');
}
$('#hilights .high .info').html(newTickerData.high24hr);
$('#hilights .low .info').html(newTickerData.low24hr);
$('#hilights .volume .info .vol1').html(newTickerData.baseVolume);
$('#hilights .volume .info .vol2').html(newTickerData.quoteVolume);
}
// Freeze the market
if (newTickerData.isFrozen == 1) {
row.addClass('frozen');
row.find('.price').html('&nbsp;FROZEN');
row.find('.volume').empty();
row.find('.change').empty();
redraw[sortedColumn] = true; // Force redraw
}
if (sortedColumn in redraw && redraw[sortedColumn])
setTimeout(function(){
$("#market" + base).DataTable().row(row).invalidate().draw();
},1);
else if (updateContents)
$("#market" + base).DataTable().row(row).invalidate();
} catch (err) { console.log(err); }
}
var orderBookCache,orderBookReady,orderBookTotals,orderBookRates,orderBookFixedRates;
function resetOrderBookCache(){
orderBookReady = false;
orderBookCache = {'asks': {}, 'bids': {}};
orderBookFixedRates = {'asks': {}, 'bids': {}};
orderBookRates = {asks: [], bids: []};
orderBookTotals = {'asks': 0.0, 'bids': 0.0};
marketEventInProgress = false;
seq = 0;
}
function changeOrderBookPrecision(newPrecision){
orderBookReady = false;
orderBookPrecision = Math.max(newPrecision,minPrecision);
orderBookPrecisionIncrement = 1 / Math.pow(10,orderBookPrecision);
orderBookFixedRates = {'asks': {}, 'bids': {}};
for (var side in orderBookCache){
var isAsk = side == 'asks';
for (var rate in orderBookCache[side]){
var amountFloat = parseFloat(orderBookCache[side][rate].amount);
var totalFloat = parseFloat(orderBookCache[side][rate].total);
var fixedRate = fixRate(rate,isAsk);
if (!(fixedRate in orderBookFixedRates[side]))
orderBookFixedRates[side][fixedRate] = {};
orderBookFixedRates[side][fixedRate][rate] = [amountFloat,totalFloat];
}
}
writeBuySellOrdersTable('asks');
writeBuySellOrdersTable('bids');
orderBookReady = true;
processMarketQueue();
}
function setMinPrecision(){
var bid = parseFloat(allTickerData[currencyPair].highestBid);
minPrecision = 2;
if (bid < 0.000001)
minPrecision = 8;
else if (bid < 0.0001)
minPrecision = 6;
else if (bid < 0.01)
minPrecision = 4;
var groupToggle = $id("groupToggle");
var groupPoints = $id("groupPoints");
limitPrecision = minPrecision != 8 && groupToggle.checked;
groupToggle.checked = limitPrecision;
groupToggle.disabled = minPrecision == 8;
if (groupToggle.checked)
removeClass(groupPoints,"disabled");
else
addClass(groupPoints,"disabled");
if (Number(groupPoints.value) < minPrecision)
groupPoints.value = Math.min(minPrecision,6);
Array.prototype.forEach.call(groupPoints.getElementsByTagName("option"),function(item){
item.disabled = (Number(item.value) < minPrecision);
if (item.disabled && item.selected)
item.selected = false;
});
changeOrderBookPrecision(orderBookPrecision);
}
function fixRate(rate,isAsk){
if (limitPrecision){
var split = rate.split(".");
rate = split[0] + "." + split[1].substr(0, orderBookPrecision);
if (isAsk && split[1].substr(orderBookPrecision) > 0)
rate = (parseFloat(rate) + orderBookPrecisionIncrement).toFixed(orderBookPrecision);
}
return rate;
}
// Enters an order from either the push or the pull API into our order book object, returning the key (rate)
function cacheOrder(order,side,push,rates_i){
if (push === true){
var rate = order.rate;
var amount = order.amount;
var amountFloat = parseFloat(amount);
} else {
var rate = order[0];
var amountFloat = push === 0 ? parseFloat(order[1]) : order[1];
var amount = push === 0 ? order[1] : amountFloat.toFixed(8);
}
var totalFloat = parseFloat(rate)*amountFloat;
var total = totalFloat.toFixed(8);
// Update totals
if (side == 'bids'){
if (rate in orderBookCache[side])
orderBookTotals[side] -= parseFloat(orderBookCache[side][rate].total);
orderBookTotals[side] += totalFloat;
} else {
if (rate in orderBookCache[side])
orderBookTotals[side] -= parseFloat(orderBookCache[side][rate].amount);
orderBookTotals[side] += amountFloat;
}
if (typeof rates_i == "undefined"){
if (orderBookRates[side].indexOf(rate) === -1){
if (side == 'bids'){
for (var i in orderBookRates[side])
if (orderBookRates[side][i]-rate < 0)
break;
} else {
for (var i in orderBookRates[side])
if (orderBookRates[side][i]-rate > 0)
break;
}
orderBookRates[side].splice(i,0,rate);
}
} else {
orderBookRates[side][rates_i] = rate;
}
orderBookCache[side][rate] = {rate: rate,amount: amount,total: total,i: rates_i};
if (limitPrecision){
var fixedRate = fixRate(rate,side == 'asks');
if (!(fixedRate in orderBookFixedRates[side]))
orderBookFixedRates[side][fixedRate] = {};
orderBookFixedRates[side][fixedRate][rate] = [amountFloat,totalFloat];
}
return rate;
}
// Removes an order from our order book object
function uncacheOrder(side,rate){
var i = orderBookRates[side].indexOf(rate);
if (i >= 0){
orderBookRates[side].splice(i,1);
for (i=i; i < orderBookRates[side].length; i++)
orderBookCache[side][orderBookRates[side][i]].i = i;
} else
console.log(rate + " not found in " + side + " book");
if (rate in orderBookCache[side]){
orderBookTotals[side] -= parseFloat(side == 'bids' ? orderBookCache[side][rate].total : orderBookCache[side][rate].amount);
delete orderBookCache[side][rate];
if (limitPrecision){
var fixedRate = fixRate(rate,side == 'asks');
if (Object.keys(orderBookFixedRates[side][fixedRate]).length > 1)
delete orderBookFixedRates[side][fixedRate][rate];
else
delete orderBookFixedRates[side][fixedRate];
}
} else {
console.log(rate + " not found in " + side + " index");
}
}
function orderBookRow(order,side){
return '<tr id="' + order.rate + side + '">'
+ '<td class="orderRate">' + order.rate + '</td>'
+ '<td class="orderAmount">' + order.amount + '</td>'
+ '<td class="orderTotal">' + order.total + '</td>'
+ '<td class="orderSum">' + order.total + '</td>'
+ '</tr>';
}
var orderBookTotalsIndex = {asks: 99999, bids: 99999};
function updateTotals(side,rowIndex,execute){
if (execute !== true){
orderBookTotalsIndex[side] = Math.min(orderBookTotalsIndex[side],rowIndex);
return;
} else if (orderBookTotalsIndex[side] >= 99999 && rowIndex >= 0) {
return;
}
rowIndex = rowIndex == -1 ? 0 : orderBookTotalsIndex[side]; // -1 means do the whole thing nao
orderBookTotalsIndex[side] = 99999;
var rows = document.getElementById(side + "TableBody").rows;
if (rowIndex < 0)
rowIndex = 0;
else if (rowIndex > rows.length)
rowIndex = rows.length;
var total = rowIndex < 1 ? 0.0 : parseFloat(rows[rowIndex-1].cells[3].innerHTML);
for (var i=rowIndex; i<rows.length; i++)
rows[i].cells[3].innerHTML = fix(total += parseFloat(rows[i].cells[2].innerHTML));
}
// Insert a new row from the order book cache into the order book table
function insertOrder(side,rate,order){
var buySide = side == 'bids';
if (typeof order == "undefined")
order = orderBookCache[side][rate];
var rowHTML = orderBookRow(order,side);
var table = document.getElementById(side + "TableBody");
var len = table.rows.length;
var reversed = false;
// Find the row number for insertion
if (reversed){
for (var i=table.rows.length-1; i>=0; i--)
if ((buySide && rate > parseFloat(table.rows[i].id)) ||
(!buySide && rate < parseFloat(table.rows[i].id)))
break;
} else {
for (var i=0; i<table.rows.length; i++)
if ((buySide && rate > parseFloat(table.rows[i].id)) ||
(!buySide && rate < parseFloat(table.rows[i].id)))
break;
}
var top = (typeof i == 'undefined') || (!reversed && i == 0) || (reversed && i == table.rows.length-1);
i = top ? (reversed ? table.rows.length-1 : 0) : parseInt(i);
var row = table.insertRow(i + (reversed ? 1 : 0));
row.innerHTML = rowHTML;
row.id = rate + side;
row.onclick=function(){orderBookClick(side,this)};
row.className = "newRow";
if (table.rows.length > orderbookDisplayLimit)
table.deleteRow(reversed ? 0 : table.rows.length-1);
if (table.rows.length != len)
reinitOrderbookPane(buySide ? "buy" : "sell");
updateTotals(side,i-1);
}
function sumOrderRow(side,rate){
var amount = 0;
var total = 0;
for (var r in orderBookFixedRates[side][rate]){
amount += orderBookFixedRates[side][rate][r][0];
total += orderBookFixedRates[side][rate][r][1];
}
return {rate: rate, amount: fix(amount), total: fix(total)};
}
// Update a row in the order book table
function updateOrder(side,rate){
var order = limitPrecision ? sumOrderRow(side,rate) : orderBookCache[side][rate];
var row = $id(rate + side);
row.innerHTML = orderBookRow(order,side);
updateTotals(side,row.rowIndex-1);
}
function asc(a,b){
return parseFloat(a) - parseFloat(b);
}
function desc(a,b){
return parseFloat(b) - parseFloat(a);
}
// Remove a row from the order book table (NOT from the cache)
function removeOrder(side,rate){
var table = $id(side + "TableBody");
var i = table.rows.length-1;
var reversed = false;
if (limitPrecision){
var fixedRates = Object.keys(orderBookFixedRates[side]).sort(side == "asks" ? asc : desc);
if (fixedRates.length > i){
var nextRate = fixedRates[i];
var row = table.insertRow(reversed ? 0 : table.rows.length);
row.id = nextRate + side;
row.innerHTML = orderBookRow(sumOrderRow(side,nextRate),side);
}
} else if (orderBookRates[side].length>i){
var row = table.insertRow(reversed ? 0 : table.rows.length);
var nextRate = orderBookRates[side][i]
row.id = nextRate + side;
row.innerHTML = orderBookRow(orderBookCache[side][nextRate],side);
}
var row = document.getElementById(rate + side);
var rowIndex = row.rowIndex;
table.removeChild(row);
if (table.rows.length-1 != i)
reinitOrderbookPane(side == 'bids' ? 'buy' : 'sell');
updateTotals(side,rowIndex-1);
}
function marketEvent(args, kwargs){
var seqInt = parseInt(kwargs.seq);
if (seqInt > seq)
marketEventQueue[kwargs.seq] = args;
if (liveOrderBooks && orderBookReady && seqInt == seq+1)
processMarketQueue();
else if (orderBookReady && Object.keys(marketEventQueue).length > 200)
completelyResetWebsocket();
}
var marketQueueTimeout = false;
function processMarketQueue(){
if (typeof marketEventQueue != "object"){
marketEventQueue = {};
completelyResetWebsocket();
}
if (marketEventInProgress || !(seq+1 in marketEventQueue))
return;
marketEventInProgress = true;
var d = marketEventQueue[++seq];
delete marketEventQueue[seq];
processMarketEvent(d);
if (Object.keys(marketEventQueue).length>0){
marketEventInProgress = false;
return processMarketQueue();
}
updateTotals('asks',0,true);
updateTotals('bids',0,true);
marketEventInProgress = false;
}
function processMarketEvent(args) {
var tradeMade = false;
var sideChanged = {asks: false, bids: false};
try{
for (argX = 0; argX < args.length; argX++) {
var data = args[argX];
var type = data['type'];
if (data['type'] == "newTrade") {
tradeMade = true;
var entry = data['data'];
var tradeID = entry['tradeID'];
if (entry['type'] == 'buy') {
typeString = "<span class='buyClass'>Buy</span>";
} else {
typeString = "<span class='sellClass'>Sell</span>";
}
var row = '<td class="date"><span class="year">' + entry['date'].substring(0, 5) + '</span>' + entry['date'].substring(5,16) + '<span class="seconds">' + entry['date'].substring(16) + '</span></td>';
row += '<td class="type">' + typeString + '</td>';
row += '<td>' + exactRound(entry['rate'], maxDecimals) + '</td>';
row += '<td>' + exactRound(entry['amount'], maxDecimals) + '</td>';
row += '<td>' + exactRound(entry['total'], maxDecimals) + '</td>';
var tradeHistoryTable = document.getElementById('tradeHistoryTableBody');
var newRow = tradeHistoryTable.insertRow(0);
newRow.className = "newRow";
newRow.innerHTML = row;
tradeHistoryTable.deleteRow(tradeHistoryTable.rows.length-1);
try {
var ch_i = allChartData[chartType]['candleStick'].length-1;
var stick = allChartData[chartType]['candleStick'][ch_i];
stick.close = parseFloat(entry['rate']);
stick.high = Math.max(stick.high,stick.close);
stick.low = Math.min(stick.low,stick.close);
stick.volume += parseFloat(entry['total']);
allChartData[chartType]['candleStick'][ch_i] = stick;
} catch (cerr) {
}
}
if (type == "orderBookModify" || type == "orderBookRemove") {
var i = argX;
order = data['data'];
side = order['type'] + 's';
rate = order.rate;
sideChanged[side] = true;
if (type == 'orderBookModify')
cacheOrder(order,side,true);
else
uncacheOrder(side,rate);
fixedRate = limitPrecision ? fixRate(rate,side == "asks") : rate;
row = document.getElementById(fixedRate + side);
if (row === null){
if (type == 'orderBookModify'){
lastRate = parseFloat(document.getElementById(side + 'TableBody')['lastChild'].id);
if ((side == 'asks' && parseFloat(fixedRate) < lastRate) ||
(side == 'bids' && parseFloat(fixedRate) > lastRate)){
if (limitPrecision)
insertOrder(side,fixedRate,{rate: fixedRate, amount: order.amount, total: orderBookCache[side][rate].total});
else
insertOrder(side,rate);
}
}
} else {
if (type == 'orderBookRemove' && !(limitPrecision && (fixedRate in orderBookFixedRates[side])))
removeOrder(side,fixedRate);
else
updateOrder(side,fixedRate);
}
}
}
} catch (e) {
console.log(e);
marketEventQueue = {};
return completelyResetWebsocket();
}
if (Object.keys(marketEventQueue).length>1)
return;
if (sideChanged.asks)
document.getElementById("asksTotal").innerHTML = orderBookTotals.asks.toFixed(8);
if (sideChanged.bids)
document.getElementById("bidsTotal").innerHTML = orderBookTotals.bids.toFixed(8);
if (orderBookRates.bids[0] >= orderBookRates.asks[0]){
marketEventQueue = {}
return completelyResetWebsocket();
}
if (updatesPaused)
$(".newRow").removeClass("newRow");
else if (tradeMade)
updateChart = true;
}
function alertEvent(args, kwargs) {
data = args[0];
if (data['type']=="notice"){
refreshNoticesBoard();
}
if (data['type']=="alert"){
$("#alertsTab .msg").html(data['message']);
$("#alertsTab .date").html("Posted by " + data['postedBy'] + " on " + data['date']);
alertID = data['id'];
$("#alertsTab").removeClass( "dismissed" ).addClass( "closed" );
}
if (data['type']=='announcement'){
/* if (data['message']=='pfft'){
var announcementHTML = '';
announcementHTML += '<div class="message">pfft! to begin soon. Get those bags ready.</div>';
$("#trollboxAnnouncement .row").html(announcementHTML);
targetTime = data['targetTime'];
countdownIntervalId = setInterval(updateCountdown,1000);
$("#trollboxAnnouncement").css("display", "block");
}*/
}
}
function heartbeatEvent (args, kwargs){
lastHeartbeat = Math.floor(Date.now()/1000);
}
function footerEvent (args, kwargs){
var footerData = args[0];
$("#serverTime").html(footerData['serverTime']);
$("#usersOnline").html(footerData['usersOnline']);
for (var vc in footerData.volume)
$("#" + vc.toLowerCase() + "VolumeFooter").html(footerData.volume[vc].split(".")[0]);
}
function userEvent (args, kwargs){
}
function unsubscribe(channel,conn){
if (conn.readyState == 1 && channel > 0){
if (channel == marketChannel)
marketChannel = 0;
conn.send(JSON.stringify({command: "unsubscribe", channel: channel}));
if ('subscriptions' in conn)
delete conn.subscriptions[channel];
} else if (marketSubscription instanceof autobahn.Subscription){
marketSubscription.unsubscribe();
marketSubscription = null;
}
}
function unsubscribeAll(){
if ('conn' in window && window.conn.readyState != 0)
for (var channel in window.conn.subscriptions)
unsubscribe(channel,window.conn);
}
function webSockets_subscribe(channel,conn){
if (conn.readyState == 1){
var params = {command: "subscribe",channel: channel};
if (channel == 1000)
params['userID'] = usid;
conn.send(JSON.stringify(params));
}
}
function startOrderBook(){
if (quickOrderBookLoading)
return setTimeout(startOrderBook,250);
setMinPrecision();
orderBookReady = true;
setBookUIstate();
fullOrderBookLoading = false;
processMarketQueue();
refreshDepthChart();
}
var webSocketConnected = false;
var webSocketConnecting = true;
var webSocketConnectionID = 0;
var marketChannel = 0;
var logseq = 10;
function initWebSockets_new(){
if (webSocketConnected)
return;
webSocketConnected = true;
webSocketConnecting = true;
window.conn = new WebSocket('wss://api2.poloniex.com');
window.conn['subscriptions'] = {};
window.conn.onopen = function(e){
webSocketConnecting = false;
lastHeartbeat = Math.floor(Date.now()/1000);
window.conn['connectionID'] = ++webSocketConnectionID;
if (loggedIn && !isLocal)
webSockets_subscribe(1000,e.target);
webSockets_subscribe(1001,e.target);
webSockets_subscribe(1002,e.target);
webSockets_subscribe(1003,e.target);
resetOrderBookCache();
webSockets_subscribe(currencyPair,e.target);
window.conn['keepAlive'] = setInterval(function(){
try{
window.conn.send(".");
} catch (err) {
resetWebsocket();
}
},60000);
}
window.conn.onmessage = function(e){
if (e.target.connectionID != webSocketConnectionID)
return e.target.close();
lastHeartbeat = Math.floor(Date.now()/1000);
if (e.data.length == 0)
return;
var msg = JSON.parse(e.data);
if (msg[1] == 1)
return e.target.subscriptions[msg[0]] = true;;
if ('error' in msg)
return console.log(msg);
if (msg[1] === 0)
return delete e.target.subscriptions[msg[0]];
switch (msg[0]){
case 1000:
for (var i in msg[2]){
var arg = msg[2][i];
switch (arg[0]){
case "b":
if (arg[2] == "e"){
var c = isNaN(Number(arg[1])) ? arg[1] : markets_currencies.byID[arg[1]].symbol;
allBalances.balances[c] = fix(parseFloat(allBalances.balances[c]) + parseFloat(arg[3]));
if (c == primaryCurrency)
$("#primaryBalance,#stopLimitPrimaryBalance").html(allBalances.balances[c]);
else if (c == secondaryCurrency)
$("#secondaryBalance,#stopLimitSecondaryBalance").html(allBalances.balances[c]);
}
break;
case "o":
if (arg[2] === "0.00000000"){
for (var oi in openOrders.limit){
if (openOrders.limit[oi].orderID == arg[1]){
delete openOrders.limit[oi];
break;
}
}
$("#myOrdersTable").DataTable().row("#orderRow-" + arg[1]).remove().draw();
} else {
var orderRow = $("#orderRow-" + arg[1]);
orderRow.find("td.amount").html(arg[2]);
orderRow.find("td.total").html( fix(parseFloat(arg[2]) * parseFloat(orderRow.find("td.rate").html())) );
}
break;
case "n":
if (arg[1] != marketChannel)
break;
var item = {orderID: arg[2],
type: arg[3] == 1 ? "buy" : "sell",
rate: arg[4],
amount: arg[5],
total: fix(parseFloat(arg[4]) * parseFloat(arg[5])),
date: arg[6]};
openOrders.limit.push(item);
writeMyOpenOrdersTable(openOrders);
break;
case "t":
break;
}
}
return;
case 1001:
//trollboxEvent(msg);
break;
case marketChannel:
var args = [];
var kwargs = {seq: msg[1]};
if (logseq){
if (logseq-- <= 0)logseq=false;
console.log(kwargs.seq);
}
for (var i in msg[2]){
var arg = msg[2][i];
switch (arg[0]){
case "o":
args.push({
type: "orderBook" + (arg[3] === "0.00000000" ? "Remove" : "Modify"),
data: { type: (arg[1] == 1 ? "bid" : "ask"),
rate: arg[2],
amount: arg[3]
}
});
break;
case "t":
args.push({
type: "newTrade",
data: { tradeID: arg[1],
type: (arg[2] == 1 ? "buy" : "sell"),
rate: arg[3],
amount: arg[4],
total: fix(parseFloat(arg[3]) * parseFloat(arg[4])),
date: timestampToDate(arg[5],true)
}
});
break;
}
}
marketEvent(args, kwargs);
break;
case 1002:
msg[2][0] = markets.byID[msg[2][0]].currencyPair;
tickerEvent(msg[2]);
break;
case 1003:
$id("serverTime").innerHTML = msg[2][0];
$id("usersOnline").innerHTML = msg[2][1];
for (var vc in msg[2][2])
$("#" + vc.toLowerCase() + "VolumeFooter").html(msg[2][2][vc].split(".")[0]);
break;
case 1010:
// Heartbeat
break;
case 2000:
if (msg[2][1] == "cancelOrder" || msg[2][1] == "cancelTriggerOrder"){
} else {
$("#result").html(msg[2][2]['response']).attr("noRefresh",true);
showAlert();
}
break;
default:
if (msg[0] > 0 && msg[0] < 1000){
if (msg[2][0][0] == "i"){
var marketInfo = msg[2][0][1];
if (marketInfo.currencyPair != currencyPair)
break;
marketChannel = msg[0];
window.conn.subscriptions[marketChannel] = true;
fullOrderBookLoading = true;
seq = msg[1];
logseq = false;
var d = marketInfo.orderBook;
for (var side in [0,1]){
var ii = 0;
for (var i in d[side])
cacheOrder([i,d[side][i]],(side == 0 ? 'asks' : 'bids'),0,ii++);
}
for (var i in marketEventQueue)
if (parseInt(i) <= seq)
delete marketEventQueue[i];
startOrderBook();
}
}
break;
}
}
window.conn.onerror = function(e){
if (e.target.connectionID != webSocketConnectionID)
e.target.close();
else
unsubscribeAll();
}
window.conn.onclose = function(e){
if (typeof e == "object" && 'keepAlive' in e.target){
clearInterval(e.target.keepAlive);
if (e.target.connectionID != webSocketConnectionID)
return true;
if (e.target.readyState == 1)
return e.target.close();
}
unsubscribeAll();
window.conn.subscriptions = {};
marketEventQueue = {};
marketChannel = 0;
lastHeartbeat = Math.floor(Date.now()/1000) + 2;
setTimeout(function(){
webSocketConnected = false;
initWebSockets_new();
}, e === true ? 250 : 2000);
}
}
function initWebSockets(refresh) {
if (newWebSockets)
return initWebSockets_new();
var wsuri = "wss://api.poloniex.com";
marketEventQueue = {};
if (typeof refresh == "undefined")
refresh = false;
window.connection = new autobahn.Connection({
url: wsuri,
realm: "realm1"
});
window.connection.onopen = function (session) {
session.subscribe(currencyPair, marketEvent).then(function(subscription){
marketSubscription = subscription;
if (refresh === true)
refreshOrderBook_br();
});
//session.subscribe('trollbox', trollboxEvent);
session.subscribe('ticker', tickerEvent);
session.subscribe('alerts', alertEvent);
session.subscribe('heartbeat', heartbeatEvent);
session.subscribe('footer', footerEvent);
}
window.connection.onclose = function(){}
window.connection.open();
}
function resetWebsocket(refresh) {
if ('conn' in window)
return window.conn.close();
if (typeof window.connection !== 'undefined' && window.connection.session !== null)
window.connection.close();
initWebSockets(refresh);
}
function completelyResetWebsocket(){
lastHeartbeat = Math.floor(Date.now()/1000);
setTimeout(refreshTradeHistory,0);
//setTimeout(hardRefreshTrollbox,0);
setTimeout(hardRefreshTicker,0);
if ('conn' in window){
resetWebsocket();
} else if ('connection' in window && window.connection.session !== null){
window.connection.close();
initWebSockets(true);
}
}
function checkHeartbeat(){
if (updatesPaused || webSocketConnecting)
return;
if ((Math.floor(Date.now()/1000) - lastHeartbeat) > (newWebSockets ? 10 : 10) || (Object.keys(marketEventQueue).length > 100 && !(seq+1 in marketEventQueue)))
completelyResetWebsocket();
}
function checkAllJSLoaded() {
if (marketTablesJsLoaded === true && chartsJsLoaded === true && privateInfoFetched === true) {
clearInterval(loadCheckInterval);
loadExchangeSettings();
initClicks();
initNonMarketTables();
getTickerInfo(); // Which then calls > initMarketTables() > updateMarketDisplay() > refreshAll()
initCharts_br_js();
//initWebSockets();
$( window ).unload(function() { saveExchangeSettings(); });
}
}
function submitStopLimitOrder() {
hideStopLimitAlert();
showProgressBar();
url = '/private.php';
command = $('#stopLimitCommand').val();
if (margin)
command = "marginS" + command.substring(1, command.length);
var posting = $.post(url, { currencyPair: currencyPair, rate: $('#stopLimitRate').val(), amount: $('#stopLimitAmount').val(), stopRate: $('#stopLimitStopRate').val(), command: command});
posting.done(function (data) {
var content = $(data);
$("#result").empty().append(content);
showAlert();
updatePrivateInfo();
setTimeout(updatePrivateInfo, 2100);
});
}
$("#stopLimitForm").submit(function (event) {
event.preventDefault();
if ($("#dimmer").is(":visible"))
return $("#alertDivOK").click();
if (document.getElementById('stopLimitAmount').value < 0.01)
return showAlert("Amount must be greater than 0.01.");
if (document.getElementById('stopLimitRate').value < 0.00000001)
return showAlert("Limit must be greater than zero.");
if (document.getElementById('stopLimitStopRate').value < 0.00000001)
return showAlert("Stop must be greater than zero.");
var stopLimitText = "If the ";
if ($('#stopLimitCommand').val() == "stopLimitBuy") {
stopLimitText += "lowest ask rises to or above ";
} else {
stopLimitText += "highest bid drops to or below ";
}
stopLimitText += parseFloat($('#stopLimitStopRate').val()) + " " + primaryCurrency + ", an order to ";
if ($('#stopLimitCommand').val() == "stopLimitBuy") {
stopLimitText += "buy ";
} else {
stopLimitText += "sell ";
}
stopLimitText += parseFloat($('#stopLimitAmount').val()) + " " + secondaryCurrency + " at a price of " + parseFloat($('#stopLimitRate').val()) + " " + primaryCurrency + " will be placed.";
$("#stopLimitAlertText").empty().append(stopLimitText);
showStopLimitAlert();
});
$("#buyForm").submit(function (event) {
event.preventDefault();
if ($("#dimmer").is(":visible"))
return $("#alertDivOK").click();
if (Number(document.getElementById('buyAmount').value) * Number(document.getElementById('buyRate').value) < 0.0001) {
$("#result").empty().append("Total must be at least 0.0001.");
showAlert();
return;
}
if (document.getElementById('buyRate').value < 0.00000001) {
$("#result").empty().append("Price must be greater than zero.");
showAlert();
return;
}
showProgressBar();
var $form = $(this),
url = '/private.php';
params = { currencyPair: currencyPair,
rate: $('#buyRate').val(),
amount: $('#buyAmount').val(),
command: (margin ? 'marginBuy' : 'buy')};
if (margin)
params['maxRate'] = $("#buyMaxRate").val() === undefined ? 0.005 : $("#buyMaxRate").val();
if (webSocketCall(params))
return true;
var posting = $.post(url, params);
posting.done(function (data) {
var content = $(data);
$("#result").empty().append(content);
showAlert();
updatePrivateInfo();
});
});
$("#sellForm").submit(function (event) {
event.preventDefault();
if ($("#dimmer").is(":visible"))
return $("#alertDivOK").click();
if (Number(document.getElementById('sellAmount').value) * Number(document.getElementById('sellRate').value) < 0.0001) {
$("#result").empty().append("Total must be at least 0.0001.");
showAlert();
return;
}
if (document.getElementById('sellRate').value < 0.00000001) {
$("#result").empty().append("Price must be greater than zero.");
showAlert();
return;
}
showProgressBar();
var $form = $(this),
url = '/private.php';
params = { currencyPair: currencyPair,
rate: $('#sellRate').val(),
amount: $('#sellAmount').val(),
command: (margin ? 'marginSell' : 'sell')};
if (margin)
params['maxRate'] = $("#sellMaxRate").val() === undefined ? 0.005 : $("#sellMaxRate").val();
if (webSocketCall(params))
return true;
var posting = $.post(url, params);
posting.done(function (data) {
var content = $(data);
$("#result").empty().append(content);
showAlert();
updatePrivateInfo();
});
});
function closeMarginPosition(currencyPair){
$("#confirmDivMessage").html("This will close your margin position with a market order. Are you sure?");
$("#confirmDivOK").unbind('click');
$("#confirmDivCancel").unbind('click');
$("#confirmDivOK").click(function(){executeCloseMarginPosition(currencyPair);});
$("#confirmDivCancel").click(hideConfirmDiv);
showConfirmDiv();
}
function executeCloseMarginPosition(currencyPair){
hideConfirmDiv(true);
showProgressBar();
$.post("/private.php",{command: "closeMarginPosition",currencyPair: currencyPair}).done(function(data){
$("#result").html(data);
showAlert();
updatePrivateInfo();
});
}
function pauseUpdates(){
if (windowActive)return;
if (updatesPaused)return;
updatesPaused = true;
$(".newRow").removeClass("newRow");
if (liveOrderBooks)
setOrderBookUpdateInterval(2000);
if ('conn' in window && 1001 in window.conn.subscriptions)
unsubscribe(1001,window.conn);
}
function resumeUpdates(){
clearTimeout(pauseTimeout);
if (!updatesPaused)return;
updatesPaused = false;
$(".newRow").removeClass("newRow");
if ($id("throttleToggle").checked)
$("#throttleFreq").change();
else
setOrderBookUpdateInterval(0);
refreshChart();
//setTimeout(hardRefreshTrollbox,0);
if (newWebSockets)
webSockets_subscribe(1001,window.conn);
}
var pauseTimeout;
function blur(){
windowActive = false;
pauseTimeout = setTimeout(pauseUpdates, 60000);
};
function focus(){
windowActive = true;
resumeUpdates();
};
var orderBookUpdateInterval;
function setOrderBookUpdateInterval(ms){
clearInterval(orderBookUpdateInterval);
liveOrderBooks = ms == 0;
if (liveOrderBooks)
processMarketQueue();
else
orderBookUpdateInterval = setInterval(processMarketQueue, ms);
}
$(document).ready(function() {
//resetOrderBookCache();
initHashChanges();
updatePrivateInfo();
clearInterval(loadCheckInterval);
loadCheckInterval = setInterval(checkAllJSLoaded, 100);
$(document).keyup(function(e){
var keyCode = e.which;
if (e.shiftKey && e.altKey && keyCode >= 48 && keyCode <= 53){
e.preventDefault();
var t = (keyCode - 48);
if (t)
$('#throttleFreq').val(t);
$('#throttleToggle').prop("checked",!t).click();
}
});
setInterval(updatePrivateInfo,privateRefreshInterval);
setInterval(refreshCandleSticks,candleStickRefreshInterval);
setInterval(refreshDepthChart,depthChartRefreshInterval);
setInterval(executeReinits, 1000);
setInterval(checkHeartbeat, 10000);
setInterval(function(){
if (updateChart){
updateChart = false;
refreshChart();
}
}, 1000);
if (/*@cc_on!@*/false) { // check for Internet Explorer
document.onfocusin = focus;
document.onfocusout = blur;
} else {
window.onfocus = focus;
window.onblur = blur;
}
} );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment