├── .gitignore ├── README ├── app └── app.ts ├── fe └── angular │ └── ib-trading-bot │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── angular.json │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ └── market-data-graphs │ │ │ ├── market-data-graphs.component.css │ │ │ ├── market-data-graphs.component.html │ │ │ ├── market-data-graphs.component.spec.ts │ │ │ └── market-data-graphs.component.ts │ ├── assets │ │ ├── .gitkeep │ │ └── chartjs-chart-financial.js │ ├── browserslist │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json │ ├── tsconfig.json │ └── tslint.json ├── package-lock.json ├── package.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | # Interactive Brokers Trading Bot 2 | 3 | In this tutorial series, we are going to build an automated trading bot that trades stocks on the US stock market for us. We are using Interactive Brokers and its API, Node.js, Angular, TypeScript and rxjs. 4 | 5 | Checkout the channel on YouTube here: 6 | https://www.youtube.com/channel/UCk0KKThPP2GxhyOY8twoWOQ 7 | 8 | The plan: 9 | 10 | 1. We get historical data of a desired stock 11 | 2. Plot the day, 1h, 5m candles on the screen 12 | 3. Find support and resistance lines, draw them on the graphs 13 | 4. Determine entry point for our trades 14 | 5. Enter trade and set profit target and stop loss -------------------------------------------------------------------------------- /app/app.ts: -------------------------------------------------------------------------------- 1 | import Ib from '@stoqey/ib'; 2 | import { stock } from '@stoqey/ib/dist/contract/stock'; 3 | import WebSocket from 'ws'; 4 | 5 | const wss = new WebSocket.Server({ port: 8080 }); 6 | let connected = false; 7 | 8 | const options = { port: 4001 }; 9 | const connection = new Ib(options); 10 | 11 | const contract = stock('AAPL', undefined, 'USD'); 12 | 13 | connection.on('connected', () => { 14 | connected = true; 15 | console.log('Connected!'); 16 | }); 17 | 18 | connection.on('disconnected', () => { 19 | connected = false; 20 | console.log('Disconnected!'); 21 | }); 22 | 23 | connection.on('result', (event: any, args: any) => { 24 | console.log('%s --- %s', event, JSON.stringify(args)); 25 | }); 26 | 27 | connection.on('error', (err: any) => { 28 | console.error('error --- %s', err.message); 29 | }); 30 | 31 | if (!connected) { 32 | connection.connect(); 33 | } 34 | 35 | wss.on('connection', (ws) => { 36 | ws.on('message', (message: string) => { 37 | console.log(`Received message => ${message}`); 38 | }); 39 | 40 | connection.reqHistoricalData(6000, contract, '', '3 M', '1 day', 'ADJUSTED_LAST', 1, 1, false); 41 | connection.reqHistoricalData(6001, contract, '', '1 W', '1 hour', 'ADJUSTED_LAST', 1, 1, false); 42 | connection.reqHistoricalData(6002, contract, '', '3600 S', '1 min', 'ADJUSTED_LAST', 1, 1, false); 43 | connection.reqRealTimeBars(6003, contract, 5, 'TRADES', true); 44 | 45 | connection.on('historicalData', (reqId: number, date: string, open: number, high: number, low: number, close: number, volume: number, count: number, WAP: number, hasGaps: boolean) => { 46 | ws.send( 47 | JSON.stringify({ 48 | reqId: reqId, 49 | t: Date.parse(`${date.substring(0,4)}-${date.substring(4,6)}-${date.substring(6,8)} ${date.substr(10)}`), 50 | o: open.toString(), 51 | h: high.toString(), 52 | l: low.toString(), 53 | c: close.toString(), 54 | }) 55 | ); 56 | }); 57 | 58 | connection.on('realtimeBar', (reqId: number, time: number, open: number, high: number, low: number, close: number, volume: number, wap: number, count: number) => { 59 | ws.send( 60 | JSON.stringify({ 61 | reqId: reqId, 62 | t: time, 63 | o: open.toString(), 64 | h: high.toString(), 65 | l: low.toString(), 66 | c: close.toString(), 67 | }) 68 | ); 69 | }); 70 | 71 | }); -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/README.md: -------------------------------------------------------------------------------- 1 | # IbTradingBot 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.0.6. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "ib-trading-bot": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/ib-trading-bot", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "src/tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "src/styles.css" 27 | ], 28 | "scripts": [] 29 | }, 30 | "configurations": { 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "src/environments/environment.ts", 35 | "with": "src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "extractCss": true, 42 | "namedChunks": false, 43 | "aot": true, 44 | "extractLicenses": true, 45 | "vendorChunk": false, 46 | "buildOptimizer": true, 47 | "budgets": [ 48 | { 49 | "type": "initial", 50 | "maximumWarning": "2mb", 51 | "maximumError": "5mb" 52 | } 53 | ] 54 | } 55 | } 56 | }, 57 | "serve": { 58 | "builder": "@angular-devkit/build-angular:dev-server", 59 | "options": { 60 | "browserTarget": "ib-trading-bot:build" 61 | }, 62 | "configurations": { 63 | "production": { 64 | "browserTarget": "ib-trading-bot:build:production" 65 | } 66 | } 67 | }, 68 | "extract-i18n": { 69 | "builder": "@angular-devkit/build-angular:extract-i18n", 70 | "options": { 71 | "browserTarget": "ib-trading-bot:build" 72 | } 73 | }, 74 | "test": { 75 | "builder": "@angular-devkit/build-angular:karma", 76 | "options": { 77 | "main": "src/test.ts", 78 | "polyfills": "src/polyfills.ts", 79 | "tsConfig": "src/tsconfig.spec.json", 80 | "karmaConfig": "src/karma.conf.js", 81 | "styles": [ 82 | "src/styles.css" 83 | ], 84 | "scripts": [], 85 | "assets": [ 86 | "src/favicon.ico", 87 | "src/assets" 88 | ] 89 | } 90 | }, 91 | "lint": { 92 | "builder": "@angular-devkit/build-angular:tslint", 93 | "options": { 94 | "tsConfig": [ 95 | "src/tsconfig.app.json", 96 | "src/tsconfig.spec.json" 97 | ], 98 | "exclude": [ 99 | "**/node_modules/**" 100 | ] 101 | } 102 | } 103 | } 104 | }, 105 | "ib-trading-bot-e2e": { 106 | "root": "e2e/", 107 | "projectType": "application", 108 | "prefix": "", 109 | "architect": { 110 | "e2e": { 111 | "builder": "@angular-devkit/build-angular:protractor", 112 | "options": { 113 | "protractorConfig": "e2e/protractor.conf.js", 114 | "devServerTarget": "ib-trading-bot:serve" 115 | }, 116 | "configurations": { 117 | "production": { 118 | "devServerTarget": "ib-trading-bot:serve:production" 119 | } 120 | } 121 | }, 122 | "lint": { 123 | "builder": "@angular-devkit/build-angular:tslint", 124 | "options": { 125 | "tsConfig": "e2e/tsconfig.e2e.json", 126 | "exclude": [ 127 | "**/node_modules/**" 128 | ] 129 | } 130 | } 131 | } 132 | } 133 | }, 134 | "defaultProject": "ib-trading-bot" 135 | } -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('workspace-project App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getTitleText()).toEqual('Welcome to ib-trading-bot!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ib-trading-bot", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~7.0.0", 15 | "@angular/common": "~7.0.0", 16 | "@angular/compiler": "~7.0.0", 17 | "@angular/core": "~7.0.0", 18 | "@angular/forms": "~7.0.0", 19 | "@angular/http": "~7.0.0", 20 | "@angular/platform-browser": "~7.0.0", 21 | "@angular/platform-browser-dynamic": "~7.0.0", 22 | "@angular/router": "~7.0.0", 23 | "core-js": "^2.5.4", 24 | "rxjs": "~6.3.3", 25 | "zone.js": "~0.8.26" 26 | }, 27 | "devDependencies": { 28 | "@angular-devkit/build-angular": "~0.10.0", 29 | "@angular/cli": "~7.0.6", 30 | "@angular/compiler-cli": "~7.0.0", 31 | "@angular/language-service": "~7.0.0", 32 | "@types/node": "~8.9.4", 33 | "@types/jasmine": "~2.8.8", 34 | "@types/jasminewd2": "~2.0.3", 35 | "codelyzer": "~4.5.0", 36 | "jasmine-core": "~2.99.1", 37 | "jasmine-spec-reporter": "~4.2.1", 38 | "karma": "~3.0.0", 39 | "karma-chrome-launcher": "~2.2.0", 40 | "karma-coverage-istanbul-reporter": "~2.0.1", 41 | "karma-jasmine": "~1.1.2", 42 | "karma-jasmine-html-reporter": "^0.2.2", 43 | "protractor": "~5.4.0", 44 | "ts-node": "~7.0.0", 45 | "tslint": "~5.11.0", 46 | "typescript": "~3.1.6" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | const routes: Routes = []; 5 | 6 | @NgModule({ 7 | imports: [RouterModule.forRoot(routes)], 8 | exports: [RouterModule] 9 | }) 10 | export class AppRoutingModule { } 11 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottocoster/interactive-brokers-trading-bot-tutorial/a381aa504b25ba81ecdb5e6bd9a7648f39db551c/fe/angular/ib-trading-bot/src/app/app.component.css -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | })); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.debugElement.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'ib-trading-bot'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.debugElement.componentInstance; 26 | expect(app.title).toEqual('ib-trading-bot'); 27 | }); 28 | 29 | it('should render title in a h1 tag', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.debugElement.nativeElement; 33 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to ib-trading-bot!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'ib-trading-bot'; 10 | } 11 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | import { MarketDataGraphsComponent } from './market-data-graphs/market-data-graphs.component'; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | AppComponent, 11 | MarketDataGraphsComponent 12 | ], 13 | imports: [ 14 | BrowserModule, 15 | AppRoutingModule 16 | ], 17 | providers: [], 18 | bootstrap: [AppComponent] 19 | }) 20 | export class AppModule { } 21 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/market-data-graphs/market-data-graphs.component.css: -------------------------------------------------------------------------------- 1 | main { 2 | display: flex; 3 | flex-wrap: wrap; 4 | } 5 | 6 | main.has-position { 7 | background-color: rgba(255, 0, 0, 0.1); 8 | } 9 | 10 | #status { 11 | display: flex; 12 | width: 100%; 13 | } 14 | 15 | #status p { 16 | margin-left: 32px; 17 | } -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/market-data-graphs/market-data-graphs.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Open order at {{ openOrder || '-' }}

4 |

Profit target at {{ profitTarget * 100 }}%

5 |

Stop loss at {{stopLoss * 100}}%

6 |

Running P&L: {{runningPnl }}

