Skip to content

Commit d83af39

Browse files
authored
Merge pull request #23 from Artimatic/feature/29-Backtesting-and-ml
Feature/29 backtesting and ml
2 parents 49c8c3f + 17d9b14 commit d83af39

File tree

12 files changed

+181
-124
lines changed

12 files changed

+181
-124
lines changed

package-lock.json

Lines changed: 22 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"algebra.js": "^0.2.6",
3737
"algotrader": "^1.3.1",
3838
"angular-highcharts": "^9.0.11",
39+
"axios": "^0.21.1",
3940
"body-parser": "^1.18.2",
4041
"boom": "^6.0.0",
4142
"chart.js": "^2.9.4",

server/api/backtest/backtest.service.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,20 +515,22 @@ class BacktestService {
515515
const idx = Number(key);
516516

517517
if (idx > minQuotes) {
518-
const q = quotes.slice(idx - minQuotes, idx);
518+
const q = quotes.slice(idx - minQuotes, idx + 1);
519519
getIndicatorQuotes.push(this.initStrategy(q));
520520
}
521521
});
522522

523523
return Promise.all(getIndicatorQuotes);
524524
})
525-
.then(indicators => {
525+
.then((indicators: Indicators[]) => {
526526
let testResults;
527+
527528
testResults = this.backtestIndicators(this.getAllRecommendations,
528529
indicators,
529530
parameters);
530531

531532
testResults.algo = 'All indicators';
533+
532534
return testResults;
533535
});
534536
}
Lines changed: 89 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,116 @@
11

22
import * as _ from 'lodash';
3+
import axios from 'axios';
4+
35
import PortfolioService from '../portfolio/portfolio.service';
46
import portfolioController from '../portfolio/portfolio.controller';
57

8+
import * as configurations from '../../config/environment';
9+
10+
const dataServiceUrl = configurations.apps.goliath;
11+
612
export interface MonthlyStrategyList {
7-
month: string;
8-
year: number;
9-
day: number;
10-
daysToExp: number;
11-
secondaryMonth: string;
12-
secondaryYear: number;
13-
secondaryDay: number;
14-
secondaryDaysToExp: number;
15-
type: string;
16-
secondaryType: string;
17-
leap: boolean;
18-
optionStrategyList: Strategy[];
13+
month: string;
14+
year: number;
15+
day: number;
16+
daysToExp: number;
17+
secondaryMonth: string;
18+
secondaryYear: number;
19+
secondaryDay: number;
20+
secondaryDaysToExp: number;
21+
type: string;
22+
secondaryType: string;
23+
leap: boolean;
24+
optionStrategyList: Strategy[];
1925
}
2026

2127
export interface Strategy {
22-
primaryLeg: Option;
23-
secondaryLeg: Option;
24-
strategyStrike: number;
25-
strategyBid: number;
26-
strategyAsk: number;
28+
primaryLeg: Option;
29+
secondaryLeg: Option;
30+
strategyStrike: number;
31+
strategyBid: number;
32+
strategyAsk: number;
2733
}
2834

2935
export interface Option {
36+
symbol: string;
37+
putCallInd: string;
38+
description: string;
39+
bid: number;
40+
ask: number;
41+
range: string;
42+
strikePrice: number;
43+
totalVolume: number;
44+
}
45+
46+
export interface OptionsChain {
47+
symbol: string;
48+
underlying: {
3049
symbol: string;
31-
putCallInd: string;
3250
description: string;
51+
change: number;
52+
percentChange: number;
53+
close: number;
3354
bid: number;
3455
ask: number;
35-
range: string;
36-
strikePrice: number;
56+
last: number;
57+
mark: number;
58+
markChange: number;
59+
markPercentChange: number;
60+
bidSize: number;
61+
askSize: number;
62+
highPrice: number;
63+
lowPrice: number;
64+
openPrice: number;
3765
totalVolume: number;
38-
}
39-
40-
export interface OptionsChain {
41-
symbol: string;
42-
underlying: {
43-
symbol: string;
44-
description: string;
45-
change: number;
46-
percentChange: number;
47-
close: number;
48-
bid: number;
49-
ask: number;
50-
last: number;
51-
mark: number;
52-
markChange: number;
53-
markPercentChange: number;
54-
bidSize: number;
55-
askSize: number;
56-
highPrice: number;
57-
lowPrice: number;
58-
openPrice: number;
59-
totalVolume: number;
60-
fiftyTwoWeekHigh: number;
61-
fiftyTwoWeekLow: number;
62-
};
63-
monthlyStrategyList: MonthlyStrategyList[];
66+
fiftyTwoWeekHigh: number;
67+
fiftyTwoWeekLow: number;
68+
};
69+
monthlyStrategyList: MonthlyStrategyList[];
6470
}
6571

6672
export interface ImpliedMove {
67-
move: number;
68-
upperPrice: number;
69-
lowerPrice: number;
70-
strategy: Strategy;
73+
move: number;
74+
upperPrice: number;
75+
lowerPrice: number;
76+
strategy: Strategy;
7177
}
7278

7379
class OptionService {
74-
calculateImpliedMove(accountId, symbol, strikeCount, optionType, minExpiration = 29) {
75-
return PortfolioService.getOptionsStraddle(accountId, symbol, strikeCount, optionType)
76-
.then((straddleOptionsChain: OptionsChain) => {
77-
const strategyList = straddleOptionsChain.monthlyStrategyList.find(element => element.daysToExp >= minExpiration);
78-
const goal = straddleOptionsChain.underlying.last;
79-
80-
const closestStrikeStraddle = strategyList.optionStrategyList.reduce((prev, curr) => {
81-
return (Math.abs(curr.strategyStrike - goal) < Math.abs(prev.strategyStrike - goal) ? curr : prev);
82-
});
83-
84-
const strategyCost = portfolioController.midPrice(closestStrikeStraddle.strategyAsk, closestStrikeStraddle.strategyBid);
85-
const move = _.round(strategyCost / goal, 3);
86-
const movePrice = _.round(move * goal, 2);
87-
88-
return {
89-
move,
90-
upperPrice: _.round(goal + movePrice, 2),
91-
lowerPrice: _.round(goal - movePrice, 2),
92-
strategyCost,
93-
strategy: closestStrikeStraddle
94-
};
95-
});
80+
calculateImpliedMove(accountId, symbol, strikeCount, optionType, minExpiration = 29) {
81+
return PortfolioService.getOptionsStraddle(accountId, symbol, strikeCount, optionType)
82+
.then((straddleOptionsChain: OptionsChain) => {
83+
const strategyList = straddleOptionsChain.monthlyStrategyList.find(element => element.daysToExp >= minExpiration);
84+
const goal = straddleOptionsChain.underlying.last;
85+
86+
const closestStrikeStraddle = strategyList.optionStrategyList.reduce((prev, curr) => {
87+
return (Math.abs(curr.strategyStrike - goal) < Math.abs(prev.strategyStrike - goal) ? curr : prev);
88+
});
89+
90+
const strategyCost = portfolioController.midPrice(closestStrikeStraddle.strategyAsk, closestStrikeStraddle.strategyBid);
91+
const move = _.round(strategyCost / goal, 3);
92+
const movePrice = _.round(move * goal, 2);
93+
94+
this.saveImpliedMove(symbol, move);
95+
return {
96+
move,
97+
upperPrice: _.round(goal + movePrice, 2),
98+
lowerPrice: _.round(goal - movePrice, 2),
99+
strategyCost,
100+
strategy: closestStrikeStraddle
101+
};
102+
});
103+
}
104+
105+
private saveImpliedMove(symbol: string, move: number) {
106+
107+
if (move) {
108+
axios.post(`${dataServiceUrl}backtest/update-implied-move`, {
109+
symbol,
110+
impliedMove: move
111+
});
96112
}
113+
}
97114
}
98115

99116
export default new OptionService();

src/app/chart-dialog/chart-dialog.component.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,19 @@ export interface AlgorithmSelection {
2121
export class ChartDialogComponent implements OnInit {
2222
smaForm: FormGroup;
2323
algorithms: AlgorithmSelection[] = [
24+
{ value: 'all', viewValue: 'All Algorithms' },
2425
{ value: 'mfi', viewValue: 'Money Flow Index' },
26+
{ value: 'demark9', viewValue: 'demark9' },
2527
{ value: 'mfiLow', viewValue: 'Money Flow Index Low' },
28+
{ value: 'mfiDivergence', viewValue: 'MFI Divergence' },
29+
{ value: 'mfiTrade', viewValue: 'MFI Trade' },
30+
{ value: 'macd', viewValue: 'MACD' },
2631
{ value: 'sma', viewValue: 'Moving Average' },
2732
{ value: 'bollingerband', viewValue: 'Bollinger Band' },
2833
{ value: 'bollingerbandmfi', viewValue: 'Bollinger Band and MFI' },
2934
{ value: 'macrossover', viewValue: 'Moving Average Crossover' },
30-
{ value: 'daily-roc', viewValue: 'Rate of Change/MFI Divergence' },
31-
{ value: 'findresistance', viewValue: 'Moving Average Resistance' },
32-
{ value: 'all', viewValue: 'All Algorithms' }
35+
{ value: 'daily-roc', viewValue: 'Rate of Change' },
36+
{ value: 'findresistance', viewValue: 'Moving Average Resistance' }
3337
];
3438

3539
selectedAlgo = 'bollingerbandmfi';

src/app/find-buy/find-buy.component.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@
2727
</tr>
2828
</ng-template>
2929
</p-table>
30+
31+
<app-pokerhand></app-pokerhand>

src/app/rh-table/backtest-stocks.constant.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,31 @@ function createParam(ticker: string): AlgoParam {
1313
}
1414

1515
export const stockList = [
16+
'FXI',
17+
'QQQJ',
18+
'ARKQ',
19+
'ARKK',
20+
'ARKW',
21+
'ARKF',
22+
'CCIV',
23+
'CGC',
24+
'ACB',
25+
'YOLO',
26+
'FCEL',
27+
'TPIC',
28+
'ALB',
29+
'RUN',
30+
'SPWR',
31+
'DQ',
32+
'CNRG',
33+
'LIT',
34+
'PBW',
35+
'TAN',
36+
'ICLN',
37+
'PLUG',
38+
'NGA',
39+
'SKLZ',
40+
'BNGO',
1641
'AA',
1742
'ARKG',
1843
'GOEV',

src/app/rh-table/rh-table.component.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ <h3 class="table-title">Stocks</h3>
7878
<span *ngSwitchCase="'impliedMovement'">
7979
{{element?.impliedMovement | percent}}
8080
</span>
81+
<span *ngSwitchCase="'previousImpliedMovement'">
82+
{{element?.previousImpliedMovement | percent}}
83+
</span>
8184
<span *ngSwitchDefault>
8285
{{element[col.field]}}
8386
</span>

0 commit comments

Comments
 (0)