'use strict'
// Required Modules:
const colors = require('colors')
const debug = require('debug')('active-tick:main')
const request = require('request')
const lodash = require('lodash')
const async = require('async')
const moment = require('moment')
const Q = require('q')
const fs = require('fs')
const AT_STR = 'YYYYMMDDHHmmss'
const AT_STRL = 'YYYYMMDDHHmmssSSS'
const MAP_LIMIT = 2
/**
* ActiveTick Class
*/
class ActiveTick {
/**
* Constructor
* @param {Object} params Params to be set into this instance
* @return {ActiveTick} ActiveTick instance
*/
constructor( params ){
debug('Instance Created:', params)
this.params = params
this.mapLimit = params.mapLimit || MAP_LIMIT
this.API = params.API
// this.test()
return this
}
// Simple to make sure it's working properly:
test(){
const symb = 'NFLX'
this.tickData( symb, '8/25/2016' )
.then(( results ) => {
console.log('results', results)
fs.writeFileSync(`./${symb}.csv`, results)
})
.catch(( err ) => {
console.log('ERR', err)
next( err )
})
}
/**
* Format a MomentJS date to ActiveTick API standard string
* @param {Date} date MomentJS date in which to format
* @return {String} Formatted String of the date given.
*/
formatToAT( date ){
return date.format(AT_STR)
}
/**
* Execute a Stack
* @param {Object} params Params of the stack item
* @param {Function} cb Callback
*/
exeStack( params, cb ){
this.fetch( params, '/tickData', cb )
}
/**
* Fetch a response from the ActiveTick API
* @param {Object} params Query String params to be sent
* @param {String} path API route to be called
* @param {Function} cb Callback
*/
fetch( params, path, cb ){
debug('Requesting:', params)
request({
url: `${this.API}${path}`,
qs: params
}, ( err, res, body ) => {
debug('Response Code:', res.statusCode)
if( err ) return cb( err )
if( res.statusCode != 200 ) return cb( new Error('Not a 200 status OK: '+res.statusCode ) )
if( body == '0' ) return cb( err, [] )
cb( err, this.parseResponse( body ) )
})
}
/**
* Parse the CSV format into JS Array
* @param {String} string CSV string ActiveTick API returns
* @return {Array} Array of items parsed from string
*/
parseResponse( string ){
string = string.split('\r\n')
console.log('len', string.length)
return lodash.reject( string, ( str ) => lodash.isEmpty( str ) )
}
/**
* Parse a Tick Response
* @param {String} str Line response from ActiveTick eg: Q,20160825093000577,0.730000,0.747000,47,35,P,Q,0
* @return {Object} Object of tick data from str
*/
parseTick( str ){
const pieces = str.split( ',' )
let res = {}
res.type = pieces[0]
res.time = moment(pieces[1], AT_STRL).valueOf()
if( pieces[0] == 'T' ){
res.type = 'trade'
res.lastprice = parseFloat( pieces[2] )
res.lastsize = parseFloat( pieces[3] )
res.lastexch = pieces[4]
res.c1 = parseInt( pieces[5] || '0' )
res.c2 = parseInt( pieces[6] || '0' )
res.c3 = parseInt( pieces[7] || '0' )
res.c4 = parseInt( pieces[8] || '0' )
}else {
res.type = 'quote'
res.bidprice = parseFloat( pieces[2] )
res.askprice = parseFloat( pieces[3] )
res.bidsize = parseFloat( pieces[4] )
res.asksize = parseFloat( pieces[5] )
res.bidexch = pieces[6] || ''
res.askexch = pieces[7] || ''
res.c1 = parseInt( pieces[8] || '0' )
}
return res
}
/**
* Get Tick data of a Stock Symbol for an entire day
* @param {String} symbol Symbol you want the tick data for
* @param {String} day Date you want tick data for eg: 08/25/2016
* @return {Promise} Returns a promise
*/
tickData( symbol, day ){
const deferred = Q.defer()
debug('tick data', symbol, day)
day = moment( new Date( day ) )
debug('D', this.formatToAT( day ))
// Set our date to 9:30am:
day.hour( 9 )
day.minute( 30 )
day.seconds( 0 )
// Divide day into 10min intervals:
let callStack = []
while( day.get('hours') < 16 ){
let params = {
symbol: symbol.toUpperCase(),
trades: 1,
quotes: 1,
beginTime: this.formatToAT( day ),
endTime: this.formatToAT( day )
}
day.add(10, 'minutes')
params.endTime = this.formatToAT( day )
callStack.push( params )
}
// Execute entire day:
async.mapLimit( callStack, this.mapLimit, this.exeStack.bind( this ), ( err, res ) => {
deferred.makeNodeResolver()( err, lodash.flatten( res ) )
})
// Return promise
return deferred.promise
}
}
/**
* Export
* @param {Object} params ActiveTick library params
* @return {ActiveTick} New instance of the ActiveTick library
*/
module.exports = ( params )=> {
return new ActiveTick( params )
}