-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathbase.js
83 lines (72 loc) · 2.42 KB
/
base.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
'use strict'
const axios = require('axios').default
const rateLimit = require('axios-rate-limit')
const cheerio = require('cheerio')
const selector = '#screener-content > table:nth-child(1) > tbody:nth-child(1) > tr:nth-child(5) > td:nth-child(1) > table:nth-child(1) > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(1) > span'
/**
* @typedef {object} Options
* @property {number?} pageLimit Maximum number of pages to fetch. Set to `0` to disable. Default is 1
* @property {number?} requestTimeout Number of milliseconds to wait between requests. Default is 1000
*/
const defaults = {
pageLimit: 1,
requestTimeout: 1000,
}
/**
* @class
* @typicalname fv
* @example
* const fv = new FinVizScreener()
*
* const tickers = await fv
* .averageVolume('Over 2M')
* .sector('Technology')
* .price('Over $50')
* .scan()
*
* console.log(tickers) //=> ['AAPL', 'MSFT', 'IBM', ... ]
*/
class FinVizScreener {
/**
* @param {Options} options Options
*/
constructor(options) {
/** @type {Options} Client instance options */
this.options = Object.assign({}, defaults, options)
/** @private */
this._axios = rateLimit(
axios.create({ baseURL: 'https://finviz.com/screener.ashx?v=411' }),
{ maxRequests: 1, perMilliseconds: this.options.requestTimeout }
)
/** @private */
this._signal = ''
/** @private */
this._filters = []
}
/**
* Scan for stocks.
*
* @returns {Promise<string[]>} List of stock tickers
*/
async scan() {
const params = { f: this._filters.join(','), s: this._signal }
let tickers = []
let nextPage = ''
let cancel = false
let counter = 0
do {
cancel = this.options.pageLimit !== 0 && ++counter >= this.options.pageLimit
// fetch tickers
const res = await this._axios.get(nextPage, { params })
const $ = cheerio.load(res.data)
tickers = tickers.concat($(selector).map((i, el) => $(el).text().trim()).get())
// find next page
const $nextPage = $('.screener_pagination').children().last()
nextPage = $nextPage.children().first().text().includes('next')
? $nextPage.prop('href')
: ''
} while(nextPage && ! cancel)
return tickers
} // scan()
} // class
module.exports = FinVizScreener