Libraryless. Click here for Pure Java version (30155L/190K).
1 | concept CleanMoveStrategy extends G22TradingStrategy {
|
2 | // How clean the move must be |
3 | settable double minCleanness = 2; |
4 | |
5 | // How profitable the move must be |
6 | settable double minProfit = 0.5; |
7 | |
8 | // Factor for turning pullback into callback |
9 | settable double callbackFactor = 1.5; |
10 | |
11 | // Max pullback of move |
12 | settable double maxPullback = 1; |
13 | |
14 | // Price has to move at least this many percent for us to |
15 | // recalculate the moves |
16 | //settable double minChangeToReactTo = 0.1; |
17 | |
18 | // How often to start a new move analysis (seconds) |
19 | settable double calcMovesEvery = 30; |
20 | |
21 | S fieldsToReset() {
|
22 | ret lines(ll(super.fieldsToReset(), [[currentMoves lastPriceReactedTo movesCalced]])); |
23 | } |
24 | |
25 | // current short & long move |
26 | settable L<LivePullbackToProfitAnalysis> currentMoves; |
27 | |
28 | //settable double lastPriceReactedTo; |
29 | settable double movesCalced; |
30 | |
31 | persistable class Position extends G22TradingStrategy.Position {
|
32 | settable CallbackJuicer juicer; |
33 | } |
34 | |
35 | srecord ProfitBeforeLeverageJuiceable(Position p) is Juiceable {
|
36 | public double juiceValue() { ret p.profitBeforeLeverage(); }
|
37 | } |
38 | |
39 | void price(double price) {
|
40 | if (currentPrice == price) ret; |
41 | currentPrice = price; |
42 | afterwards { afterStep(); change(); }
|
43 | |
44 | // Close positions |
45 | |
46 | for (p : openPositions()) {
|
47 | if (p.juicer != null) {
|
48 | var signals = p.juicer.calculateCloseSignals(); |
49 | var strongest = highestBy(signals, s -> s.strength()); |
50 | if (strongest != null && strongest.isTrigger()) |
51 | p.close(strongest); |
52 | } |
53 | } |
54 | |
55 | // Check if we should start a position |
56 | if (empty(openPositions()) && shouldCalcMoves()) {
|
57 | // Calculate 2 current moves backwards in time |
58 | var time = currentTime(); |
59 | currentMoves = map(falseTrue(), isShort -> {
|
60 | new LivePullbackToProfitAnalysis a; |
61 | a.pullbackLimit(maxPullback); |
62 | a.isShort(isShort); |
63 | int idx = actualTicker.indexOfTimestamp(currentTime()); |
64 | while (idx >= 0 && !a.done()) |
65 | a.feed(actualTicker.getPricePoint(idx--)); |
66 | ret a; |
67 | }); |
68 | |
69 | bool shouldShort = false, shouldLong = false; |
70 | PullbackToProfit openReason = null; |
71 | |
72 | for (move : currentMoves) |
73 | for (ptp : move.ptpList()) |
74 | if (ptp.cleanness() >= minCleanness && ptp.profit() >= minProfit) {
|
75 | openReason = ptp; |
76 | if (openReason.isShort) |
77 | shouldLong = true; |
78 | else |
79 | shouldShort = true; |
80 | } |
81 | |
82 | if (shouldShort && shouldLong) |
83 | print("Conflicting signal (long+short at once)");
|
84 | else if (shouldShort || shouldLong) {
|
85 | int direction = shouldShort ? -1 : 1; |
86 | new Position p; |
87 | p.marginToUse = marginPerPosition; |
88 | var callbackRate = openReason.pullback*callbackFactor; |
89 | p.juicer = new CallbackJuicer(callbackRate); |
90 | p.juicer.juiceable(new ProfitBeforeLeverageJuiceable(p)); |
91 | openPosition(p, direction, openReason); |
92 | } |
93 | } |
94 | } |
95 | |
96 | bool shouldCalcMoves() {
|
97 | /*if (!differentByEpsilonRatio(lastPriceReactedTo, currentPrice, minChangeToReactTo/100)) |
98 | false; |
99 | lastPriceReactedTo(currentPrice); |
100 | true;*/ |
101 | |
102 | var time = currentTime(); |
103 | if (time >= movesCalced+fromSeconds(calcMovesEvery)) {
|
104 | movesCalced = time; |
105 | true; |
106 | } |
107 | false; |
108 | } |
109 | |
110 | L<? extends Position> openPositions() { ret (L) super.openPositions(); }
|
111 | |
112 | LS status() {
|
113 | ret listCombine( |
114 | map(currentMoves, move -> "Move: " + move), |
115 | super.status() |
116 | ); |
117 | } |
118 | } |
Began life as a copy of #1036259
download show line numbers debug dex old transpilations
Travelled to 2 computer(s): mqqgnosmbjvj, wnsclhtenguj
No comments. add comment
| Snippet ID: | #1036518 |
| Snippet name: | CleanMoveStrategy [OK, for one coin at a time] |
| Eternal ID of this version: | #1036518/24 |
| Text MD5: | 94555821f69917dc9700d40612fc0f9f |
| Transpilation MD5: | adc080c1457fd60eee2d546e040f7598 |
| Author: | stefan |
| Category: | javax / trading |
| Type: | JavaX fragment (include) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2023-01-22 17:06:35 |
| Source code size: | 3681 bytes / 118 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 816 / 1052 |
| Version history: | 23 change(s) |
| Referenced in: | [show references] |