Libraryless. Click here for Pure Java version (10557L/53K).
1 | set flag Reparse. |
2 | |
3 | sclass Corridor { |
4 | record noeq Position(/*settable*/ double openingPrice, /*settable*/ double direction) { |
5 | /*settable*/ double closingPrice = Double.NaN; |
6 | |
7 | bool closed() { ret !isNaN(closingPrice); } |
8 | S type() { ret trading_directionToPositionType(direction); } |
9 | |
10 | double profitAtPrice(double price) { |
11 | ret (price-openingPrice)*direction; |
12 | } |
13 | |
14 | double profit() { |
15 | ret profitAtPrice(closed() ? closingPrice : currentPrice()); |
16 | } |
17 | |
18 | void close { |
19 | if (closed()) fail("Can't close again"); |
20 | openPositions.remove(this); |
21 | closingPrice = currentPrice(); |
22 | closedPositions.add(this); |
23 | realizedProfit += profit(); |
24 | } |
25 | |
26 | toString { |
27 | ret renderFunctionCall( |
28 | spaceCombine( |
29 | closed() ? "Closed" : null, |
30 | type() |
31 | ), |
32 | openingPrice, |
33 | "profit=" + profit()); |
34 | } |
35 | } |
36 | |
37 | record noeq Threshold(/*settable*/ double price, /*settable*/ double direction, Runnable action) { |
38 | void trigger { |
39 | print("Triggered at " + price + " " + direction + ": " + action); |
40 | callF(action); |
41 | } |
42 | } |
43 | |
44 | settable double epsilon = 0.001; |
45 | settable double ladderStep = 1; |
46 | gettable double currentPrice = 0; |
47 | |
48 | gettable double lastDirection; |
49 | gettable double realizedProfit; |
50 | new L<Loop> loops; |
51 | new TreeMultiMap<Double, Threshold> thresholds; |
52 | new LinkedHashSet<Position> openPositions; |
53 | new L<Position> closedPositions; |
54 | |
55 | record noeq Loop(/*settable*/ double startingPrice, /*settable*/ double direction) { |
56 | Position position; |
57 | Loop successor; |
58 | |
59 | class Open is Runnable { |
60 | run { |
61 | if (position != null && !position.closed()) |
62 | fail("Trying to re-open position: " + this); |
63 | |
64 | print("Opening position at " + currentPrice() + " by loop " + this); |
65 | position = openPosition(direction); |
66 | if (successor == null) |
67 | successor = new Loop(startingPrice+ladderStep, direction).init(); |
68 | } |
69 | |
70 | toString { ret spaceCombine("Open", startingPrice, direction); } |
71 | } |
72 | |
73 | class Close is Runnable { |
74 | run { |
75 | if (position != null) { |
76 | print("Closing position at " + currentPrice() + " by loop " + this); |
77 | position.close(); |
78 | } |
79 | } |
80 | |
81 | toString { ret spaceCombine("Close", startingPrice, direction); } |
82 | } |
83 | |
84 | selfType init() { |
85 | loops.add(this); |
86 | addThreshold(startingPrice, -direction, new Open); |
87 | addThreshold(startingPrice+ladderStep, direction, new Close); |
88 | |
89 | this; |
90 | } |
91 | |
92 | toString { |
93 | ret formatRecordVars("Loop", |
94 | +startingPrice, |
95 | +direction, |
96 | +position, |
97 | succ := successor == null ?: "t" |
98 | ); |
99 | } |
100 | } |
101 | |
102 | Position openPosition(double direction) { |
103 | ret addAndReturn(openPositions, new Position(currentPrice(), direction)); |
104 | } |
105 | |
106 | Threshold addThreshold(double price, double direction, Runnable action) { |
107 | var t = new Threshold(price, direction, action); |
108 | thresholds.put(t.price, t); |
109 | bool triggered = (lastDirection == 0 || lastDirection == direction) && absDiff(currentPrice, price) < epsilon; |
110 | printVars addThreshold(+currentPrice, +price, +direction, +lastDirection, +triggered); |
111 | if (triggered) |
112 | t.trigger(); |
113 | ret t; |
114 | } |
115 | |
116 | void start { |
117 | double price = currentPrice(); |
118 | print("Starting CORRIDOR at " + price + " +/- " + ladderStep); |
119 | lastDirection = 0; |
120 | new Loop(price, 1).init(); |
121 | new Loop(price, -1).init(); |
122 | } |
123 | |
124 | selfType currentPrice aka price(double price) { |
125 | double oldPrice = currentPrice; |
126 | if (oldPrice == price) this; |
127 | |
128 | currentPrice = price; |
129 | int direction = sign(price-oldPrice); |
130 | lastDirection = direction; |
131 | NavigableMap<Double, L<Threshold>> map = thresholds.innerMap(); |
132 | map = direction > 0 |
133 | ? map.subMap(oldPrice, false, price, true) |
134 | : map.subMap(price, true, oldPrice, false); |
135 | var keys = keys(map); |
136 | LL<Threshold> thresholdsCrossed = valuesList(map); |
137 | if (direction < 0) |
138 | reverseInPlace(thresholdsCrossed); |
139 | |
140 | new L<Threshold> toExecute; |
141 | for (actions : thresholdsCrossed) |
142 | for (t : actions) |
143 | if (t.direction == direction) |
144 | toExecute.add(t); |
145 | |
146 | printWithPrecedingNL(commaCombine( |
147 | "New price: " + currentPrice, |
148 | "direction: " + direction, |
149 | "Thresholds crossed: " + keys, |
150 | n2(toExecute, "trigger"))); |
151 | |
152 | for (t : toExecute) t.trigger(); |
153 | |
154 | this; |
155 | } |
156 | |
157 | double unrealizedProfit() { |
158 | ret doubleSum(map(openPositions, ->.profit())); |
159 | } |
160 | |
161 | double profit() { |
162 | ret realizedProfit+unrealizedProfit(); |
163 | } |
164 | |
165 | LS status() { |
166 | double up = unrealizedProfit(); |
167 | ret ll( |
168 | "Profit: " + realizedProfit+up, |
169 | "Realized profit: " + realizedProfit + " from " + n2(closedPositions, "closed position"), |
170 | "Unrealized profit: " + up + " in " + n2(openPositions, "open position"), |
171 | //n2(loops, "loop"), |
172 | //n2(keysSize(thresholds), "threshold"), |
173 | //n2(l(thresholds), "threshold action"), |
174 | ); |
175 | } |
176 | |
177 | toString { ret commaCombine(status()); } |
178 | } |
Began life as a copy of #1036196
download show line numbers debug dex old transpilations
Travelled to 2 computer(s): mqqgnosmbjvj, wnsclhtenguj
No comments. add comment
Snippet ID: | #1036199 |
Snippet name: | Corridor [backup] |
Eternal ID of this version: | #1036199/1 |
Text MD5: | df720143d023644cd40c4dc87b1dccde |
Transpilation MD5: | 3ae729a21689ec51e14d9fa44bfcac8d |
Author: | stefan |
Category: | javax / gazelle 22 |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-10-17 01:09:41 |
Source code size: | 5275 bytes / 178 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 160 / 225 |
Referenced in: | [show references] |