1 | set flag Reparse. |
2 | |
3 | sclass Corridor { |
4 | settable double ladderStep = 1; |
5 | settable int capacity = 6; |
6 | settable bool openTwoPositionsAtStart = true; |
7 | |
8 | record noeq Position(double openingPrice, double direction) { |
9 | double closingPrice = Double.NaN; |
10 | |
11 | int digitizedOpeningPrice() { ret digitizePrice(openingPrice); } |
12 | |
13 | bool isLong() { ret direction > 0; } |
14 | bool isShort() { ret direction < 0; } |
15 | |
16 | bool closed() { ret !isNaN(closingPrice); } |
17 | S type() { ret trading_directionToPositionType(direction); } |
18 | |
19 | double profitAtPrice(double price) { |
20 | ret (price-openingPrice)*direction; |
21 | } |
22 | |
23 | double profit() { |
24 | ret profitAtPrice(closed() ? closingPrice : currentPrice()); |
25 | } |
26 | |
27 | void close { |
28 | if (closed()) fail("Can't close again"); |
29 | openPositions.remove(this); |
30 | closingPrice = currentPrice(); |
31 | closedPositions.add(this); |
32 | realizedProfit += profit(); |
33 | print(this); |
34 | printPositions(); |
35 | } |
36 | |
37 | toString { |
38 | ret renderFunctionCall( |
39 | spaceCombine( |
40 | closed() ? "Closed" : null, |
41 | type() |
42 | ), |
43 | openingPrice + " [" + digitizedOpeningPrice() + "]", |
44 | "profit=" + profit()); |
45 | } |
46 | } |
47 | |
48 | gettable double currentPrice = 0; |
49 | |
50 | gettable double oldPrice = Double.NaN; |
51 | gettable double startingPrice = Double.NaN; |
52 | gettable double digitizationBase; |
53 | gettable int lastDirection; |
54 | gettable double realizedProfit; |
55 | gettable int stepCount; |
56 | gettable new LinkedHashSet<Position> openPositions; |
57 | gettable new L<Position> closedPositions; |
58 | gettable new DoubleBuffer priceHistory; |
59 | |
60 | Position openPosition(double direction) { |
61 | var p = new Position(currentPrice(), direction); |
62 | openPositions.add(p); |
63 | print("Opening " + p); |
64 | printPositions(); |
65 | ret p; |
66 | } |
67 | |
68 | bool hasPosition(double price, double direction) { |
69 | ret findPosition(price, direction) != null; |
70 | } |
71 | |
72 | Position closePosition(double price, double direction) { |
73 | var p = findPosition(price, direction); |
74 | p?.close(); |
75 | ret p; |
76 | } |
77 | |
78 | Position findPosition(double price, double direction) { |
79 | ret firstThat(openPositions(), p -> |
80 | p.digitizedOpeningPrice() == digitizedPrice(price) && p.direction == direction); |
81 | } |
82 | |
83 | Position openShort() { ret openPosition(-1); } |
84 | Position openLong() { ret openPosition(1); } |
85 | |
86 | void printPositions { |
87 | print(colonCombine(n2(openPositions, "open position"), |
88 | joinWithComma(openPositions))); |
89 | } |
90 | |
91 | bool started() { ret !isNaN(startingPrice); } |
92 | |
93 | void start { |
94 | if (started()) fail("Already started"); |
95 | startingPrice = currentPrice(); |
96 | digitizationBase = frac(startingPrice/ladderStep); |
97 | print("Starting CORRIDOR at " + startingPrice + " +/- " + ladderStep); |
98 | if (openTwoPositionsAtStart) { |
99 | openPosition(1); |
100 | openPosition(-1); |
101 | } |
102 | } |
103 | |
104 | int digitizePrice aka digitizedPrice(double price) { |
105 | ret iround((price-digitizationBase)/ladderStep); |
106 | } |
107 | |
108 | int oldPriceDigitized() { |
109 | ret digitizePrice(oldPrice); |
110 | } |
111 | |
112 | int currentPriceDigitized() { |
113 | ret digitizePrice(currentPrice()); |
114 | } |
115 | |
116 | void prices(double... prices) { |
117 | fOr (price : prices) |
118 | price(price); |
119 | } |
120 | |
121 | void currentPrice aka price(double price) { |
122 | oldPrice = currentPrice; |
123 | |
124 | if (oldPrice == price) ret; |
125 | |
126 | currentPrice = price; |
127 | int direction = sign(price-oldPrice); |
128 | lastDirection = direction; |
129 | if (oldPriceDigitized() == currentPriceDigitized()) ret; |
130 | |
131 | bool first = empty(priceHistory); |
132 | priceHistory.add(price); |
133 | ++stepCount; |
134 | if (first) |
135 | printWithPrecedingNL("Starting price: " + price); |
136 | else |
137 | printWithPrecedingNL(commaCombine( |
138 | "Step " + stepCount + ". Old price: " + oldPrice, |
139 | "New price: " + price)); |
140 | |
141 | if (started()) |
142 | step(); |
143 | |
144 | print(this); |
145 | } |
146 | |
147 | swappable void step { |
148 | // Close forward position "behind us" |
149 | closePosition(currentPrice()-ladderStep*lastDirection(), lastDirection()); |
150 | |
151 | int p1 = oldPriceDigitized(); |
152 | int p2 = currentPriceDigitized(); |
153 | |
154 | // Open backward position here (if not there yet) |
155 | int direction = lastDirection(); |
156 | if (!hasPosition(currentPrice(), -direction)) |
157 | openPosition(-direction); |
158 | } |
159 | |
160 | double unrealizedProfit() { |
161 | ret doubleSum(map(openPositions, ->.profit())); |
162 | } |
163 | |
164 | L<Position> shortPositionsAtOrBelowPrice(double openingPrice) { |
165 | ret filter(openPositions, p -> p.isShort() && p.openingPrice <= openingPrice); |
166 | } |
167 | |
168 | L<Position> longPositionsAtOrAbovePrice(double openingPrice) { |
169 | ret filter(openPositions, p -> p.isLong() && p.openingPrice >= openingPrice); |
170 | } |
171 | |
172 | L<Position> negativePositions() { |
173 | ret filter(openPositions, p -> p.profit() < 0); |
174 | } |
175 | |
176 | double debt() { |
177 | ret doubleSum(map(negativePositions(), ->.profit())); |
178 | } |
179 | |
180 | double profit() { |
181 | ret realizedProfit+unrealizedProfit(); |
182 | } |
183 | |
184 | LS status() { |
185 | ret ll( |
186 | "Step " + n2(stepCount), |
187 | "Profit: " + profit(), |
188 | "Realized profit: " + realizedProfit + " from " + n2(closedPositions, "closed position"), |
189 | "Unrealized profit: " + unrealizedProfit() + " in " + n2(openPositions, "open position"), |
190 | "Debt: " + debt(), |
191 | ); |
192 | } |
193 | |
194 | toString { ret commaCombine(status()); } |
195 | } |
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: | #1036207 |
Snippet name: | Corridor [backup 2] |
Eternal ID of this version: | #1036207/1 |
Text MD5: | cff91d47fcef415ee640456ba21292f2 |
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-19 17:51:41 |
Source code size: | 5452 bytes / 195 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 125 / 140 |
Referenced in: | [show references] |