Skip to content

Instantly share code, notes, and snippets.

@kroitor
Created April 21, 2020 23:02
Show Gist options
  • Save kroitor/56e454223d4ee82e1b45d66e744825b3 to your computer and use it in GitHub Desktop.
Save kroitor/56e454223d4ee82e1b45d66e744825b3 to your computer and use it in GitHub Desktop.
"use strict";
/* ------------------------------------------------------------------------ */
const blessed = require ('blessed')
, ccxt = require ('ccxt')
, log = require ('ololog')
, ansi = require ('ansicolor').nice
, StackTracey = require ('stacktracey')
, asciichart = require ('asciichart')
, asTable = require ('as-table').configure ({
delimiter: ' | '.lightGray.dim,
right: true,
title: x => String (x).lightGray,
dash: '-'.lightGray.dim
})
/* ------------------------------------------------------------------------ */
const printErr = err => {
if (('actual' in err) && ('expected' in err)) {
log.bright.red.error ('[AssertionError] ' + err.message, '\n')
log.red.error.indent (1) ('actual: ', err.actual, '\n')
log.green.error.indent (1) ('expected:', err.expected, '\n')
log.bright.red.error.indent (1) (new StackTracey (err).pretty)
} else {
log.bright.red.error ('\n', err)
}
process.exit (1)
}
/* ------------------------------------------------------------------------ */
const enableRateLimit = true
const exchanges = {
kraken: new ccxt.kraken ({ enableRateLimit }),
gdax: new ccxt.gdax ({ enableRateLimit }),
}
/* ------------------------------------------------------------------------ */
const id = 'kraken'
const balances = {}
const renderDelay = 1000
const cursorUp = '\u001b[1A'
const retryDelay = 5000
const symbol = 'BTC/USD'
const timeframe = '1m'
let output = undefined
let lastPrice = undefined
let firstPrice = undefined
const exchange = new ccxt[id] ({ enableRateLimit })
/* ------------------------------------------------------------------------ */
// Create a screen object.
const screen = blessed.screen ()
screen.title = [ 'CCXT', exchanges[id].name, symbol, timeframe ].join (' ')
var chart = blessed.box ({
top: 'center',
left: 'center',
width: 150,
height: 34,
// content: 'Hello {bold}world{/bold}!',
// tags: true,
border: {
type: 'line'
},
style: {
fg: 'white',
bg: 'black',
border: {
fg: '#224422'
},
hover: {
bg: 'blue'
}
}
})
screen.append (chart);
chart.setLine (1, 'Loading...'.dim)
// // If our box is clicked, change the content.
// box.on ('click', function (data) {
// box.setContent ('{center}Some different {red-fg}content{/red-fg}.{/center}')
// screen.render ()
// })
// // If box is focused, handle `enter`/`return` and give us some more content.
// box.key ('enter', function (ch, key) {
// box.setContent ('{right}Even different {black-fg}content{/black-fg}.{/right}\n')
// box.setLine (1, 'bar')
// box.insertLine (1, 'foo')
// screen.render ()
// })
// chart.key ('f1', function (ch, key) {
// chart.style.bg = 'blue'
// // screen.render ()
// })
// Quit on Escape, q, or Control-C.
screen.key (['escape', 'q', 'C-c'], function (ch, key) {
return process.exit (0)
});
// Focus our element.
chart.focus ()
/* ------------------------------------------------------------------------ */
;(async () => {
/* ..................................................................... */
const poll = new Promise (async (resolve, reject) => {
await exchange.loadMarkets ()
if (!exchange.symbols.includes (symbol))
throw new Error (id + ' does not support ' + symbol)
while (true) {
try {
const closingPrice = 4 // [ timestamp, open, high, low, close, volume ]
const ohlcv = await exchange.fetchOHLCV (symbol, timeframe)
firstPrice = ohlcv[0][closingPrice]
lastPrice = ohlcv[ohlcv.length - 1][closingPrice]
const series = ohlcv.slice (-120).map (x => x[closingPrice])
output = asciichart.plot (series, { height: 30, padding: ' ' }).split ('\n')
// dirty highlight hack, as formatting is not supported by asciichart (for now)
output = output.map (line => {
const openSymbolIndex = line.indexOf ('┼')
const delimiterIndex = Math.max (openSymbolIndex, line.indexOf ('┤'))
const openSymbolFound = openSymbolIndex >= 0
line = line.slice (0, -1)
const price = line.slice (0, 7)
let lastCharacter = line.slice (-1)
if (openSymbolFound)
line = firstPrice.toFixed (2).white + line.slice (7).white
else
line = (price + line.slice (7, 9)).green + line.slice (9)
let currentPriceLine = false
if (lastCharacter == '╰' || lastCharacter == '╭' || lastCharacter == '─') {
currentPriceLine = true
}
line = line + ((currentPriceLine) ? ('┼ '.white + lastPrice.toFixed (2).white) : ('├ '.green + price.green))
return ' ' + line
// return openSymbolFound ? : line.slice
})
} catch (e) {
// log.error (e)
await ccxt.sleep (retryDelay)
}
}
})
//*/
/* ..................................................................... */
const render = new Promise (async (resolve, reject) => {
while (true) {
await ccxt.sleep (renderDelay)
// for (let exchange of exchanges) {
// }
chart.setLine (0, [
'',
exchange.name.bright.cyan,
symbol.bright.cyan,
timeframe.cyan,
' '.repeat (79),
String (new Date ()).cyan,
].join (' '))
if (!output) {
chart.setLine (1, ' Loading' + '.'.red.repeat (parseInt (Date.now () / renderDelay) % 10))
// screen.debug (new Date (), output.length)
// screen.render ()
// log (chart)
// process.exit ()
} else {
output.forEach ((line, i) => {
chart.setLine (i + 1, line)
})
}
screen.render ()
}
})
/* ..................................................................... */
await Promise.all ([ poll, render ])
}) ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment