Libraryless. Click here for Pure Java version (31271L/199K).
1 | // Design notes. |
2 | // |
3 | // NG stands for "Non-Garbage" |
4 | // |
5 | // !Design notes end |
6 | |
7 | sclass NGSStrategy extends G22CandleBasedStrategyWithTrailingStop { |
8 | settable double minDistance = 0.4; |
9 | settable double maxDistance = 50; |
10 | settable int period1 = 100; // the "slow" MA |
11 | settable int period2 = 5; // the fast MA (for opening) |
12 | settable double maMinMove = 0.07; // MA trend threshold |
13 | settable double maMinMove2 = 0.05; // MA trend threshold 2 (hysterisis) |
14 | settable bool doLongs = true; |
15 | settable bool doShorts = true; |
16 | settable double unblockDistance = 0.8; |
17 | |
18 | // per-run fields |
19 | |
20 | S fieldsToReset() { |
21 | ret lineCombine(super.fieldsToReset(), [[ |
22 | ma1 ma2 lastMA1 longCondition shortCondition blockShort blockLong maMove movingAverage1_cache movingAverage2_cache |
23 | maDirection maDirectionHistory |
24 | maMoveHistory blockLongHistory blockShortHistory |
25 | longConditionHistory shortConditionHistory |
26 | ]]); |
27 | } |
28 | |
29 | settable double ma1; |
30 | settable double ma2; |
31 | settable double lastMA1 = Double.NaN; |
32 | settable bool longCondition; |
33 | settable bool shortCondition; |
34 | settable bool blockLong; |
35 | settable bool blockShort; |
36 | settable double maMove; |
37 | settable int maDirection; |
38 | |
39 | gettable TickerSequence maMoveHistory = new TickerSequence("maMove"); |
40 | gettable TickerSequence blockLongHistory = new TickerSequence("blockLong"); |
41 | gettable TickerSequence blockShortHistory = new TickerSequence("blockShort"); |
42 | gettable TickerSequence longConditionHistory = new TickerSequence("longCondition"); |
43 | gettable TickerSequence shortConditionHistory = new TickerSequence("shortCondition"); |
44 | gettable TickerSequence maDirectionHistory = new TickerSequence("maDirection"); |
45 | |
46 | void ngsStep aka ngsLogic() { |
47 | double close = currentPrice(); |
48 | double drift = drift(); |
49 | |
50 | longCondition(doLongs && close > upperBand() && close < upperMaxDistanceBand() && maRising()); |
51 | shortCondition(doShorts & close < lowerBand() && close > lowerMaxDistanceBand() && maFalling()); |
52 | |
53 | longConditionHistory?.addIfPriceChanged(boolToInt(longCondition), currentTime()); |
54 | shortConditionHistory?.addIfPriceChanged(boolToInt(shortCondition), currentTime()); |
55 | |
56 | if (ma2 > ma1 || close > lowerReturnBand()) |
57 | unblockShort(); |
58 | |
59 | if (ma2 < ma1 || close < upperReturnBand()) |
60 | unblockLong(); |
61 | |
62 | if (!inCooldown() && drift == 0) { |
63 | if (longCondition && !blockLong) { |
64 | openLong(); |
65 | blockLong(true); |
66 | } |
67 | |
68 | if (shortCondition && !blockShort) { |
69 | openShort(); |
70 | blockShort(true); |
71 | } |
72 | } |
73 | |
74 | if (drift > 0 && close < lowerBand()) |
75 | closeAllPositions("Below band"); |
76 | |
77 | if (drift < 0 && close > upperBand()) |
78 | closeAllPositions("Above band"); |
79 | } |
80 | |
81 | simplyCached MAIndicator movingAverage1() { |
82 | ret new MAIndicator(period1); |
83 | } |
84 | |
85 | simplyCached MAIndicator movingAverage2() { |
86 | ret new MAIndicator(period2); |
87 | } |
88 | |
89 | L<CandleBasedIndicator> indicators() { |
90 | ret ll(movingAverage1(), movingAverage2()); |
91 | } |
92 | |
93 | void unblockLong { |
94 | if (blockLong) { |
95 | log("Long unblock"); |
96 | blockLong(false); |
97 | } |
98 | } |
99 | |
100 | void unblockShort { |
101 | if (blockShort) { |
102 | log("Short unblock"); |
103 | blockShort(false); |
104 | } |
105 | } |
106 | |
107 | bool maRising() { ret maDirection > 0; } |
108 | bool maFalling() { ret maDirection < 0; } |
109 | double moveSignal() { ret maMove/maMinMove*100; } |
110 | |
111 | double upperBand(dbl ma1 default ma1) { ret ma1*(1+minDistance/100); } |
112 | double lowerBand(dbl ma1 default ma1) { ret ma1*(1-minDistance/100); } |
113 | double upperMaxDistanceBand() { ret ma1*(1+maxDistance/100); } |
114 | double lowerMaxDistanceBand() { ret ma1*(1-maxDistance/100); } |
115 | double upperReturnBand() { ret ma1*(1+unblockDistance/100); } |
116 | double lowerReturnBand() { ret ma1*(1-unblockDistance/100); } |
117 | |
118 | { |
119 | granularity(30); |
120 | |
121 | onNewPrice(price -> ngsStep()); |
122 | onCandleCompleted(candle -> { |
123 | lastMA1(ma1); |
124 | ma1(movingAverage1()!); |
125 | ma2(movingAverage2()!); |
126 | maMove((ma1/lastMA1-1)*100); |
127 | maMoveHistory?.addIfPriceChanged(maMove, currentTime()); |
128 | if (maMove >= maMinMove) |
129 | maDirection(1); |
130 | else if (maMove <= -maMinMove) |
131 | maDirection(-1); |
132 | else if (maDirection < 0 && maMove >= -maMinMove2 |
133 | || maDirection > 0 && maMove <= maMinMove2) |
134 | maDirection(0); |
135 | maDirectionHistory?.addIfPriceChanged(maDirection, currentTime()); |
136 | ngsStep(); |
137 | }); |
138 | } |
139 | |
140 | LS status() { |
141 | ret listCombine( |
142 | "Min distance, MA min move: " + minDistance + " " + maMinMove + " (current move: " + formatDouble(maMove, 4) + ")", |
143 | "MA periods: " + period1 + " " + period2, |
144 | "Do: " + commaCombine(stringIf(doLongs, "Longs"), stringIf(doShorts, "Shorts")), |
145 | "Moving averages: " + formatDouble_significant(ma1, 4) + ", " + formatDouble_significant(ma2, 4), |
146 | valueOrNull(blockLong, "Long blocked"), |
147 | valueOrNull(longCondition, "Long condition"), |
148 | valueOrNull(blockShort, "Short blocked"), |
149 | valueOrNull(shortCondition, "Short condition"), |
150 | super.status() |
151 | ); |
152 | } |
153 | |
154 | void afterStep :: before { |
155 | blockLongHistory?.addIfPriceChanged(boolToInt(blockLong), currentTime()); |
156 | blockShortHistory?.addIfPriceChanged(boolToInt(blockShort), currentTime()); |
157 | |
158 | } |
159 | } |
Began life as a copy of #1036558
download show line numbers debug dex old transpilations
Travelled to 2 computer(s): mqqgnosmbjvj, wnsclhtenguj
No comments. add comment
Snippet ID: | #1036571 |
Snippet name: | NGSStrategy backup |
Eternal ID of this version: | #1036571/1 |
Text MD5: | 308e6a1d70e461e4eac6b5d628fd428b |
Transpilation MD5: | 7529bdffd8940eddc4bca741be49fc87 |
Author: | stefan |
Category: | javax / trading |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2023-03-14 12:08:53 |
Source code size: | 5356 bytes / 159 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 123 / 169 |
Referenced in: | [show references] |