7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 | 21 |
22 | 23 |
24 |
25 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/market-data-graphs/market-data-graphs.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MarketDataGraphsComponent } from './market-data-graphs.component'; 4 | 5 | describe('MarketDataGraphsComponent', () => { 6 | let component: MarketDataGraphsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MarketDataGraphsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MarketDataGraphsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/app/market-data-graphs/market-data-graphs.component.ts: -------------------------------------------------------------------------------- 1 | import { trigger } from '@angular/animations'; 2 | import { Component, OnInit } from '@angular/core'; 3 | import { Subject } from 'rxjs'; 4 | 5 | declare const Chart; 6 | declare const luxon; 7 | 8 | export interface CandlestickData { 9 | reqId: number; 10 | t: number; 11 | o: number; 12 | h: number; 13 | l: number; 14 | c: number; 15 | } 16 | 17 | @Component({ 18 | selector: 'app-market-data-graphs', 19 | templateUrl: './market-data-graphs.component.html', 20 | styleUrls: ['./market-data-graphs.component.css'] 21 | }) 22 | export class MarketDataGraphsComponent implements OnInit { 23 | webSocketConnection: WebSocket; 24 | webSocketMessage$ = new Subject(); 25 | historicData: CandlestickData[]; 26 | messageArray: CandlestickData[] = []; 27 | entryPoint: CandlestickData; 28 | profitTarget = 0.005; 29 | stopLoss = 0.005; 30 | openOrder: number; 31 | hasPosition: boolean; 32 | runningPnl: number; 33 | takeProfitOrder: number; 34 | stopLossOrder: number; 35 | 36 | constructor() { } 37 | 38 | ngOnInit() { 39 | this.startWebSocketClient(); 40 | 41 | this.webSocketMessage$.subscribe((message: string) => { 42 | const parsedMessage: CandlestickData = JSON.parse(message); 43 | this.messageArray.push(parsedMessage); 44 | 45 | // Check when data for a certain graph has finished, if so, render the graph 46 | if (parsedMessage.t === null) { 47 | if (parsedMessage.reqId === 6000) { 48 | const lines = this.findSupportAndResistance(this.messageArray, 6000); 49 | 50 | this.renderGraph( 51 | this.messageArray 52 | .filter(candlestick => candlestick.t > 0) 53 | .filter(candlestick => candlestick.reqId === 6000), 'chart3M1D', lines.supportLines, lines.resistanceLines); 54 | 55 | console.log(lines); 56 | } 57 | 58 | if (parsedMessage.reqId === 6001) { 59 | const lines = this.findSupportAndResistance(this.messageArray, 6001); 60 | 61 | this.renderGraph( 62 | this.messageArray 63 | .filter(candlestick => candlestick.t > 0) 64 | .filter(candlestick => candlestick.reqId === 6001), 'chart1W1H', lines.supportLines, lines.resistanceLines); 65 | } 66 | 67 | if (parsedMessage.reqId === 6002) { 68 | const lines = this.findSupportAndResistance(this.messageArray, 6002); 69 | 70 | this.renderGraph( 71 | this.messageArray 72 | .filter(candlestick => candlestick.t > 0) 73 | .filter(candlestick => candlestick.reqId === 6002), 'chart1H1m', lines.supportLines, lines.resistanceLines); 74 | } 75 | } 76 | 77 | // Live 5 sec bar graph 78 | if (parsedMessage.reqId === 6003) { 79 | const lines = this.findSupportAndResistance(this.messageArray, 6003); 80 | 81 | this.entryPoint = this.findEntryPoint(6003, this.messageArray, lines); 82 | 83 | this.paperTrade(6003, this.messageArray); 84 | 85 | this.renderGraph( 86 | this.messageArray 87 | .filter(candlestick => candlestick.t > 0) 88 | .filter(candlestick => candlestick.reqId === 6003), 'chart5s', lines.supportLines, lines.resistanceLines, this.entryPoint, this.openOrder, this.takeProfitOrder, this.stopLossOrder); 89 | } 90 | }); 91 | } 92 | 93 | findEntryPoint(reqId: number, messageArray: CandlestickData[], supportAndResistanceLines: {supportLines: CandlestickData[], resistanceLines: CandlestickData[]}): CandlestickData { 94 | // Find closest support line 95 | const closestSupportLine = supportAndResistanceLines.supportLines 96 | .sort((a, b) => b.l - a.l) 97 | .find(supportLine => { 98 | return messageArray[messageArray.length - 1].l > supportLine.l; 99 | }); 100 | 101 | return closestSupportLine; 102 | } 103 | 104 | paperTrade(reqId: number, messageArray: CandlestickData[]) { 105 | if (!reqId || !messageArray) { 106 | return; 107 | } 108 | 109 | const liveData = messageArray 110 | .filter(candlestick => candlestick.t > 0) 111 | .filter(candlestick => candlestick.reqId === reqId); 112 | 113 | const lastClose = liveData[liveData.length - 1].c; 114 | 115 | if (this.hasPosition) { 116 | this.runningPnl = lastClose - this.openOrder; 117 | } 118 | 119 | 120 | if (!this.hasPosition && liveData[liveData.length - 1].l <= this.openOrder) { 121 | this.hasPosition = true; 122 | this.takeProfitOrder = this.entryPoint.l * (1 + this.profitTarget); 123 | this.stopLossOrder = this.entryPoint.l * (1 - this.stopLoss); 124 | 125 | console.log(`Buy order filled at ${this.openOrder}`); 126 | console.log(`Creating take profit order at ${this.takeProfitOrder}`); 127 | console.log(`Creating stop loss order at ${this.stopLossOrder}`); 128 | 129 | return; 130 | } 131 | 132 | // Create new buy order if there isn't any 133 | // Update order when entry point is updated 134 | 135 | if (!this.hasPosition && this.entryPoint && (!this.openOrder || this.openOrder !== this.entryPoint.l)) { 136 | console.log(`Creating buy order at ${this.entryPoint.l}`); 137 | 138 | this.openOrder = this.entryPoint.l; 139 | } 140 | 141 | // Clear entry point if we're in a position 142 | if (this.hasPosition) { 143 | this.entryPoint = null; 144 | } 145 | } 146 | 147 | startWebSocketClient() { 148 | const url = 'ws://localhost:8080/'; 149 | this.webSocketConnection = new WebSocket(url); 150 | 151 | this.webSocketConnection.onopen = () => { 152 | console.log(`WebSocket connected!`); 153 | }; 154 | 155 | this.webSocketConnection.onerror = error => { 156 | console.log(`WebSocket error: ${error}`); 157 | }; 158 | 159 | this.webSocketConnection.onmessage = (messageEvent: MessageEvent) => { 160 | const lastMessage = (messageEvent.data as string); 161 | this.webSocketMessage$.next(lastMessage); 162 | }; 163 | } 164 | 165 | renderGraph(data: CandlestickData[], element: string, supportLines: CandlestickData[], resistanceLines: CandlestickData[], entryPoint?: CandlestickData, openOrder?: number, takeProfitOrder?: number, stopLossOrder?: number): void { 166 | const ctx = (document.getElementById(element) as any).getContext('2d'); 167 | ctx.canvas.width = 600; 168 | ctx.canvas.height = 400; 169 | 170 | const datasets: any = [{ 171 | label: element, 172 | data: data 173 | }]; 174 | 175 | supportLines.forEach(supportLine => 176 | datasets.push({ 177 | type: 'line', 178 | label: `Support line`, 179 | borderColor: 'blue', 180 | borderWidth: 1, 181 | fill: false, 182 | data: [{ 183 | x: supportLine.t, 184 | y: supportLine.l, 185 | }, 186 | { 187 | x: Date.now(), 188 | y: supportLine.l, 189 | }] 190 | }) 191 | ) 192 | 193 | resistanceLines.forEach(resistanceLine => 194 | datasets.push({ 195 | type: 'line', 196 | label: `Resistance line`, 197 | borderColor: 'red', 198 | borderWidth: 1, 199 | fill: false, 200 | data: [{ 201 | x: resistanceLine.t, 202 | y: resistanceLine.h, 203 | }, 204 | { 205 | x: Date.now(), 206 | y: resistanceLine.h, 207 | }] 208 | }) 209 | ) 210 | 211 | // Draw entry point 212 | if (entryPoint) { 213 | datasets.push({ 214 | type: 'line', 215 | label: `Entry point`, 216 | borderColor: 'green', 217 | borderWidth: 2, 218 | fill: false, 219 | data: [{ 220 | x: entryPoint.t, 221 | y: entryPoint.l, 222 | }, 223 | { 224 | x: Date.now(), 225 | y: entryPoint.l, 226 | }] 227 | }); 228 | } 229 | 230 | // Draw open order 231 | if (openOrder) { 232 | datasets.push({ 233 | type: 'line', 234 | label: `Entry point`, 235 | borderColor: 'green', 236 | borderWidth: 2, 237 | fill: false, 238 | data: [{ 239 | x: entryPoint.t, 240 | y: entryPoint.l, 241 | }, 242 | { 243 | x: Date.now(), 244 | y: entryPoint.l, 245 | }] 246 | }); 247 | } 248 | 249 | // Draw take profit order 250 | if (takeProfitOrder) { 251 | datasets.push({ 252 | type: 'line', 253 | label: `Take profit order`, 254 | borderColor: 'lightgreen', 255 | borderWidth: 2, 256 | fill: false, 257 | data: [{ 258 | x: entryPoint.t, 259 | y: takeProfitOrder, 260 | }, 261 | { 262 | x: Date.now(), 263 | y: takeProfitOrder, 264 | }] 265 | }); 266 | } 267 | 268 | // Draw stop loss order 269 | if (stopLossOrder) { 270 | datasets.push({ 271 | type: 'line', 272 | label: `Stop Loss order`, 273 | borderColor: 'purple', 274 | borderWidth: 2, 275 | fill: false, 276 | data: [{ 277 | x: entryPoint.t, 278 | y: stopLossOrder, 279 | }, 280 | { 281 | x: Date.now(), 282 | y: stopLossOrder, 283 | }] 284 | }); 285 | } 286 | 287 | const chart = new Chart(ctx, { 288 | type: 'candlestick', 289 | data: { 290 | datasets: datasets 291 | } 292 | }); 293 | } 294 | 295 | findSupportAndResistance(messageArray: CandlestickData[], reqId: number) { 296 | const supportLines = messageArray 297 | .filter(candlestick => candlestick.t > 0) 298 | .filter(candlestick => candlestick.reqId === reqId) 299 | .filter((value, index, array) => { 300 | if (index > 0 301 | && index < (array.length - 2) 302 | && array[index - 1].l >= value.l 303 | && array[index + 1].l > value.l) { 304 | return true; 305 | } 306 | }).sort((a, b) => a.l - b.l); 307 | 308 | const resistanceLines = messageArray 309 | .filter(candlestick => candlestick.t > 0) 310 | .filter(candlestick => candlestick.reqId === reqId) 311 | .filter((value, index, array) => { 312 | if (index > 0 313 | && index < (array.length - 2) 314 | && array[index - 1].h <= value.h 315 | && array[index + 1].h < value.h) { 316 | return true; 317 | } 318 | }).sort((a, b) => b.h - a.h); 319 | 320 | const averageBarHeight = messageArray 321 | .filter(candlestick => candlestick.t > 0) 322 | .filter(candlestick => candlestick.reqId === reqId) 323 | .map(candlestick => candlestick.h - candlestick.l) 324 | .reduce((previous, current) => previous + current) 325 | / messageArray 326 | .filter(candlestick => candlestick.t > 0) 327 | .filter(candlestick => candlestick.reqId === reqId).length; 328 | 329 | const uniqueSupportLines: CandlestickData[] = []; 330 | 331 | supportLines.forEach((supportLine, index, array) => { 332 | if (index === 0) { 333 | uniqueSupportLines.push(supportLine); 334 | } 335 | 336 | if (index > 0) { 337 | const isUnique = uniqueSupportLines.every(uniqueSupportLine => { 338 | return Math.abs(supportLine.l - uniqueSupportLine.l) > 2 * averageBarHeight; 339 | }); 340 | 341 | if (isUnique) { 342 | uniqueSupportLines.push(supportLine); 343 | } 344 | } 345 | }); 346 | 347 | const uniqueResistanceLines: CandlestickData[] = []; 348 | 349 | resistanceLines.forEach((resistanceLine, index, array) => { 350 | if (index === 0) { 351 | uniqueResistanceLines.push(resistanceLine); 352 | } 353 | 354 | if (index > 0) { 355 | const isUnique = uniqueResistanceLines.every(uniqueResistanceLine => { 356 | return Math.abs(resistanceLine.h - uniqueResistanceLine.h) > 2 * averageBarHeight; 357 | }); 358 | 359 | if (isUnique) { 360 | uniqueResistanceLines.push(resistanceLine); 361 | } 362 | } 363 | }); 364 | 365 | return { 366 | supportLines: uniqueSupportLines, 367 | resistanceLines: uniqueResistanceLines 368 | } 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottocoster/interactive-brokers-trading-bot-tutorial/a381aa504b25ba81ecdb5e6bd9a7648f39db551c/fe/angular/ib-trading-bot/src/assets/.gitkeep -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/assets/chartjs-chart-financial.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @license 3 | * chartjs-chart-financial 4 | * http://chartjs.org/ 5 | * Version: 0.1.0 6 | * 7 | * Copyright 2020 Chart.js Contributors 8 | * Released under the MIT license 9 | * https://github.com/chartjs/chartjs-chart-financial/blob/master/LICENSE.md 10 | */ 11 | (function (global, factory) { 12 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('chart.js')) : 13 | typeof define === 'function' && define.amd ? define(['chart.js'], factory) : 14 | (global = global || self, factory(global.Chart)); 15 | }(this, (function (Chart) { 'use strict'; 16 | 17 | Chart = Chart && Object.prototype.hasOwnProperty.call(Chart, 'default') ? Chart['default'] : Chart; 18 | 19 | const helpers = Chart.helpers; 20 | 21 | Chart.defaults.financial = { 22 | label: '', 23 | 24 | parsing: false, 25 | 26 | hover: { 27 | mode: 'label' 28 | }, 29 | 30 | datasets: { 31 | categoryPercentage: 0.8, 32 | barPercentage: 0.9, 33 | animation: { 34 | numbers: { 35 | type: 'number', 36 | properties: ['x', 'y', 'base', 'width', 'open', 'high', 'low', 'close'] 37 | } 38 | } 39 | }, 40 | 41 | scales: { 42 | x: { 43 | type: 'time', 44 | distribution: 'series', 45 | offset: true, 46 | ticks: { 47 | major: { 48 | enabled: true, 49 | }, 50 | fontStyle: context => context.tick.major ? 'bold' : undefined, 51 | source: 'data', 52 | maxRotation: 0, 53 | autoSkip: true, 54 | autoSkipPadding: 75, 55 | sampleSize: 100 56 | }, 57 | afterBuildTicks: scale => { 58 | const DateTime = window && window.luxon && window.luxon.DateTime; 59 | if (!DateTime) { 60 | return; 61 | } 62 | const majorUnit = scale._majorUnit; 63 | const ticks = scale.ticks; 64 | const firstTick = ticks[0]; 65 | 66 | let val = DateTime.fromMillis(ticks[0].value); 67 | if ((majorUnit === 'minute' && val.second === 0) 68 | || (majorUnit === 'hour' && val.minute === 0) 69 | || (majorUnit === 'day' && val.hour === 9) 70 | || (majorUnit === 'month' && val.day <= 3 && val.weekday === 1) 71 | || (majorUnit === 'year' && val.month === 1)) { 72 | firstTick.major = true; 73 | } else { 74 | firstTick.major = false; 75 | } 76 | let lastMajor = val.get(majorUnit); 77 | 78 | for (let i = 1; i < ticks.length; i++) { 79 | const tick = ticks[i]; 80 | val = DateTime.fromMillis(tick.value); 81 | const currMajor = val.get(majorUnit); 82 | tick.major = currMajor !== lastMajor; 83 | lastMajor = currMajor; 84 | } 85 | scale.ticks = ticks; 86 | } 87 | }, 88 | y: { 89 | type: 'linear' 90 | } 91 | }, 92 | 93 | tooltips: { 94 | intersect: false, 95 | mode: 'index', 96 | callbacks: { 97 | label(tooltipItem, data) { 98 | const dataset = data.datasets[tooltipItem.datasetIndex]; 99 | const point = dataset.data[tooltipItem.index]; 100 | 101 | if (!helpers.isNullOrUndef(point.y)) { 102 | return Chart.defaults.tooltips.callbacks.label(tooltipItem, data); 103 | } 104 | 105 | const {o, h, l, c} = point; 106 | 107 | return 'O: ' + o + ' H: ' + h + ' L: ' + l + ' C: ' + c; 108 | } 109 | } 110 | } 111 | }; 112 | 113 | /** 114 | * This class is based off controller.bar.js from the upstream Chart.js library 115 | */ 116 | class FinancialController extends Chart.controllers.bar { 117 | 118 | getLabelAndValue(index) { 119 | const me = this; 120 | const parsed = me.getParsed(index); 121 | 122 | const {o, h, l, c} = parsed; 123 | const value = 'O: ' + o + ' H: ' + h + ' L: ' + l + ' C: ' + c; 124 | 125 | return { 126 | label: '' + me._cachedMeta.iScale.getLabelForValue(parsed.t), 127 | value 128 | }; 129 | } 130 | 131 | getAllParsedValues() { 132 | const parsed = this._cachedMeta._parsed; 133 | const values = []; 134 | for (let i = 0; i < parsed.length; ++i) { 135 | values.push(parsed[i].t); 136 | } 137 | return values; 138 | } 139 | 140 | /** 141 | * Implement this ourselves since it doesn't handle high and low values 142 | * https://github.com/chartjs/Chart.js/issues/7328 143 | * @protected 144 | */ 145 | getMinMax(scale) { 146 | const meta = this._cachedMeta; 147 | const _parsed = meta._parsed; 148 | 149 | if (_parsed.length < 2) { 150 | return {min: 0, max: 1}; 151 | } 152 | 153 | if (scale === meta.iScale) { 154 | return {min: _parsed[0].t, max: _parsed[_parsed.length - 1].t}; 155 | } 156 | 157 | let min = Number.POSITIVE_INFINITY; 158 | let max = Number.NEGATIVE_INFINITY; 159 | for (let i = 0; i < _parsed.length; i++) { 160 | const data = _parsed[i]; 161 | min = Math.min(min, data.l); 162 | max = Math.max(max, data.h); 163 | } 164 | return {min, max}; 165 | } 166 | 167 | _getRuler() { 168 | const me = this; 169 | const meta = me._cachedMeta; 170 | const iScale = meta.iScale; 171 | const pixels = []; 172 | for (let i = 0; i < meta.data.length; ++i) { 173 | pixels.push(iScale.getPixelForValue(me.getParsed(i).t)); 174 | } 175 | return { 176 | pixels, 177 | start: iScale._startPixel, 178 | end: iScale._endPixel, 179 | stackCount: me._getStackCount(), 180 | scale: iScale 181 | }; 182 | } 183 | 184 | /** 185 | * @protected 186 | */ 187 | calculateElementProperties(index, ruler, reset, options) { 188 | const me = this; 189 | const vscale = me._getValueScale(); 190 | const base = vscale.getBasePixel(); 191 | const ipixels = me._calculateBarIndexPixels(index, ruler, options); 192 | const data = me.chart.data.datasets[me.index].data[index]; 193 | const open = vscale.getPixelForValue(data.o); 194 | const high = vscale.getPixelForValue(data.h); 195 | const low = vscale.getPixelForValue(data.l); 196 | const close = vscale.getPixelForValue(data.c); 197 | 198 | return { 199 | base: reset ? base : low, 200 | x: ipixels.center, 201 | y: (low + high) / 2, 202 | width: ipixels.size, 203 | open, 204 | high, 205 | low, 206 | close 207 | }; 208 | } 209 | 210 | draw() { 211 | const me = this; 212 | const chart = me.chart; 213 | const rects = me._cachedMeta.data; 214 | helpers.canvas.clipArea(chart.ctx, chart.chartArea); 215 | for (let i = 0; i < rects.length; ++i) { 216 | rects[i].draw(me._ctx); 217 | } 218 | helpers.canvas.unclipArea(chart.ctx); 219 | } 220 | 221 | } 222 | 223 | FinancialController.prototype.dataElementType = Chart.elements.Financial; 224 | 225 | const globalOpts = Chart.defaults; 226 | 227 | globalOpts.elements.financial = { 228 | color: { 229 | up: 'rgba(80, 160, 115, 1)', 230 | down: 'rgba(215, 85, 65, 1)', 231 | unchanged: 'rgba(90, 90, 90, 1)', 232 | } 233 | }; 234 | 235 | /** 236 | * Helper function to get the bounds of the bar regardless of the orientation 237 | * @param {Rectangle} bar the bar 238 | * @param {boolean} [useFinalPosition] 239 | * @return {object} bounds of the bar 240 | * @private 241 | */ 242 | function getBarBounds(bar, useFinalPosition) { 243 | const {x, y, base, width, height} = bar.getProps(['x', 'low', 'high', 'width', 'height'], useFinalPosition); 244 | 245 | let left, right, top, bottom, half; 246 | 247 | if (bar.horizontal) { 248 | half = height / 2; 249 | left = Math.min(x, base); 250 | right = Math.max(x, base); 251 | top = y - half; 252 | bottom = y + half; 253 | } else { 254 | half = width / 2; 255 | left = x - half; 256 | right = x + half; 257 | top = Math.min(y, base); // use min because 0 pixel at top of screen 258 | bottom = Math.max(y, base); 259 | } 260 | 261 | return {left, top, right, bottom}; 262 | } 263 | 264 | function inRange(bar, x, y, useFinalPosition) { 265 | const skipX = x === null; 266 | const skipY = y === null; 267 | const bounds = !bar || (skipX && skipY) ? false : getBarBounds(bar, useFinalPosition); 268 | 269 | return bounds 270 | && (skipX || x >= bounds.left && x <= bounds.right) 271 | && (skipY || y >= bounds.top && y <= bounds.bottom); 272 | } 273 | 274 | class FinancialElement extends Chart.Element { 275 | 276 | height() { 277 | return this.base - this.y; 278 | } 279 | 280 | inRange(mouseX, mouseY, useFinalPosition) { 281 | return inRange(this, mouseX, mouseY, useFinalPosition); 282 | } 283 | 284 | inXRange(mouseX, useFinalPosition) { 285 | return inRange(this, mouseX, null, useFinalPosition); 286 | } 287 | 288 | inYRange(mouseY, useFinalPosition) { 289 | return inRange(this, null, mouseY, useFinalPosition); 290 | } 291 | 292 | getRange(axis) { 293 | return axis === 'x' ? this.width / 2 : this.height / 2; 294 | } 295 | 296 | getCenterPoint(useFinalPosition) { 297 | const {x, low, high} = this.getProps(['x', 'low', 'high'], useFinalPosition); 298 | return { 299 | x, 300 | y: (high + low) / 2 301 | }; 302 | } 303 | 304 | tooltipPosition(useFinalPosition) { 305 | const {x, open, close} = this.getProps(['x', 'open', 'close'], useFinalPosition); 306 | return { 307 | x, 308 | y: (open + close) / 2 309 | }; 310 | } 311 | } 312 | 313 | const helpers$1 = Chart.helpers; 314 | const globalOpts$1 = Chart.defaults; 315 | 316 | globalOpts$1.elements.candlestick = helpers$1.merge({}, [globalOpts$1.elements.financial, { 317 | borderColor: globalOpts$1.elements.financial.color.unchanged, 318 | borderWidth: 1, 319 | }]); 320 | 321 | class CandlestickElement extends FinancialElement { 322 | draw(ctx) { 323 | const me = this; 324 | 325 | const {x, open, high, low, close} = me; 326 | 327 | let borderColors = me.borderColor; 328 | if (typeof borderColors === 'string') { 329 | borderColors = { 330 | up: borderColors, 331 | down: borderColors, 332 | unchanged: borderColors 333 | }; 334 | } 335 | 336 | let borderColor; 337 | if (close < open) { 338 | borderColor = helpers$1.valueOrDefault(borderColors ? borderColors.up : undefined, globalOpts$1.elements.candlestick.borderColor); 339 | ctx.fillStyle = helpers$1.valueOrDefault(me.color ? me.color.up : undefined, globalOpts$1.elements.candlestick.color.up); 340 | } else if (close > open) { 341 | borderColor = helpers$1.valueOrDefault(borderColors ? borderColors.down : undefined, globalOpts$1.elements.candlestick.borderColor); 342 | ctx.fillStyle = helpers$1.valueOrDefault(me.color ? me.color.down : undefined, globalOpts$1.elements.candlestick.color.down); 343 | } else { 344 | borderColor = helpers$1.valueOrDefault(borderColors ? borderColors.unchanged : undefined, globalOpts$1.elements.candlestick.borderColor); 345 | ctx.fillStyle = helpers$1.valueOrDefault(me.color ? me.color.unchanged : undefined, globalOpts$1.elements.candlestick.color.unchanged); 346 | } 347 | 348 | ctx.lineWidth = helpers$1.valueOrDefault(me.borderWidth, globalOpts$1.elements.candlestick.borderWidth); 349 | ctx.strokeStyle = helpers$1.valueOrDefault(borderColor, globalOpts$1.elements.candlestick.borderColor); 350 | 351 | ctx.beginPath(); 352 | ctx.moveTo(x, high); 353 | ctx.lineTo(x, Math.min(open, close)); 354 | ctx.moveTo(x, low); 355 | ctx.lineTo(x, Math.max(open, close)); 356 | ctx.stroke(); 357 | ctx.fillRect(x - me.width / 2, close, me.width, open - close); 358 | ctx.strokeRect(x - me.width / 2, close, me.width, open - close); 359 | ctx.closePath(); 360 | } 361 | } 362 | 363 | Chart.defaults.candlestick = Chart.helpers.merge({}, Chart.defaults.financial); 364 | 365 | class CandlestickController extends FinancialController { 366 | 367 | updateElements(elements, start, mode) { 368 | const me = this; 369 | const dataset = me.getDataset(); 370 | const ruler = me._ruler || me._getRuler(); 371 | 372 | for (let i = 0; i < elements.length; i++) { 373 | const index = start + i; 374 | const options = me.resolveDataElementOptions(index, mode); 375 | 376 | const baseProperties = me.calculateElementProperties(index, ruler, mode === 'reset', options); 377 | const properties = { 378 | ...baseProperties, 379 | datasetLabel: dataset.label || '', 380 | // label: '', // to get label value please use dataset.data[index].label 381 | 382 | // Appearance 383 | color: dataset.color, 384 | borderColor: dataset.borderColor, 385 | borderWidth: dataset.borderWidth, 386 | }; 387 | properties.options = options; 388 | 389 | me.updateElement(elements[i], index, properties, mode); 390 | } 391 | } 392 | 393 | } 394 | 395 | CandlestickController.prototype.dataElementType = CandlestickElement; 396 | Chart.controllers.candlestick = CandlestickController; 397 | 398 | const helpers$2 = Chart.helpers; 399 | const globalOpts$2 = Chart.defaults; 400 | 401 | globalOpts$2.elements.ohlc = helpers$2.merge({}, [globalOpts$2.elements.financial, { 402 | lineWidth: 2, 403 | armLength: null, 404 | armLengthRatio: 0.8, 405 | }]); 406 | 407 | class OhlcElement extends FinancialElement { 408 | draw(ctx) { 409 | const me = this; 410 | 411 | const {x, open, high, low, close} = me; 412 | 413 | const armLengthRatio = helpers$2.valueOrDefault(me.armLengthRatio, globalOpts$2.elements.ohlc.armLengthRatio); 414 | let armLength = helpers$2.valueOrDefault(me.armLength, globalOpts$2.elements.ohlc.armLength); 415 | if (armLength === null) { 416 | // The width of an ohlc is affected by barPercentage and categoryPercentage 417 | // This behavior is caused by extending controller.financial, which extends controller.bar 418 | // barPercentage and categoryPercentage are now set to 1.0 (see controller.ohlc) 419 | // and armLengthRatio is multipled by 0.5, 420 | // so that when armLengthRatio=1.0, the arms from neighbour ohcl touch, 421 | // and when armLengthRatio=0.0, ohcl are just vertical lines. 422 | armLength = me.width * armLengthRatio * 0.5; 423 | } 424 | 425 | if (close < open) { 426 | ctx.strokeStyle = helpers$2.valueOrDefault(me.color ? me.color.up : undefined, globalOpts$2.elements.ohlc.color.up); 427 | } else if (close > open) { 428 | ctx.strokeStyle = helpers$2.valueOrDefault(me.color ? me.color.down : undefined, globalOpts$2.elements.ohlc.color.down); 429 | } else { 430 | ctx.strokeStyle = helpers$2.valueOrDefault(me.color ? me.color.unchanged : undefined, globalOpts$2.elements.ohlc.color.unchanged); 431 | } 432 | ctx.lineWidth = helpers$2.valueOrDefault(me.lineWidth, globalOpts$2.elements.ohlc.lineWidth); 433 | 434 | ctx.beginPath(); 435 | ctx.moveTo(x, high); 436 | ctx.lineTo(x, low); 437 | ctx.moveTo(x - armLength, open); 438 | ctx.lineTo(x, open); 439 | ctx.moveTo(x + armLength, close); 440 | ctx.lineTo(x, close); 441 | ctx.stroke(); 442 | } 443 | } 444 | 445 | Chart.defaults.ohlc = Chart.helpers.merge({}, Chart.defaults.financial); 446 | Chart.defaults.set('ohlc', { 447 | datasets: { 448 | barPercentage: 1.0, 449 | categoryPercentage: 1.0 450 | } 451 | }); 452 | 453 | class OhlcController extends FinancialController { 454 | 455 | updateElements(elements, start, mode) { 456 | const me = this; 457 | const dataset = me.getDataset(); 458 | const ruler = me._ruler || me._getRuler(); 459 | 460 | for (let i = 0; i < elements.length; i++) { 461 | const index = start + i; 462 | const options = me.resolveDataElementOptions(index, mode); 463 | 464 | const baseProperties = me.calculateElementProperties(index, ruler, mode === 'reset', options); 465 | const properties = { 466 | ...baseProperties, 467 | datasetLabel: dataset.label || '', 468 | lineWidth: dataset.lineWidth, 469 | armLength: dataset.armLength, 470 | armLengthRatio: dataset.armLengthRatio, 471 | color: dataset.color, 472 | }; 473 | properties.options = options; 474 | 475 | me.updateElement(elements[i], index, properties, mode); 476 | } 477 | } 478 | 479 | } 480 | 481 | OhlcController.prototype.dataElementType = OhlcElement; 482 | Chart.controllers.ohlc = OhlcController; 483 | 484 | }))); 485 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottocoster/interactive-brokers-trading-bot-tutorial/a381aa504b25ba81ecdb5e6bd9a7648f39db551c/fe/angular/ib-trading-bot/src/favicon.ico -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IbTradingBot 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** 38 | * If the application will be indexed by Google Search, the following is required. 39 | * Googlebot uses a renderer based on Chrome 41. 40 | * https://developers.google.com/search/docs/guides/rendering 41 | **/ 42 | // import 'core-js/es6/array'; 43 | 44 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 45 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 46 | 47 | /** IE10 and IE11 requires the following for the Reflect API. */ 48 | // import 'core-js/es6/reflect'; 49 | 50 | /** 51 | * Web Animations `@angular/platform-browser/animations` 52 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 53 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 54 | **/ 55 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 56 | 57 | /** 58 | * By default, zone.js will patch all possible macroTask and DomEvents 59 | * user can disable parts of macroTask/DomEvents patch by setting following flags 60 | */ 61 | 62 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 63 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 64 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 65 | 66 | /* 67 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 68 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 69 | */ 70 | // (window as any).__Zone_enable_cross_context_check = true; 71 | 72 | /*************************************************************************************************** 73 | * Zone JS is required by default for Angular itself. 74 | */ 75 | import 'zone.js/dist/zone'; // Included with Angular CLI. 76 | 77 | 78 | /*************************************************************************************************** 79 | * APPLICATION IMPORTS 80 | */ 81 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "target": "es5", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "es2018", 18 | "dom" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /fe/angular/ib-trading-bot/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-redundant-jsdoc": true, 69 | "no-shadowed-variable": true, 70 | "no-string-literal": false, 71 | "no-string-throw": true, 72 | "no-switch-case-fall-through": true, 73 | "no-trailing-whitespace": true, 74 | "no-unnecessary-initializer": true, 75 | "no-unused-expression": true, 76 | "no-use-before-declare": true, 77 | "no-var-keyword": true, 78 | "object-literal-sort-keys": false, 79 | "one-line": [ 80 | true, 81 | "check-open-brace", 82 | "check-catch", 83 | "check-else", 84 | "check-whitespace" 85 | ], 86 | "prefer-const": true, 87 | "quotemark": [ 88 | true, 89 | "single" 90 | ], 91 | "radix": true, 92 | "semicolon": [ 93 | true, 94 | "always" 95 | ], 96 | "triple-equals": [ 97 | true, 98 | "allow-null-check" 99 | ], 100 | "typedef-whitespace": [ 101 | true, 102 | { 103 | "call-signature": "nospace", 104 | "index-signature": "nospace", 105 | "parameter": "nospace", 106 | "property-declaration": "nospace", 107 | "variable-declaration": "nospace" 108 | } 109 | ], 110 | "unified-signatures": true, 111 | "variable-name": false, 112 | "whitespace": [ 113 | true, 114 | "check-branch", 115 | "check-decl", 116 | "check-operator", 117 | "check-separator", 118 | "check-type" 119 | ], 120 | "no-output-on-prefix": true, 121 | "use-input-property-decorator": true, 122 | "use-output-property-decorator": true, 123 | "use-host-property-decorator": true, 124 | "no-input-rename": true, 125 | "no-output-rename": true, 126 | "use-life-cycle-interface": true, 127 | "use-pipe-transform-interface": true, 128 | "component-class-suffix": true, 129 | "directive-class-suffix": true 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ib-trading-bot", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@stoqey/ib": { 8 | "version": "0.1.0", 9 | "resolved": "https://registry.npmjs.org/@stoqey/ib/-/ib-0.1.0.tgz", 10 | "integrity": "sha512-9I6MYWBgQzcjJGo7StWvdI5sxzGaiqDPxH6omc8sg2E/uKeWeK4qezJyhewG14FNxV4LQI3NO8f8T2h/2zqODg==", 11 | "requires": { 12 | "chalk": "^4.0.0", 13 | "command-buffer": "^0.1.0", 14 | "dotenv": "^8.2.0", 15 | "function-rate-limit": "^1.1.0", 16 | "lodash": "^4.17.20", 17 | "moment": "^2.24.0" 18 | } 19 | }, 20 | "@types/body-parser": { 21 | "version": "1.19.0", 22 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", 23 | "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", 24 | "requires": { 25 | "@types/connect": "*", 26 | "@types/node": "*" 27 | } 28 | }, 29 | "@types/color-name": { 30 | "version": "1.1.1", 31 | "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", 32 | "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" 33 | }, 34 | "@types/connect": { 35 | "version": "3.4.33", 36 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", 37 | "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", 38 | "requires": { 39 | "@types/node": "*" 40 | } 41 | }, 42 | "@types/express": { 43 | "version": "4.17.8", 44 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz", 45 | "integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==", 46 | "requires": { 47 | "@types/body-parser": "*", 48 | "@types/express-serve-static-core": "*", 49 | "@types/qs": "*", 50 | "@types/serve-static": "*" 51 | } 52 | }, 53 | "@types/express-serve-static-core": { 54 | "version": "4.17.12", 55 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.12.tgz", 56 | "integrity": "sha512-EaEdY+Dty1jEU7U6J4CUWwxL+hyEGMkO5jan5gplfegUgCUsIUWqXxqw47uGjimeT4Qgkz/XUfwoau08+fgvKA==", 57 | "requires": { 58 | "@types/node": "*", 59 | "@types/qs": "*", 60 | "@types/range-parser": "*" 61 | } 62 | }, 63 | "@types/mime": { 64 | "version": "2.0.3", 65 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", 66 | "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" 67 | }, 68 | "@types/node": { 69 | "version": "14.6.4", 70 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz", 71 | "integrity": "sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ==" 72 | }, 73 | "@types/qs": { 74 | "version": "6.9.4", 75 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz", 76 | "integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==" 77 | }, 78 | "@types/range-parser": { 79 | "version": "1.2.3", 80 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", 81 | "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" 82 | }, 83 | "@types/serve-static": { 84 | "version": "1.13.5", 85 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz", 86 | "integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==", 87 | "requires": { 88 | "@types/express-serve-static-core": "*", 89 | "@types/mime": "*" 90 | } 91 | }, 92 | "@types/strip-bom": { 93 | "version": "3.0.0", 94 | "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", 95 | "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=" 96 | }, 97 | "@types/strip-json-comments": { 98 | "version": "0.0.30", 99 | "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", 100 | "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==" 101 | }, 102 | "@types/ws": { 103 | "version": "7.2.6", 104 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.6.tgz", 105 | "integrity": "sha512-Q07IrQUSNpr+cXU4E4LtkSIBPie5GLZyyMC1QtQYRLWz701+XcoVygGUZgvLqElq1nU4ICldMYPnexlBsg3dqQ==", 106 | "requires": { 107 | "@types/node": "*" 108 | } 109 | }, 110 | "abbrev": { 111 | "version": "1.0.9", 112 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", 113 | "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", 114 | "optional": true 115 | }, 116 | "accepts": { 117 | "version": "1.3.7", 118 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 119 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 120 | "requires": { 121 | "mime-types": "~2.1.24", 122 | "negotiator": "0.6.2" 123 | } 124 | }, 125 | "amdefine": { 126 | "version": "1.0.1", 127 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 128 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", 129 | "optional": true 130 | }, 131 | "ansi-styles": { 132 | "version": "4.2.1", 133 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", 134 | "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", 135 | "requires": { 136 | "@types/color-name": "^1.1.1", 137 | "color-convert": "^2.0.1" 138 | } 139 | }, 140 | "anymatch": { 141 | "version": "3.1.1", 142 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 143 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 144 | "requires": { 145 | "normalize-path": "^3.0.0", 146 | "picomatch": "^2.0.4" 147 | } 148 | }, 149 | "arg": { 150 | "version": "4.1.3", 151 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 152 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" 153 | }, 154 | "argparse": { 155 | "version": "1.0.10", 156 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 157 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 158 | "optional": true, 159 | "requires": { 160 | "sprintf-js": "~1.0.2" 161 | } 162 | }, 163 | "array-find-index": { 164 | "version": "1.0.2", 165 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", 166 | "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" 167 | }, 168 | "array-flatten": { 169 | "version": "1.1.1", 170 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 171 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 172 | }, 173 | "async": { 174 | "version": "1.5.2", 175 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 176 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 177 | "optional": true 178 | }, 179 | "balanced-match": { 180 | "version": "1.0.0", 181 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 182 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 183 | }, 184 | "binary-extensions": { 185 | "version": "2.1.0", 186 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", 187 | "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" 188 | }, 189 | "body-parser": { 190 | "version": "1.19.0", 191 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 192 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 193 | "requires": { 194 | "bytes": "3.1.0", 195 | "content-type": "~1.0.4", 196 | "debug": "2.6.9", 197 | "depd": "~1.1.2", 198 | "http-errors": "1.7.2", 199 | "iconv-lite": "0.4.24", 200 | "on-finished": "~2.3.0", 201 | "qs": "6.7.0", 202 | "raw-body": "2.4.0", 203 | "type-is": "~1.6.17" 204 | } 205 | }, 206 | "brace-expansion": { 207 | "version": "1.1.11", 208 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 209 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 210 | "requires": { 211 | "balanced-match": "^1.0.0", 212 | "concat-map": "0.0.1" 213 | } 214 | }, 215 | "braces": { 216 | "version": "3.0.2", 217 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 218 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 219 | "requires": { 220 | "fill-range": "^7.0.1" 221 | } 222 | }, 223 | "buffer-from": { 224 | "version": "1.1.1", 225 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 226 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 227 | }, 228 | "bytes": { 229 | "version": "3.1.0", 230 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 231 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 232 | }, 233 | "camelcase": { 234 | "version": "2.1.1", 235 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", 236 | "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" 237 | }, 238 | "camelcase-keys": { 239 | "version": "2.1.0", 240 | "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", 241 | "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", 242 | "requires": { 243 | "camelcase": "^2.0.0", 244 | "map-obj": "^1.0.0" 245 | } 246 | }, 247 | "chalk": { 248 | "version": "4.1.0", 249 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 250 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 251 | "requires": { 252 | "ansi-styles": "^4.1.0", 253 | "supports-color": "^7.1.0" 254 | } 255 | }, 256 | "chokidar": { 257 | "version": "3.4.2", 258 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", 259 | "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", 260 | "requires": { 261 | "anymatch": "~3.1.1", 262 | "braces": "~3.0.2", 263 | "fsevents": "~2.1.2", 264 | "glob-parent": "~5.1.0", 265 | "is-binary-path": "~2.1.0", 266 | "is-glob": "~4.0.1", 267 | "normalize-path": "~3.0.0", 268 | "readdirp": "~3.4.0" 269 | } 270 | }, 271 | "color-convert": { 272 | "version": "2.0.1", 273 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 274 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 275 | "requires": { 276 | "color-name": "~1.1.4" 277 | } 278 | }, 279 | "color-name": { 280 | "version": "1.1.4", 281 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 282 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 283 | }, 284 | "command-buffer": { 285 | "version": "0.1.0", 286 | "resolved": "https://registry.npmjs.org/command-buffer/-/command-buffer-0.1.0.tgz", 287 | "integrity": "sha1-ztP0D3cokxTbkct37zsAwzLo4mg=" 288 | }, 289 | "concat-map": { 290 | "version": "0.0.1", 291 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 292 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 293 | }, 294 | "content-disposition": { 295 | "version": "0.5.3", 296 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 297 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 298 | "requires": { 299 | "safe-buffer": "5.1.2" 300 | } 301 | }, 302 | "content-type": { 303 | "version": "1.0.4", 304 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 305 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 306 | }, 307 | "cookie": { 308 | "version": "0.4.0", 309 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 310 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 311 | }, 312 | "cookie-signature": { 313 | "version": "1.0.6", 314 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 315 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 316 | }, 317 | "currently-unhandled": { 318 | "version": "0.4.1", 319 | "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", 320 | "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", 321 | "requires": { 322 | "array-find-index": "^1.0.1" 323 | } 324 | }, 325 | "dateformat": { 326 | "version": "1.0.12", 327 | "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", 328 | "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", 329 | "requires": { 330 | "get-stdin": "^4.0.1", 331 | "meow": "^3.3.0" 332 | } 333 | }, 334 | "debug": { 335 | "version": "2.6.9", 336 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 337 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 338 | "requires": { 339 | "ms": "2.0.0" 340 | } 341 | }, 342 | "decamelize": { 343 | "version": "1.2.0", 344 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 345 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" 346 | }, 347 | "deep-is": { 348 | "version": "0.1.3", 349 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 350 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 351 | "optional": true 352 | }, 353 | "depd": { 354 | "version": "1.1.2", 355 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 356 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 357 | }, 358 | "destroy": { 359 | "version": "1.0.4", 360 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 361 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 362 | }, 363 | "diff": { 364 | "version": "4.0.2", 365 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 366 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" 367 | }, 368 | "dotenv": { 369 | "version": "8.2.0", 370 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", 371 | "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" 372 | }, 373 | "dynamic-dedupe": { 374 | "version": "0.3.0", 375 | "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", 376 | "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", 377 | "requires": { 378 | "xtend": "^4.0.0" 379 | } 380 | }, 381 | "ee-first": { 382 | "version": "1.1.1", 383 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 384 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 385 | }, 386 | "encodeurl": { 387 | "version": "1.0.2", 388 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 389 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 390 | }, 391 | "error-ex": { 392 | "version": "1.3.2", 393 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 394 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 395 | "requires": { 396 | "is-arrayish": "^0.2.1" 397 | } 398 | }, 399 | "escape-html": { 400 | "version": "1.0.3", 401 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 402 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 403 | }, 404 | "escodegen": { 405 | "version": "1.8.1", 406 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", 407 | "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", 408 | "optional": true, 409 | "requires": { 410 | "esprima": "^2.7.1", 411 | "estraverse": "^1.9.1", 412 | "esutils": "^2.0.2", 413 | "optionator": "^0.8.1", 414 | "source-map": "~0.2.0" 415 | }, 416 | "dependencies": { 417 | "source-map": { 418 | "version": "0.2.0", 419 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", 420 | "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", 421 | "optional": true, 422 | "requires": { 423 | "amdefine": ">=0.0.4" 424 | } 425 | } 426 | } 427 | }, 428 | "esprima": { 429 | "version": "2.7.3", 430 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", 431 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", 432 | "optional": true 433 | }, 434 | "estraverse": { 435 | "version": "1.9.3", 436 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", 437 | "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", 438 | "optional": true 439 | }, 440 | "esutils": { 441 | "version": "2.0.3", 442 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 443 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 444 | "optional": true 445 | }, 446 | "etag": { 447 | "version": "1.8.1", 448 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 449 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 450 | }, 451 | "express": { 452 | "version": "4.17.1", 453 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 454 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 455 | "requires": { 456 | "accepts": "~1.3.7", 457 | "array-flatten": "1.1.1", 458 | "body-parser": "1.19.0", 459 | "content-disposition": "0.5.3", 460 | "content-type": "~1.0.4", 461 | "cookie": "0.4.0", 462 | "cookie-signature": "1.0.6", 463 | "debug": "2.6.9", 464 | "depd": "~1.1.2", 465 | "encodeurl": "~1.0.2", 466 | "escape-html": "~1.0.3", 467 | "etag": "~1.8.1", 468 | "finalhandler": "~1.1.2", 469 | "fresh": "0.5.2", 470 | "merge-descriptors": "1.0.1", 471 | "methods": "~1.1.2", 472 | "on-finished": "~2.3.0", 473 | "parseurl": "~1.3.3", 474 | "path-to-regexp": "0.1.7", 475 | "proxy-addr": "~2.0.5", 476 | "qs": "6.7.0", 477 | "range-parser": "~1.2.1", 478 | "safe-buffer": "5.1.2", 479 | "send": "0.17.1", 480 | "serve-static": "1.14.1", 481 | "setprototypeof": "1.1.1", 482 | "statuses": "~1.5.0", 483 | "type-is": "~1.6.18", 484 | "utils-merge": "1.0.1", 485 | "vary": "~1.1.2" 486 | } 487 | }, 488 | "fast-levenshtein": { 489 | "version": "2.0.6", 490 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 491 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 492 | "optional": true 493 | }, 494 | "fill-range": { 495 | "version": "7.0.1", 496 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 497 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 498 | "requires": { 499 | "to-regex-range": "^5.0.1" 500 | } 501 | }, 502 | "finalhandler": { 503 | "version": "1.1.2", 504 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 505 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 506 | "requires": { 507 | "debug": "2.6.9", 508 | "encodeurl": "~1.0.2", 509 | "escape-html": "~1.0.3", 510 | "on-finished": "~2.3.0", 511 | "parseurl": "~1.3.3", 512 | "statuses": "~1.5.0", 513 | "unpipe": "~1.0.0" 514 | } 515 | }, 516 | "find-up": { 517 | "version": "1.1.2", 518 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 519 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 520 | "requires": { 521 | "path-exists": "^2.0.0", 522 | "pinkie-promise": "^2.0.0" 523 | } 524 | }, 525 | "forwarded": { 526 | "version": "0.1.2", 527 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 528 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 529 | }, 530 | "fresh": { 531 | "version": "0.5.2", 532 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 533 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 534 | }, 535 | "fs.realpath": { 536 | "version": "1.0.0", 537 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 538 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 539 | }, 540 | "fsevents": { 541 | "version": "2.1.3", 542 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", 543 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", 544 | "optional": true 545 | }, 546 | "function-rate-limit": { 547 | "version": "1.1.0", 548 | "resolved": "https://registry.npmjs.org/function-rate-limit/-/function-rate-limit-1.1.0.tgz", 549 | "integrity": "sha1-7M3xr5GPyVnrZQkFhgPkYuN/1oM=" 550 | }, 551 | "get-stdin": { 552 | "version": "4.0.1", 553 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", 554 | "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" 555 | }, 556 | "glob": { 557 | "version": "7.1.6", 558 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 559 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 560 | "requires": { 561 | "fs.realpath": "^1.0.0", 562 | "inflight": "^1.0.4", 563 | "inherits": "2", 564 | "minimatch": "^3.0.4", 565 | "once": "^1.3.0", 566 | "path-is-absolute": "^1.0.0" 567 | } 568 | }, 569 | "glob-parent": { 570 | "version": "5.1.1", 571 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 572 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 573 | "requires": { 574 | "is-glob": "^4.0.1" 575 | } 576 | }, 577 | "graceful-fs": { 578 | "version": "4.2.4", 579 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", 580 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" 581 | }, 582 | "handlebars": { 583 | "version": "4.7.6", 584 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", 585 | "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", 586 | "optional": true, 587 | "requires": { 588 | "minimist": "^1.2.5", 589 | "neo-async": "^2.6.0", 590 | "source-map": "^0.6.1", 591 | "uglify-js": "^3.1.4", 592 | "wordwrap": "^1.0.0" 593 | } 594 | }, 595 | "has-flag": { 596 | "version": "4.0.0", 597 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 598 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" 599 | }, 600 | "hosted-git-info": { 601 | "version": "2.8.8", 602 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", 603 | "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" 604 | }, 605 | "http-errors": { 606 | "version": "1.7.2", 607 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 608 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 609 | "requires": { 610 | "depd": "~1.1.2", 611 | "inherits": "2.0.3", 612 | "setprototypeof": "1.1.1", 613 | "statuses": ">= 1.5.0 < 2", 614 | "toidentifier": "1.0.0" 615 | }, 616 | "dependencies": { 617 | "inherits": { 618 | "version": "2.0.3", 619 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 620 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 621 | } 622 | } 623 | }, 624 | "iconv-lite": { 625 | "version": "0.4.24", 626 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 627 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 628 | "requires": { 629 | "safer-buffer": ">= 2.1.2 < 3" 630 | } 631 | }, 632 | "indent-string": { 633 | "version": "2.1.0", 634 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", 635 | "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", 636 | "requires": { 637 | "repeating": "^2.0.0" 638 | } 639 | }, 640 | "inflight": { 641 | "version": "1.0.6", 642 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 643 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 644 | "requires": { 645 | "once": "^1.3.0", 646 | "wrappy": "1" 647 | } 648 | }, 649 | "inherits": { 650 | "version": "2.0.4", 651 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 652 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 653 | }, 654 | "ipaddr.js": { 655 | "version": "1.9.1", 656 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 657 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 658 | }, 659 | "is-arrayish": { 660 | "version": "0.2.1", 661 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 662 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" 663 | }, 664 | "is-binary-path": { 665 | "version": "2.1.0", 666 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 667 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 668 | "requires": { 669 | "binary-extensions": "^2.0.0" 670 | } 671 | }, 672 | "is-extglob": { 673 | "version": "2.1.1", 674 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 675 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" 676 | }, 677 | "is-finite": { 678 | "version": "1.1.0", 679 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", 680 | "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" 681 | }, 682 | "is-glob": { 683 | "version": "4.0.1", 684 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 685 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 686 | "requires": { 687 | "is-extglob": "^2.1.1" 688 | } 689 | }, 690 | "is-number": { 691 | "version": "7.0.0", 692 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 693 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" 694 | }, 695 | "is-utf8": { 696 | "version": "0.2.1", 697 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 698 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" 699 | }, 700 | "isexe": { 701 | "version": "2.0.0", 702 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 703 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 704 | "optional": true 705 | }, 706 | "istanbul": { 707 | "version": "0.4.5", 708 | "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", 709 | "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", 710 | "optional": true, 711 | "requires": { 712 | "abbrev": "1.0.x", 713 | "async": "1.x", 714 | "escodegen": "1.8.x", 715 | "esprima": "2.7.x", 716 | "glob": "^5.0.15", 717 | "handlebars": "^4.0.1", 718 | "js-yaml": "3.x", 719 | "mkdirp": "0.5.x", 720 | "nopt": "3.x", 721 | "once": "1.x", 722 | "resolve": "1.1.x", 723 | "supports-color": "^3.1.0", 724 | "which": "^1.1.1", 725 | "wordwrap": "^1.0.0" 726 | }, 727 | "dependencies": { 728 | "glob": { 729 | "version": "5.0.15", 730 | "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", 731 | "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", 732 | "optional": true, 733 | "requires": { 734 | "inflight": "^1.0.4", 735 | "inherits": "2", 736 | "minimatch": "2 || 3", 737 | "once": "^1.3.0", 738 | "path-is-absolute": "^1.0.0" 739 | } 740 | }, 741 | "has-flag": { 742 | "version": "1.0.0", 743 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 744 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 745 | "optional": true 746 | }, 747 | "mkdirp": { 748 | "version": "0.5.5", 749 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 750 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 751 | "optional": true, 752 | "requires": { 753 | "minimist": "^1.2.5" 754 | } 755 | }, 756 | "resolve": { 757 | "version": "1.1.7", 758 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 759 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", 760 | "optional": true 761 | }, 762 | "supports-color": { 763 | "version": "3.2.3", 764 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", 765 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", 766 | "optional": true, 767 | "requires": { 768 | "has-flag": "^1.0.0" 769 | } 770 | } 771 | } 772 | }, 773 | "js-yaml": { 774 | "version": "3.14.0", 775 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", 776 | "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", 777 | "optional": true, 778 | "requires": { 779 | "argparse": "^1.0.7", 780 | "esprima": "^4.0.0" 781 | }, 782 | "dependencies": { 783 | "esprima": { 784 | "version": "4.0.1", 785 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 786 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 787 | "optional": true 788 | } 789 | } 790 | }, 791 | "levn": { 792 | "version": "0.3.0", 793 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 794 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 795 | "optional": true, 796 | "requires": { 797 | "prelude-ls": "~1.1.2", 798 | "type-check": "~0.3.2" 799 | } 800 | }, 801 | "load-json-file": { 802 | "version": "1.1.0", 803 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", 804 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", 805 | "requires": { 806 | "graceful-fs": "^4.1.2", 807 | "parse-json": "^2.2.0", 808 | "pify": "^2.0.0", 809 | "pinkie-promise": "^2.0.0", 810 | "strip-bom": "^2.0.0" 811 | } 812 | }, 813 | "lodash": { 814 | "version": "4.17.20", 815 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 816 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 817 | }, 818 | "loud-rejection": { 819 | "version": "1.6.0", 820 | "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", 821 | "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", 822 | "requires": { 823 | "currently-unhandled": "^0.4.1", 824 | "signal-exit": "^3.0.0" 825 | } 826 | }, 827 | "make-error": { 828 | "version": "1.3.6", 829 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 830 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" 831 | }, 832 | "map-obj": { 833 | "version": "1.0.1", 834 | "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", 835 | "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" 836 | }, 837 | "media-typer": { 838 | "version": "0.3.0", 839 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 840 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 841 | }, 842 | "meow": { 843 | "version": "3.7.0", 844 | "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", 845 | "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", 846 | "requires": { 847 | "camelcase-keys": "^2.0.0", 848 | "decamelize": "^1.1.2", 849 | "loud-rejection": "^1.0.0", 850 | "map-obj": "^1.0.1", 851 | "minimist": "^1.1.3", 852 | "normalize-package-data": "^2.3.4", 853 | "object-assign": "^4.0.1", 854 | "read-pkg-up": "^1.0.1", 855 | "redent": "^1.0.0", 856 | "trim-newlines": "^1.0.0" 857 | } 858 | }, 859 | "merge-descriptors": { 860 | "version": "1.0.1", 861 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 862 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 863 | }, 864 | "methods": { 865 | "version": "1.1.2", 866 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 867 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 868 | }, 869 | "mime": { 870 | "version": "1.6.0", 871 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 872 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 873 | }, 874 | "mime-db": { 875 | "version": "1.44.0", 876 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 877 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" 878 | }, 879 | "mime-types": { 880 | "version": "2.1.27", 881 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 882 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 883 | "requires": { 884 | "mime-db": "1.44.0" 885 | } 886 | }, 887 | "minimatch": { 888 | "version": "3.0.4", 889 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 890 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 891 | "requires": { 892 | "brace-expansion": "^1.1.7" 893 | } 894 | }, 895 | "minimist": { 896 | "version": "1.2.5", 897 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 898 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 899 | }, 900 | "mkdirp": { 901 | "version": "1.0.4", 902 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 903 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" 904 | }, 905 | "moment": { 906 | "version": "2.27.0", 907 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", 908 | "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" 909 | }, 910 | "ms": { 911 | "version": "2.0.0", 912 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 913 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 914 | }, 915 | "negotiator": { 916 | "version": "0.6.2", 917 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 918 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 919 | }, 920 | "neo-async": { 921 | "version": "2.6.2", 922 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 923 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", 924 | "optional": true 925 | }, 926 | "nopt": { 927 | "version": "3.0.6", 928 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", 929 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 930 | "optional": true, 931 | "requires": { 932 | "abbrev": "1" 933 | } 934 | }, 935 | "normalize-package-data": { 936 | "version": "2.5.0", 937 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", 938 | "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", 939 | "requires": { 940 | "hosted-git-info": "^2.1.4", 941 | "resolve": "^1.10.0", 942 | "semver": "2 || 3 || 4 || 5", 943 | "validate-npm-package-license": "^3.0.1" 944 | } 945 | }, 946 | "normalize-path": { 947 | "version": "3.0.0", 948 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 949 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" 950 | }, 951 | "object-assign": { 952 | "version": "4.1.1", 953 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 954 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 955 | }, 956 | "on-finished": { 957 | "version": "2.3.0", 958 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 959 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 960 | "requires": { 961 | "ee-first": "1.1.1" 962 | } 963 | }, 964 | "once": { 965 | "version": "1.4.0", 966 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 967 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 968 | "requires": { 969 | "wrappy": "1" 970 | } 971 | }, 972 | "optionator": { 973 | "version": "0.8.3", 974 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", 975 | "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", 976 | "optional": true, 977 | "requires": { 978 | "deep-is": "~0.1.3", 979 | "fast-levenshtein": "~2.0.6", 980 | "levn": "~0.3.0", 981 | "prelude-ls": "~1.1.2", 982 | "type-check": "~0.3.2", 983 | "word-wrap": "~1.2.3" 984 | } 985 | }, 986 | "parse-json": { 987 | "version": "2.2.0", 988 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 989 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 990 | "requires": { 991 | "error-ex": "^1.2.0" 992 | } 993 | }, 994 | "parseurl": { 995 | "version": "1.3.3", 996 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 997 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 998 | }, 999 | "path-exists": { 1000 | "version": "2.1.0", 1001 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 1002 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 1003 | "requires": { 1004 | "pinkie-promise": "^2.0.0" 1005 | } 1006 | }, 1007 | "path-is-absolute": { 1008 | "version": "1.0.1", 1009 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1010 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1011 | }, 1012 | "path-parse": { 1013 | "version": "1.0.6", 1014 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1015 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 1016 | }, 1017 | "path-to-regexp": { 1018 | "version": "0.1.7", 1019 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1020 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 1021 | }, 1022 | "path-type": { 1023 | "version": "1.1.0", 1024 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", 1025 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", 1026 | "requires": { 1027 | "graceful-fs": "^4.1.2", 1028 | "pify": "^2.0.0", 1029 | "pinkie-promise": "^2.0.0" 1030 | } 1031 | }, 1032 | "picomatch": { 1033 | "version": "2.2.2", 1034 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 1035 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" 1036 | }, 1037 | "pify": { 1038 | "version": "2.3.0", 1039 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1040 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" 1041 | }, 1042 | "pinkie": { 1043 | "version": "2.0.4", 1044 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1045 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" 1046 | }, 1047 | "pinkie-promise": { 1048 | "version": "2.0.1", 1049 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1050 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1051 | "requires": { 1052 | "pinkie": "^2.0.0" 1053 | } 1054 | }, 1055 | "prelude-ls": { 1056 | "version": "1.1.2", 1057 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1058 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1059 | "optional": true 1060 | }, 1061 | "proxy-addr": { 1062 | "version": "2.0.6", 1063 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", 1064 | "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", 1065 | "requires": { 1066 | "forwarded": "~0.1.2", 1067 | "ipaddr.js": "1.9.1" 1068 | } 1069 | }, 1070 | "qs": { 1071 | "version": "6.7.0", 1072 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 1073 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 1074 | }, 1075 | "range-parser": { 1076 | "version": "1.2.1", 1077 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1078 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 1079 | }, 1080 | "raw-body": { 1081 | "version": "2.4.0", 1082 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 1083 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 1084 | "requires": { 1085 | "bytes": "3.1.0", 1086 | "http-errors": "1.7.2", 1087 | "iconv-lite": "0.4.24", 1088 | "unpipe": "1.0.0" 1089 | } 1090 | }, 1091 | "read-pkg": { 1092 | "version": "1.1.0", 1093 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", 1094 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", 1095 | "requires": { 1096 | "load-json-file": "^1.0.0", 1097 | "normalize-package-data": "^2.3.2", 1098 | "path-type": "^1.0.0" 1099 | } 1100 | }, 1101 | "read-pkg-up": { 1102 | "version": "1.0.1", 1103 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", 1104 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", 1105 | "requires": { 1106 | "find-up": "^1.0.0", 1107 | "read-pkg": "^1.0.0" 1108 | } 1109 | }, 1110 | "readdirp": { 1111 | "version": "3.4.0", 1112 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", 1113 | "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", 1114 | "requires": { 1115 | "picomatch": "^2.2.1" 1116 | } 1117 | }, 1118 | "redent": { 1119 | "version": "1.0.0", 1120 | "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", 1121 | "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", 1122 | "requires": { 1123 | "indent-string": "^2.1.0", 1124 | "strip-indent": "^1.0.1" 1125 | } 1126 | }, 1127 | "repeating": { 1128 | "version": "2.0.1", 1129 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", 1130 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", 1131 | "requires": { 1132 | "is-finite": "^1.0.0" 1133 | } 1134 | }, 1135 | "resolve": { 1136 | "version": "1.17.0", 1137 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", 1138 | "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", 1139 | "requires": { 1140 | "path-parse": "^1.0.6" 1141 | } 1142 | }, 1143 | "rimraf": { 1144 | "version": "2.7.1", 1145 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1146 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1147 | "requires": { 1148 | "glob": "^7.1.3" 1149 | } 1150 | }, 1151 | "safe-buffer": { 1152 | "version": "5.1.2", 1153 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1154 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1155 | }, 1156 | "safer-buffer": { 1157 | "version": "2.1.2", 1158 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1159 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1160 | }, 1161 | "semver": { 1162 | "version": "5.7.1", 1163 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 1164 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 1165 | }, 1166 | "send": { 1167 | "version": "0.17.1", 1168 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 1169 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 1170 | "requires": { 1171 | "debug": "2.6.9", 1172 | "depd": "~1.1.2", 1173 | "destroy": "~1.0.4", 1174 | "encodeurl": "~1.0.2", 1175 | "escape-html": "~1.0.3", 1176 | "etag": "~1.8.1", 1177 | "fresh": "0.5.2", 1178 | "http-errors": "~1.7.2", 1179 | "mime": "1.6.0", 1180 | "ms": "2.1.1", 1181 | "on-finished": "~2.3.0", 1182 | "range-parser": "~1.2.1", 1183 | "statuses": "~1.5.0" 1184 | }, 1185 | "dependencies": { 1186 | "ms": { 1187 | "version": "2.1.1", 1188 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 1189 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 1190 | } 1191 | } 1192 | }, 1193 | "serve-static": { 1194 | "version": "1.14.1", 1195 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 1196 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 1197 | "requires": { 1198 | "encodeurl": "~1.0.2", 1199 | "escape-html": "~1.0.3", 1200 | "parseurl": "~1.3.3", 1201 | "send": "0.17.1" 1202 | } 1203 | }, 1204 | "setprototypeof": { 1205 | "version": "1.1.1", 1206 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 1207 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 1208 | }, 1209 | "signal-exit": { 1210 | "version": "3.0.3", 1211 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 1212 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" 1213 | }, 1214 | "source-map": { 1215 | "version": "0.6.1", 1216 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1217 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 1218 | }, 1219 | "source-map-support": { 1220 | "version": "0.5.19", 1221 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 1222 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 1223 | "requires": { 1224 | "buffer-from": "^1.0.0", 1225 | "source-map": "^0.6.0" 1226 | } 1227 | }, 1228 | "spdx-correct": { 1229 | "version": "3.1.1", 1230 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", 1231 | "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", 1232 | "requires": { 1233 | "spdx-expression-parse": "^3.0.0", 1234 | "spdx-license-ids": "^3.0.0" 1235 | } 1236 | }, 1237 | "spdx-exceptions": { 1238 | "version": "2.3.0", 1239 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", 1240 | "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" 1241 | }, 1242 | "spdx-expression-parse": { 1243 | "version": "3.0.1", 1244 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", 1245 | "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", 1246 | "requires": { 1247 | "spdx-exceptions": "^2.1.0", 1248 | "spdx-license-ids": "^3.0.0" 1249 | } 1250 | }, 1251 | "spdx-license-ids": { 1252 | "version": "3.0.5", 1253 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", 1254 | "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" 1255 | }, 1256 | "sprintf-js": { 1257 | "version": "1.0.3", 1258 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1259 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1260 | "optional": true 1261 | }, 1262 | "statuses": { 1263 | "version": "1.5.0", 1264 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 1265 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 1266 | }, 1267 | "strip-bom": { 1268 | "version": "2.0.0", 1269 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", 1270 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", 1271 | "requires": { 1272 | "is-utf8": "^0.2.0" 1273 | } 1274 | }, 1275 | "strip-indent": { 1276 | "version": "1.0.1", 1277 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", 1278 | "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", 1279 | "requires": { 1280 | "get-stdin": "^4.0.1" 1281 | } 1282 | }, 1283 | "strip-json-comments": { 1284 | "version": "2.0.1", 1285 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1286 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" 1287 | }, 1288 | "supports-color": { 1289 | "version": "7.2.0", 1290 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1291 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1292 | "requires": { 1293 | "has-flag": "^4.0.0" 1294 | } 1295 | }, 1296 | "to-regex-range": { 1297 | "version": "5.0.1", 1298 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1299 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1300 | "requires": { 1301 | "is-number": "^7.0.0" 1302 | } 1303 | }, 1304 | "toidentifier": { 1305 | "version": "1.0.0", 1306 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 1307 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 1308 | }, 1309 | "tree-kill": { 1310 | "version": "1.2.2", 1311 | "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", 1312 | "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" 1313 | }, 1314 | "trim-newlines": { 1315 | "version": "1.0.0", 1316 | "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", 1317 | "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" 1318 | }, 1319 | "ts-node": { 1320 | "version": "8.10.2", 1321 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", 1322 | "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", 1323 | "requires": { 1324 | "arg": "^4.1.0", 1325 | "diff": "^4.0.1", 1326 | "make-error": "^1.1.1", 1327 | "source-map-support": "^0.5.17", 1328 | "yn": "3.1.1" 1329 | } 1330 | }, 1331 | "ts-node-dev": { 1332 | "version": "1.0.0-pre.62", 1333 | "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.0.0-pre.62.tgz", 1334 | "integrity": "sha512-hfsEuCqUZOVnZ86l7A3icxD1nFt1HEmLVbx4YOHCkrbSHPBNWcw+IczAPZo3zz7YiOm9vs0xG6OENNrkgm89tQ==", 1335 | "requires": { 1336 | "chokidar": "^3.4.0", 1337 | "dateformat": "~1.0.4-1.2.3", 1338 | "dynamic-dedupe": "^0.3.0", 1339 | "minimist": "^1.2.5", 1340 | "mkdirp": "^1.0.4", 1341 | "resolve": "^1.0.0", 1342 | "rimraf": "^2.6.1", 1343 | "source-map-support": "^0.5.12", 1344 | "tree-kill": "^1.2.2", 1345 | "ts-node": "^8.10.2", 1346 | "tsconfig": "^7.0.0" 1347 | } 1348 | }, 1349 | "tsconfig": { 1350 | "version": "7.0.0", 1351 | "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", 1352 | "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", 1353 | "requires": { 1354 | "@types/strip-bom": "^3.0.0", 1355 | "@types/strip-json-comments": "0.0.30", 1356 | "strip-bom": "^3.0.0", 1357 | "strip-json-comments": "^2.0.0" 1358 | }, 1359 | "dependencies": { 1360 | "strip-bom": { 1361 | "version": "3.0.0", 1362 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 1363 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" 1364 | } 1365 | } 1366 | }, 1367 | "type-check": { 1368 | "version": "0.3.2", 1369 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1370 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1371 | "optional": true, 1372 | "requires": { 1373 | "prelude-ls": "~1.1.2" 1374 | } 1375 | }, 1376 | "type-is": { 1377 | "version": "1.6.18", 1378 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1379 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1380 | "requires": { 1381 | "media-typer": "0.3.0", 1382 | "mime-types": "~2.1.24" 1383 | } 1384 | }, 1385 | "typescript": { 1386 | "version": "4.0.2", 1387 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", 1388 | "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==" 1389 | }, 1390 | "uglify-js": { 1391 | "version": "3.10.4", 1392 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.4.tgz", 1393 | "integrity": "sha512-kBFT3U4Dcj4/pJ52vfjCSfyLyvG9VYYuGYPmrPvAxRw/i7xHiT4VvCev+uiEMcEEiu6UNB6KgWmGtSUYIWScbw==", 1394 | "optional": true 1395 | }, 1396 | "ultron": { 1397 | "version": "1.1.1", 1398 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", 1399 | "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" 1400 | }, 1401 | "unpipe": { 1402 | "version": "1.0.0", 1403 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1404 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1405 | }, 1406 | "utils-merge": { 1407 | "version": "1.0.1", 1408 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1409 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 1410 | }, 1411 | "validate-npm-package-license": { 1412 | "version": "3.0.4", 1413 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 1414 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 1415 | "requires": { 1416 | "spdx-correct": "^3.0.0", 1417 | "spdx-expression-parse": "^3.0.0" 1418 | } 1419 | }, 1420 | "vary": { 1421 | "version": "1.1.2", 1422 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1423 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1424 | }, 1425 | "which": { 1426 | "version": "1.3.1", 1427 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1428 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1429 | "optional": true, 1430 | "requires": { 1431 | "isexe": "^2.0.0" 1432 | } 1433 | }, 1434 | "word-wrap": { 1435 | "version": "1.2.3", 1436 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 1437 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 1438 | "optional": true 1439 | }, 1440 | "wordwrap": { 1441 | "version": "1.0.0", 1442 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1443 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1444 | "optional": true 1445 | }, 1446 | "wrappy": { 1447 | "version": "1.0.2", 1448 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1449 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1450 | }, 1451 | "ws": { 1452 | "version": "7.3.1", 1453 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", 1454 | "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" 1455 | }, 1456 | "wss": { 1457 | "version": "3.3.4", 1458 | "resolved": "https://registry.npmjs.org/wss/-/wss-3.3.4.tgz", 1459 | "integrity": "sha512-WgVZercD6pVUwEUjFSUpTE7UoOGYAQUwye5VoSuYyPH58xZKfvCEYPTbdGdqdILMnmhSCPoRJXhgsSKY3CmbtA==", 1460 | "requires": { 1461 | "istanbul": "^0.4.5", 1462 | "ws": "^2.3.1" 1463 | }, 1464 | "dependencies": { 1465 | "safe-buffer": { 1466 | "version": "5.0.1", 1467 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", 1468 | "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" 1469 | }, 1470 | "ws": { 1471 | "version": "2.3.1", 1472 | "resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz", 1473 | "integrity": "sha1-a5Sz5EfLajY/eF6vlK9jWejoHIA=", 1474 | "requires": { 1475 | "safe-buffer": "~5.0.1", 1476 | "ultron": "~1.1.0" 1477 | } 1478 | } 1479 | } 1480 | }, 1481 | "xtend": { 1482 | "version": "4.0.2", 1483 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1484 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 1485 | }, 1486 | "yn": { 1487 | "version": "3.1.1", 1488 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1489 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" 1490 | } 1491 | } 1492 | } 1493 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ib-trading-bot", 3 | "version": "1.0.0", 4 | "description": "Interactive Brokers Trading Bot", 5 | "main": "index.ts", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "dev": "ts-node-dev --respawn --transpile-only app/app.ts", 9 | "tsc": "tsc" 10 | }, 11 | "author": "Otto Coster", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@stoqey/ib": "^0.1.0", 15 | "@types/express": "^4.17.8", 16 | "@types/ws": "^7.2.6", 17 | "express": "^4.17.1", 18 | "ts-node-dev": "^1.0.0-pre.62", 19 | "typescript": "^4.0.2", 20 | "ws": "^7.3.1", 21 | "wss": "^3.3.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | // "types": [], /* Type declaration files to be included in compilation. */ 50 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 51 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 52 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 53 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 54 | 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | 61 | /* Experimental Options */ 62 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 63 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 64 | 65 | /* Advanced Options */ 66 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 67 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 68 | } 69 | } 70 | --------------------------------------------------------------------------------