UNPKG

3.72 kBJavaScriptView Raw
1const Market = require('../broker/robinhood/Market');
2const schedule = require('node-schedule');
3const moment = require('moment');
4
5/**
6 * Used to run functions at specified intervals or times of day.
7 */
8class Scheduler {
9
10 /**
11 * Creates a new scheduled task
12 * @author Torrey Leonard <https://github.com/Ladinn>
13 * @param {Function} f
14 */
15 constructor(f) {
16 this.f = f;
17 this.job = null;
18 }
19
20 /**
21 * Runs every day on market open.
22 * @author Torrey Leonard <https://github.com/Ladinn>
23 * @param {Number} offset - The offset, in milliseconds, from market open to run the algorithm. Negative is before, positive is after.
24 * @returns {Promise<Date>} - Date object of next invocation.
25 */
26 onMarketOpen(offset) {
27 const _this = this;
28 if (!offset) offset = 0;
29 return new Promise((resolve, reject) => {
30 if (_this.job !== null) reject(new Error("You must cancel this job before scheduling it again!"));
31 else Market.getByMIC("XNYS").then(nyse => {
32 nyse.getNextOpen().then(next => {
33 let date = new Date(next.getTime() + offset);
34 if (moment(date).isBefore(moment())) {
35 date = moment(date).add('1', 'day').toDate();
36 }
37 _this.job = schedule.scheduleJob(date, (invocationDate) => {
38 _this.f();
39 let date = moment(invocationDate);
40 schedule.scheduleJob(date.add('1', 'day'), _this.f);
41 });
42 resolve(_this.job.nextInvocation().toDate());
43 })
44 });
45 })
46 }
47
48 /**
49 * Runs every day on market close.
50 * @author Torrey Leonard <https://github.com/Ladinn>
51 * @param {Number} offset - The offset, in milliseconds, from market close to run the algorithm. Negative is before, positive is after.
52 * @returns {Promise<schedule>}
53 */
54 onMarketClose(offset) {
55 const _this = this;
56 if (!offset) offset = 0;
57 return new Promise((resolve, reject) => {
58 if (_this.job !== null) reject(new Error("You must cancel this job before scheduling it again!"));
59 else Market.getByMIC("XNYS").then(nyse => {
60 nyse.getNextClose().then(next => {
61 let date = new Date(next.getTime() + offset);
62 if (moment(date).isBefore(moment())) {
63 date = moment(date).add('1', 'day').toDate();
64 }
65 _this.job = schedule.scheduleJob(date, (invocationDate) => {
66 _this.f();
67 let date = moment(invocationDate);
68 schedule.scheduleJob(date.add('1', 'day'), _this.f);
69 });
70 resolve(_this.job.nextInvocation().toDate());
71 })
72 });
73 });
74 }
75
76 /**
77 * Runs every 'x' minutes while the market is open.
78 * @author Torrey Leonard <https://github.com/Ladinn>
79 * @param {Number} minutes
80 * @param {Boolean} extended - Whether to run during extended trading hours.
81 */
82 every(minutes, extended) {
83 const _this = this;
84 return new Promise((resolve, reject) => {
85 if (_this.job !== null) reject(new Error("You must cancel this job before scheduling it again!"));
86 else {
87 _this.job = schedule.scheduleJob("*/" + minutes + " * * * 1-5", () => {
88 Market.getByMIC("XNYS").then(nyse => {
89 if (nyse.isOpenNow()) _this.f();
90 else if (extended && nyse.isExtendedOpenNow()) _this.f();
91 })
92 });
93 resolve(_this.job.nextInvocation().toDate());
94 }
95 });
96 }
97
98 /**
99 * Cancels a job.
100 * @author Torrey Leonard <https://github.com/Ladinn>
101 */
102 cancel() {
103 if (this.job === null) return new Error("This job has not been scheduled yet.");
104 else {
105 this.job.cancel();
106 this.job = null;
107 }
108 }
109
110 /**
111 * Returns the date of the next invocation of the given job.
112 * @author Torrey Leonard <https://github.com/Ladinn>
113 * @returns {Date|Error}
114 */
115 getNext() {
116 if (this.job === null) return new Error("This job has not been scheduled yet.");
117 else return this.job.nextInvocation();
118 }
119
120}
121
122module.exports = Scheduler;
\No newline at end of file