UNPKG

5.88 kBJavaScriptView Raw
1const LibraryError = require('../globals/LibraryError');
2const Quote = require('../globals/Quote');
3const OptionsChain = require('../globals/OptionsChain');
4const request = require('request');
5const async = require('async');
6const ora = require('ora');
7
8/**
9 * Used to interact with the Yahoo Finance API.
10 */
11class Yahoo {
12
13 /**
14 * Returns an array of Quote objects from Yahoo Finance.
15 * @author Torrey Leonard <https://github.com/Ladinn>
16 * @constructor
17 * @param {String} symbol
18 * @param {String} range - How far back to retrieve data: [1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max]
19 * @param {String} interval - How long each quote should represent: [1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo]
20 * @param {Boolean} extended - Whether to include data from extended trading hours.
21 * @returns {Promise<Array>}
22 */
23 static getQuotes(symbol, range, interval, extended) {
24 return new Promise((resolve, reject) => {
25 request({
26 uri: "https://query2.finance.yahoo.com/v7/finance/chart/" + symbol + "?range=" + range + "&interval=" + interval + "&indicators=quote&includeTimestamps=true&includePrePost=" + extended + "&events=div%7Csplit%7Cearn"
27 }, (error, response, body) => {
28 if (error) reject(error);
29 else if (response.statusCode !== 200) reject(new LibraryError(body));
30 else {
31
32 let json = JSON.parse(body).chart.result[0];
33
34 let array = [];
35
36 const timestamps = json.timestamp;
37 const quotes = json.indicators.quote[0];
38
39 if (timestamps === undefined) reject(new LibraryError("Invalid range given. Yahoo suggests using: " + json.meta.validRanges + " (Is this stock too young?)"));
40 else {
41
42 Object.keys(timestamps).forEach(key => {
43 if (quotes[key] !== null) array.push(
44 new Quote({
45 symbol: symbol,
46 source: "Yahoo/" + json.meta.exchangeName,
47 date: new Date(timestamps[key] * 1000),
48 price: {
49 open: Number(quotes.open[key]),
50 high: Number(quotes.high[key]),
51 low: Number(quotes.low[key]),
52 close: Number(quotes.close[key]),
53 volume: Number(quotes.volume[key])
54 }
55 })
56 )
57 });
58
59 resolve(array);
60
61 }
62
63 }
64 })
65 })
66 }
67
68 /**
69 * Returns a new OptionsChain object with data from Yahoo Finance.
70 * @author Torrey Leonard <https://github.com/Ladinn>
71 * @param {String} symbol
72 * @returns {Promise<OptionsChain>}
73 */
74 static getOptionsChain(symbol) {
75 return new Promise((resolve, reject) => {
76 const loading = ora("Downloading from Yahoo! Finance...").start();
77 request('https://query2.finance.yahoo.com/v7/finance/options/' + symbol, (error, response, body) => {
78 if (error) reject(error);
79 else if (response.statusCode !== 200) reject(new LibraryError(body));
80 else try {
81 let json = JSON.parse(body);
82 let data = json.optionChain.result[0];
83 const timestamps = data.expirationDates;
84 let array = [];
85 async.forEachOf(timestamps, (value, key, callback) => {
86 request('https://query2.finance.yahoo.com/v7/finance/options/' + symbol + '?date=' + value, (error, response, body) => {
87 if (error) reject(error);
88 else if (response.statusCode !== 200) reject(new LibraryError(body));
89 else try {
90
91 json = JSON.parse(body);
92 data = json.optionChain.result[0];
93
94 const options = data.options[0];
95 const calls = options.calls;
96 const puts = options.puts;
97
98 let callVolume = 0;
99 let putVolume = 0;
100
101 let callOpenInterest = 0;
102 let putOpenInterest = 0;
103
104 let callObject = {};
105 let putObject = {};
106
107 calls.forEach(value => {
108 callVolume += value.volume || 0;
109 callOpenInterest += value.openInterest || 0;
110 callObject[Number(value.strike)] = {
111 strike: Number(value.strike),
112 lastPrice: Number(value.lastPrice),
113 bid: Number(value.bid),
114 ask: Number(value.ask),
115 change: Number(value.change),
116 volume: Number(value.volume),
117 openInterest: Number(value.openInterest),
118 lastTradeDate: new Date(value.lastTradeDate * 1000),
119 impliedVolatility: Number(value.impliedVolatility),
120 inTheMoney: Boolean(value.inTheMoney)
121 }
122 });
123
124 puts.forEach(value => {
125 putVolume += Number(value.volume || 0);
126 putOpenInterest += Number(value.openInterest || 0);
127 putObject[Number(value.strike)] = {
128 strike: Number(value.strike),
129 lastPrice: Number(value.lastPrice || 0),
130 bid: Number(value.bid || 0),
131 ask: Number(value.ask || 0),
132 change: Number(value.change || 0),
133 volume: Number(value.volume || 0),
134 openInterest: Number(value.openInterest),
135 lastTradeDate: new Date(value.lastTradeDate * 1000),
136 impliedVolatility: Number(value.impliedVolatility),
137 inTheMoney: Boolean(value.inTheMoney)
138 }
139 });
140
141 let ratio = (putVolume + putOpenInterest) / (callVolume + callOpenInterest);
142
143 if (!isNaN(ratio)) {
144 array.push({
145 date: new Date(value * 1000),
146 callVolume: callVolume,
147 putVolume: putVolume,
148 callOpenInterest: callOpenInterest,
149 putOpenInterest: putOpenInterest,
150 putCallRatio: ratio,
151 calls: callObject,
152 puts: putObject
153 });
154 }
155
156 loading.text += '.';
157 callback();
158
159 } catch (error) {
160 reject(error);
161 }
162 });
163 }, () => {
164 loading.succeed("Download complete.");
165 resolve(new OptionsChain(array))
166 } );
167 } catch (error) {
168 reject(error);
169 }
170 });
171 })
172 }
173
174}
175
176module.exports = Yahoo;
\No newline at end of file