Skip to content

Instantly share code, notes, and snippets.

@fernandojunior
Last active May 19, 2018 01:50
Show Gist options
  • Save fernandojunior/5339c4aed789b7842696aaa8821339bc to your computer and use it in GitHub Desktop.
Save fernandojunior/5339c4aed789b7842696aaa8821339bc to your computer and use it in GitHub Desktop.
ohlcv challenge
{
"extends": "standard"
}
node_modules/
package-lock.json

Server

  • Install deps: npm i

  • Start server: npm run start

  • Check lint: npm run lint

  • Run sercice tests: npm run test

  • Endpoint to get OHLCV: GET http://localhost:8989?market=BTC-DOGE&exchange=bittrex

const express = require('express')
const bodyParser = require('body-parser')
const routes = require('./routes')
const PORT = 8989
const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(routes)
app.listen(PORT, () => {
console.log(`OHLCV Server endpoint listening on http://localhost:${PORT}/. Query paramters: { exchange='bittrex', market='USDT-BTC' } `)
})
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "./node_modules/mocha/bin/mocha service.test.js",
"start": "node index.js",
"lint": "eslint *.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.18.3",
"dateformat": "^3.0.3",
"express": "^4.16.3",
"mathjs": "^4.2.2",
"request": "^2.86.0",
"request-promise": "^4.2.2"
},
"devDependencies": {
"eslint": "^4.19.1",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.7.0",
"eslint-plugin-standard": "^3.1.0",
"mocha": "^5.1.1"
}
}
const express = require('express')
const { getOhlcv } = require('./service')
const routes = express()
// TODO use APIDOC for REST API doc
routes.get('/', async (req, res) => {
// TODO use ExpressValidator to verify query params
res.send(await getOhlcv(req.query))
})
module.exports = routes
const dateFormat = require('dateformat')
const math = require('mathjs')
const { getExchangeData, addTwoZeroPad, getSecondsFromTimestamp } = require('./utils')
function filterDataByTimestamp (data, timeStamp) {
return data.filter((item) => (item.TimeStamp.includes(timeStamp)))
}
async function getOhlcv ({ exchange = 'bittrex', market = 'USDT-BTC' }) {
const { result: data } = await getExchangeData({ exchange, market })
let [ year, month, day, hour, min ] = dateFormat(new Date(), 'UTC:yyyy,mm,dd,HH,MM').split(',')
min = parseInt(min) - 1 // last minute before current
let lastMinTimestamp = `${year}-${month}-${day}T${hour}:${addTwoZeroPad(min)}`
// const lastMinTimestamp = '2018-05-16T20:04'
let filtered = filterDataByTimestamp(data, lastMinTimestamp)
// find last minute with data ?
// while (filtered.length === 0) {
// lastMinTimestamp = `${year}-${month}-${day}T${hour}:${addTwoZeroPad(--min)}`
// filtered = filterDataByTimestamp(data, lastMinTimestamp)
// }
console.info(`Registrated data in last min: length = ${filtered.length}, lastMinute = ${lastMinTimestamp}`)
let open, high, low, close, volume, time
if (filtered.length > 0) {
const sortedByTimestamp = filtered.sort((a, b) => (getSecondsFromTimestamp(a) - getSecondsFromTimestamp(b)))
const prices = filtered.map((item) => (parseFloat(item.Price)))
const quantities = filtered.map((item) => (parseFloat(item.Quantity)))
open = sortedByTimestamp[0].Price
high = math.max(prices)
low = math.min(prices)
close = sortedByTimestamp[sortedByTimestamp.length - 1].Price
volume = quantities.reduce((a, b) => (a + b))
time = new Date(`${lastMinTimestamp}:00Z`).getTime() / 1000
}
return { open, high, low, close, volume, time }
}
module.exports = { getOhlcv }
const assert = require('assert')
const { getOhlcv } = require('./service')
describe('test getOhlcv function', () => { // eslint-disable-line
['open', 'high', 'low', 'close', 'volume', 'time'].forEach((prop) => {
it(`should an object with the ${prop} prop`, async () => { // eslint-disable-line
assert.equal(Object.keys(await getOhlcv({})).includes(prop), true)
})
})
})
const request = require('request-promise')
function addTwoZeroPad (n) {
return typeof n === 'string' ? n : ('0' + n).slice(-2)
}
function getSecondsFromTimestamp (item) {
return parseFloat(item.TimeStamp.split(':')[2])
}
const exchangeApiUrls = {
bittrex: ({ market }) => (`https://bittrex.com/api/v1.1/public/getmarkethistory?market=${market}`)
}
function getExchangeApiUrl ({ exchange, market }) {
return exchangeApiUrls[exchange]({ market })
}
async function getExchangeData (options) {
const url = getExchangeApiUrl(options)
console.info(`Requesting ${url}`)
return JSON.parse(await request(url))
}
module.exports = { addTwoZeroPad, getSecondsFromTimestamp, getExchangeData }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment